[cdo] 01/06: upstream 1.9.2rc1

Alastair McKinstry mckinstry at moszumanska.debian.org
Tue Nov 14 14:26:03 UTC 2017


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

mckinstry pushed a commit to branch debian/master
in repository cdo.

commit 97a3dd36b647b8ddd7bb06d3bde89201064d3754
Author: Alastair McKinstry <mckinstry at debian.org>
Date:   Mon Nov 6 11:44:11 2017 +0000

    upstream 1.9.2rc1
---
 ChangeLog                            |    33 +
 Makefile.am                          |    13 +-
 Makefile.in                          |    93 +-
 NEWS                                 |     8 +
 OPERATORS                            |     5 +
 aclocal.m4                           |   113 +-
 cdo.settings.in                      |   116 +-
 cdo.spec                             |     2 +-
 config/default                       |    12 +-
 configure                            |  4445 +-
 configure.ac                         |    73 +-
 contrib/Makefile.in                  |    35 +-
 contrib/cdoCompletion.bash           |     3 +-
 contrib/cdoCompletion.tcsh           |     3 +-
 contrib/cdoCompletion.zsh            |     3 +-
 doc/cdo.pdf                          |   Bin 2720332 -> 2309417 bytes
 doc/cdo_cmor.pdf                     |   Bin 261892 -> 261888 bytes
 doc/cdo_eca.pdf                      |   Bin 214702 -> 205826 bytes
 doc/cdo_magics.pdf                   |   Bin 829854 -> 829885 bytes
 doc/cdo_refcard.pdf                  |   Bin 97632 -> 99176 bytes
 libcdi/ChangeLog                     |     8 +
 libcdi/Makefile.in                   |    72 +-
 libcdi/aclocal.m4                    |    71 +-
 libcdi/app/Makefile.in               |    25 +-
 libcdi/app/cdi.c                     |    39 +-
 libcdi/configure                     |   393 +-
 libcdi/configure.ac                  |     2 +-
 libcdi/doc/cdi_cman.pdf              |   Bin 335148 -> 338053 bytes
 libcdi/doc/cdi_fman.pdf              |   Bin 363677 -> 366205 bytes
 libcdi/examples/Makefile.in          |    25 +-
 libcdi/examples/cdi_copy.c           |     2 +-
 libcdi/examples/cdi_read.c           |     6 +-
 libcdi/examples/cdi_read_f2003.f90   |     5 +-
 libcdi/examples/cdi_write.c          |     6 +-
 libcdi/examples/cdi_write_const.c    |     2 +-
 libcdi/examples/cdi_write_ens.c      |     2 +-
 libcdi/examples/cdi_write_f2003.f90  |     5 +-
 libcdi/examples/cdi_write_hybrid.c   |    20 +-
 libcdi/examples/pio/Makefile.in      |    25 +-
 libcdi/interfaces/Makefile.in        |    25 +-
 libcdi/interfaces/cdi.cpp            |    18 +-
 libcdi/src/Makefile.in               |    29 +-
 libcdi/src/cdf_lazy_grid.c           |     8 +-
 libcdi/src/cdf_read.c                |    36 +-
 libcdi/src/cdf_write.c               |    18 +-
 libcdi/src/cdi.h                     |    62 +-
 libcdi/src/cdi.inc                   |     4 +
 libcdi/src/cdiFortran.c              |   211 +-
 libcdi/src/cdi_int.h                 |    14 +-
 libcdi/src/cdilib.c                  | 77967 +++++++++++++++++----------------
 libcdi/src/cdipio.h                  |     4 +-
 libcdi/src/cdipioFortran.c           |     4 +-
 libcdi/src/config.h.in               |     5 +
 libcdi/src/grb_read.c                |    32 +-
 libcdi/src/grb_write.c               |    42 +-
 libcdi/src/gribapi_utilities.c       |    47 +-
 libcdi/src/grid.c                    |   322 +-
 libcdi/src/grid.h                    |    24 +-
 libcdi/src/iterator_fallback.c       |     4 +-
 libcdi/src/mo_cdi.f90                |   163 +-
 libcdi/src/pio_client.c              |    10 +-
 libcdi/src/pio_interface.c           |    14 +-
 libcdi/src/pio_interface.h           |     4 +-
 libcdi/src/pio_server.c              |     8 +-
 libcdi/src/stream.c                  |     8 +-
 libcdi/src/stream_cdf.h              |    14 +-
 libcdi/src/stream_cdf_i.c            |    55 +-
 libcdi/src/stream_cdf_o.c            |    77 +-
 libcdi/src/stream_cgribex.c          |    80 +-
 libcdi/src/stream_cgribex.h          |    12 +-
 libcdi/src/stream_ext.c              |    35 +-
 libcdi/src/stream_ext.h              |     6 +-
 libcdi/src/stream_grb.c              |     7 +-
 libcdi/src/stream_grb.h              |    12 +-
 libcdi/src/stream_gribapi.c          |    98 +-
 libcdi/src/stream_gribapi.h          |    10 +-
 libcdi/src/stream_ieg.c              |    50 +-
 libcdi/src/stream_ieg.h              |     6 +-
 libcdi/src/stream_read.c             |    34 +-
 libcdi/src/stream_srv.c              |    41 +-
 libcdi/src/stream_srv.h              |     6 +-
 libcdi/src/stream_write.c            |    50 +-
 libcdi/src/varscan.c                 |     2 +-
 libcdi/src/vlist.c                   |    14 +-
 libcdi/src/vlist_var.c               |    16 +-
 libcdi/src/zaxis.c                   |    12 +-
 libcdi/tests/Makefile.in             |    54 +-
 libcdi/tests/stream_cksum.c          |     2 +-
 libcdi/tests/test_cdf_read.c         |     4 +-
 libcdi/tests/test_grib.c             |     2 +-
 m4/acx_cfortran_flags.m4             |   171 +
 m4/acx_check_cfortran.m4             |   275 +
 src/Adisit.cc                        |     2 +-
 src/Afterburner.cc                   |     6 +-
 src/Arith.cc                         |    18 +-
 src/Arithc.cc                        |     6 +-
 src/Arithdays.cc                     |     6 +-
 src/Arithlat.cc                      |     2 +-
 src/CDIread.cc                       |     2 +-
 src/CDItest.cc                       |     2 +-
 src/CMOR.cc                          |    12 +-
 src/CMOR_lite.cc                     |     2 +-
 src/Cat.cc                           |     2 +-
 src/Change.cc                        |     2 +-
 src/Change_e5slm.cc                  |     6 +-
 src/Cloudlayer.cc                    |     2 +-
 src/Collgrid.cc                      |    14 +-
 src/Command.cc                       |     4 +-
 src/Comp.cc                          |    66 +-
 src/Compc.cc                         |    48 +-
 src/Complextorect.cc                 |     2 +-
 src/Cond.cc                          |    19 +-
 src/Cond2.cc                         |    17 +-
 src/Condc.cc                         |     2 +-
 src/Consecstat.cc                    |    10 +-
 src/Copy.cc                          |     4 +-
 src/Deltat.cc                        |     2 +-
 src/Deltime.cc                       |     2 +-
 src/Derivepar.cc                     |     2 +-
 src/Detrend.cc                       |     2 +-
 src/Diff.cc                          |    10 +-
 src/Distgrid.cc                      |   104 +-
 src/Duplicate.cc                     |     2 +-
 src/EOFs.cc                          |     9 +-
 src/Echam5ini.cc                     |     3 +-
 src/Enlarge.cc                       |    31 +-
 src/Enlargegrid.cc                   |     5 +-
 src/Ensstat.cc                       |     4 +-
 src/Ensstat3.cc                      |     3 +-
 src/Ensval.cc                        |     3 +-
 src/Eof3d.cc                         |     3 +-
 src/Eofcoeff.cc                      |    11 +-
 src/Eofcoeff3d.cc                    |    13 +-
 src/EstFreq.cc                       |     3 +-
 src/Exprf.cc                         |    10 +-
 src/FC.cc                            |    22 +-
 src/Fillmiss.cc                      |    10 +-
 src/Filter.cc                        |     4 +-
 src/Fldrms.cc                        |     8 +-
 src/Fldstat.cc                       |     2 +-
 src/Fldstat2.cc                      |     4 +-
 src/Fourier.cc                       |     2 +-
 src/Gengrid.cc                       |     5 +-
 src/Gradsdes.cc                      |     4 +-
 src/Gridboxstat.cc                   |    66 +-
 src/Harmonic.cc                      |     2 +-
 src/Hi.cc                            |    26 +-
 src/Histogram.cc                     |     2 +-
 src/Importamsr.cc                    |     6 +-
 src/Importbinary.cc                  |     4 +-
 src/Importcmsaf.cc                   |     6 +-
 src/Importobs.cc                     |     2 +-
 src/Info.cc                          |    30 +-
 src/Input.cc                         |     2 +-
 src/Intgrid.cc                       |    92 +-
 src/Intgridtraj.cc                   |     2 +-
 src/Intlevel.cc                      |    10 +-
 src/Intlevel3d.cc                    |    14 +-
 src/Intntime.cc                      |    10 +-
 src/Inttime.cc                       |    10 +-
 src/Intyear.cc                       |     2 +-
 src/Invert.cc                        |     2 +-
 src/Invertlev.cc                     |     6 +-
 src/Isosurface.cc                    |     2 +-
 src/Maggraph.cc                      |     2 +-
 src/Magplot.cc                       |     2 +-
 src/Magvector.cc                     |     2 +-
 src/Makefile.am                      |    36 +-
 src/Makefile.in                      |   239 +-
 src/MapReduce.cc                     |    11 +-
 src/Maskbox.cc                       |     2 +-
 src/Mastrfu.cc                       |     4 +-
 src/Math.cc                          |     2 +-
 src/Merge.cc                         |     2 +-
 src/Mergegrid.cc                     |     2 +-
 src/Mergetime.cc                     |     2 +-
 src/Merstat.cc                       |     6 +-
 src/Monarith.cc                      |    10 +-
 src/Mrotuv.cc                        |    30 +-
 src/Mrotuvb.cc                       |    54 +-
 src/NCL_wind.cc                      |   328 +
 src/Output.cc                        |     2 +-
 src/Outputgmt.cc                     |     2 +-
 src/Pack.cc                          |     2 +-
 src/Pardup.cc                        |     6 +-
 src/Pinfo.cc                         |     8 +-
 src/Pressure.cc                      |     2 +-
 src/Regres.cc                        |     2 +-
 src/Remap.cc                         |    78 +-
 src/Remapeta.cc                      |     2 +-
 src/Replace.cc                       |     8 +-
 src/Replacevalues.cc                 |     2 +-
 src/Rhopot.cc                        |     2 +-
 src/Rotuv.cc                         |     4 +-
 src/Runpctl.cc                       |     2 +-
 src/Runstat.cc                       |     2 +-
 src/Samplegrid.cc                    |     2 +-
 src/Samplegridicon.cc                |   127 +-
 src/Seascount.cc                     |     6 +-
 src/Seaspctl.cc                      |     2 +-
 src/Seasstat.cc                      |     8 +-
 src/Selbox.cc                        |     2 +-
 src/Select.cc                        |     6 +-
 src/Selgridcell.cc                   |     3 +-
 src/Selmulti.cc                      |     2 +-
 src/Seloperator.cc                   |     2 +-
 src/Seltime.cc                       |     2 +-
 src/Selvar.cc                        |     2 +-
 src/Set.cc                           |     2 +-
 src/Setattribute.cc                  |     2 +-
 src/Setbox.cc                        |     2 +-
 src/Setgatt.cc                       |     2 +-
 src/Setgrid.cc                       |     2 +-
 src/Sethalo.cc                       |     2 +-
 src/Setmiss.cc                       |     2 +-
 src/Setpartab.cc                     |     2 +-
 src/Setrcaname.cc                    |     2 +-
 src/Settime.cc                       |     2 +-
 src/Setzaxis.cc                      |     2 +-
 src/Shiftxy.cc                       |     2 +-
 src/Sinfo.cc                         |     4 +-
 src/Smooth.cc                        |    20 +-
 src/Sort.cc                          |     6 +-
 src/Sorttimestamp.cc                 |     2 +-
 src/Spectral.cc                      |     2 +-
 src/Spectrum.cc                      |     2 +-
 src/Split.cc                         |     2 +-
 src/Splitrec.cc                      |     2 +-
 src/Splitsel.cc                      |     2 +-
 src/Splittime.cc                     |     2 +-
 src/Splityear.cc                     |     2 +-
 src/Subtrend.cc                      |     2 +-
 src/Tee.cc                           |     2 +-
 src/Templates.cc                     |     4 +-
 src/Test.cc                          |     2 +-
 src/Tests.cc                         |     2 +-
 src/Timcount.cc                      |     6 +-
 src/Timcumsum.cc                     |     8 +-
 src/Timpctl.cc                       |     2 +-
 src/Timselpctl.cc                    |     2 +-
 src/Timselstat.cc                    |    10 +-
 src/Timsort.cc                       |     2 +-
 src/Timstat.cc                       |     2 +-
 src/Timstat2.cc                      |     2 +-
 src/Timstat3.cc                      |     2 +-
 src/Tocomplex.cc                     |     2 +-
 src/Transpose.cc                     |     2 +-
 src/Trend.cc                         |     2 +-
 src/Trms.cc                          |    19 +-
 src/Tstepcount.cc                    |     2 +-
 src/Vargen.cc                        |    62 +-
 src/Varrms.cc                        |     2 +-
 src/Verifygrid.cc                    |    43 +-
 src/Vertcum.cc                       |     6 +-
 src/Vertintap.cc                     |    12 +-
 src/Vertintml.cc                     |    12 +-
 src/Vertstat.cc                      |    10 +-
 src/Vertwind.cc                      |     4 +-
 src/Wct.cc                           |    15 +-
 src/Wind.cc                          |     2 +-
 src/WindTrans.cc                     |    56 +-
 src/Writerandom.cc                   |     2 +-
 src/XTimstat.cc                      |     9 +-
 src/YAR.cc                           |     6 +-
 src/Ydayarith.cc                     |    12 +-
 src/Ydaypctl.cc                      |     2 +-
 src/Ydaystat.cc                      |    71 +-
 src/Ydrunpctl.cc                     |     2 +-
 src/Ydrunstat.cc                     |     2 +-
 src/Yearmonstat.cc                   |     8 +-
 src/Yhourarith.cc                    |    12 +-
 src/Yhourstat.cc                     |     8 +-
 src/Ymonarith.cc                     |    14 +-
 src/Ymonpctl.cc                      |     2 +-
 src/Ymonstat.cc                      |     8 +-
 src/Yseaspctl.cc                     |     2 +-
 src/Yseasstat.cc                     |     8 +-
 src/Zonstat.cc                       |     6 +-
 src/after_vertint.cc                 |     2 +-
 src/after_vertint.h                  |    30 +-
 src/afterburner.h                    |    10 +-
 src/afterburnerlib.cc                |    14 +-
 src/argument.cc                      |    32 +-
 src/argument.h                       |     2 +-
 src/cdo.cc                           |    58 +-
 src/cdoDebugOutput.cc                |    22 +
 src/cdoDebugOutput.h                 |   112 +
 src/cdo_int.h                        |    19 +-
 src/cdo_read.cc                      |     4 +-
 src/cdo_vlist.cc                     |    22 +-
 src/cdotest.cc                       |     5 +-
 src/cellsearchorder.h                | 30000 +++++++++++++
 src/cf_interface.h                   |    23 +
 src/cfortran.h                       |  2559 ++
 src/cmortable_parser.cc              |     2 +-
 src/compare.h                        |    10 +-
 src/config.h.in                      |    17 +
 src/ecacore.cc                       |     8 +-
 src/ecautil.cc                       |    26 +-
 src/expr.cc                          |    43 +-
 src/expr.h                           |     1 +
 src/expr_lex.cc                      |   310 +-
 src/expr_yacc.cc                     |   210 +-
 src/features.cc                      |    20 +-
 src/field.cc                         |    48 +-
 src/field2.cc                        |   243 +-
 src/fieldc.cc                        |     6 +-
 src/fieldmer.cc                      |    42 +-
 src/fieldzon.cc                      |    42 +-
 src/getMemorySize.c                  |    97 +
 src/getRSS.c                         |   122 +
 src/grid.cc                          |    16 +-
 src/grid.h                           |     2 +-
 src/grid_area.cc                     |    20 +-
 src/grid_from_name.cc                |    14 +-
 src/grid_print.cc                    |    42 +-
 src/grid_read.cc                     |    10 +-
 src/grid_search.cc                   |   122 +-
 src/grid_search.h                    |    21 +-
 src/griddes.cc                       |    12 +-
 src/griddes.h                        |     6 +-
 src/griddes_h5.cc                    |    34 +-
 src/griddes_nc.cc                    |     6 +-
 src/gridreference.cc                 |     4 +-
 src/interpol.cc                      |    44 +-
 src/kdtreelib/kdtree.h               |    52 +-
 src/kdtreelib/kdtree_cartesian.cc    |   126 +-
 src/kdtreelib/kdtree_common.cc       |    84 +-
 src/kdtreelib/kdtree_spherical.cc    |    26 +-
 src/kdtreelib/pmergesort.cc          |    13 +-
 src/kdtreelib/pqueue.cc              |    46 +-
 src/kdtreelib/pqueue.h               |    22 +-
 src/lib/ncl/Makefile.am              |     6 +
 {contrib => src/lib/ncl}/Makefile.in |   222 +-
 src/lib/ncl/rvdv.f                   |   456 +
 src/libncl.h                         |    26 +
 src/modules.cc                       |     5 +-
 src/nearpt3c.cc                      |    32 +
 src/nearpt3c.h                       |     6 -
 src/nearpt3x.h                       |   645 +
 src/operator_help.h                  |    30 +-
 src/par_io.cc                        |     5 +-
 src/par_io.h                         |    14 +-
 src/pipe.cc                          |     8 +-
 src/pipe.h                           |    10 +-
 src/printinfo.h                      |    16 +-
 src/process.cc                       |   367 +-
 src/process.h                        |   112 +-
 src/pstream.cc                       |   136 +-
 src/pstream.h                        |     9 +-
 src/pstream_write.h                  |     4 +-
 src/remap.h                          |    17 +-
 src/remap_bicubic_scrip.cc           |    68 +-
 src/remap_bilinear_scrip.cc          |    68 +-
 src/remap_conserv.cc                 |     4 +-
 src/remap_distwgt.cc                 |    56 +-
 src/remap_scrip_io.cc                |    16 +-
 src/remap_search_latbins.cc          |    68 +-
 src/remap_search_reg2d.cc            |    57 +-
 src/remap_store_link_cnsrv.cc        |     2 +-
 src/remaplib.cc                      |    25 +-
 src/sellist.cc                       |    32 +-
 src/util.cc                          |   106 +-
 src/util.h                           |    19 +-
 test/Arithc.test.in                  |    15 +-
 test/Expr.test.in                    |     3 +-
 test/Makefile.in                     |    80 +-
 test/data/Makefile.in                |    35 +-
 test/data/expr2_ref                  |   Bin 6720 -> 6720 bytes
 369 files changed, 82877 insertions(+), 43079 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5a3dfee..eacecb1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2017-11-23  Uwe Schulzweida
+
+	* Using CDI library version 1.9.2
+	* Version 1.9.2 release
+
+2017-11-02  Uwe Schulzweida
+
+	* expr: nesting of ?: operator lost in cdo-1.9.1 [Bug #7992]
+
+2017-10-26  Uwe Schulzweida
+
+	* select with start=end range aborts with 'Invalid character' [Bug #7976]
+
+2017-10-25  Uwe Schulzweida
+
+	* Expr: convert constant parameter to float for 32-bit float data (bug fix)
+	* Condc: convert constant parameter to float for 32-bit float data (bug fix)
+	* Cond: convert data to float for 32-bit float data (bug fix)
+
+2017-10-23  Uwe Schulzweida
+
+	* Added operator uv2vr_cfd: U and V wind to relative vorticity (interface to NCL)
+	* Added operator uv2dv_cfd: U and V wind to divergence (interface to NCL)
+	* gengrid: bug fix
+
+2017-10-20  Uwe Schulzweida
+
+	* Ydaystat: don't adjust the output year if the last input year is incomplete (bug fix)
+
+2017-10-08  Uwe Schulzweida
+
+	* changed type of nmiss to size_t
+
 2017-10-05  Uwe Schulzweida
 
 	* Using CDI library version 1.9.1
diff --git a/Makefile.am b/Makefile.am
index 73f00df..041c301 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,8 +1,19 @@
 # Process this file with automake to produce Makefile.in
-SUBDIRS = libcdi src contrib test/data test
+SUBDIRS = libcdi src/lib/ncl src contrib test/data test
 #
 EXTRA_DIST=config/default OPERATORS doc/cdo.pdf doc/cdo_cmor.pdf doc/cdo_eca.pdf doc/cdo_magics.pdf doc/cdo_refcard.pdf cdo.spec README
 #
+doc/cdo.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdf ; cp cdo.pdf ..
+doc/cdo_cmor.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfcmor ; cp cdo_cmor.pdf ..
+doc/cdo_eca.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfeca ; cp cdo_eca.pdf ..
+doc/cdo_magics.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfmagics ; cp cdo_magics.pdf ..
+doc/cdo_refcard.pdf:
+	cd doc/tex ; ./makedoc ; ./makerefcard ; cp cdo_refcard.pdf ..
+#
 ACLOCAL_AMFLAGS = -I m4
 #
 CLEANFILES  = `ls *~ 2> /dev/null`
diff --git a/Makefile.in b/Makefile.in
index 8a5cb0f..4dc885a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,21 +88,10 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = .
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/configure $(am__configure_deps) \
-	$(top_srcdir)/config/mkinstalldirs $(srcdir)/cdo.spec.in \
-	$(srcdir)/cdo.settings.in AUTHORS COPYING ChangeLog INSTALL \
-	NEWS README config/ar-lib config/compile config/config.guess \
-	config/config.sub config/depcomp config/install-sh \
-	config/missing config/mkinstalldirs config/ltmain.sh \
-	$(top_srcdir)/config/ar-lib $(top_srcdir)/config/compile \
-	$(top_srcdir)/config/config.guess \
-	$(top_srcdir)/config/config.sub \
-	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
-	$(top_srcdir)/config/missing \
-	$(top_srcdir)/config/tap-driver.sh
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -101,6 +100,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__DIST_COMMON)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
@@ -163,6 +164,18 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/cdo.settings.in \
+	$(srcdir)/cdo.spec.in $(top_srcdir)/config/ar-lib \
+	$(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \
+	$(top_srcdir)/config/config.sub \
+	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
+	$(top_srcdir)/config/missing \
+	$(top_srcdir)/config/mkinstalldirs \
+	$(top_srcdir)/config/tap-driver.sh AUTHORS COPYING ChangeLog \
+	INSTALL NEWS README config/ar-lib config/compile \
+	config/config.guess config/config.sub config/depcomp \
+	config/install-sh config/ltmain.sh config/missing \
+	config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -246,18 +259,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -333,6 +350,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -382,7 +400,7 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 
 # Process this file with automake to produce Makefile.in
-SUBDIRS = libcdi src contrib test/data test
+SUBDIRS = libcdi src/lib/ncl src contrib test/data test
 #
 EXTRA_DIST = config/default OPERATORS doc/cdo.pdf doc/cdo_cmor.pdf doc/cdo_eca.pdf doc/cdo_magics.pdf doc/cdo_refcard.pdf cdo.spec README
 #
@@ -407,7 +425,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -611,7 +628,7 @@ distdir: $(DISTFILES)
 	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
 	|| chmod -R a+r "$(distdir)"
 dist-gzip: distdir
-	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
 	$(am__post_remove_distdir)
 
 dist-bzip2: distdir
@@ -627,17 +644,17 @@ dist-xz: distdir
 	$(am__post_remove_distdir)
 
 dist-tarZ: distdir
-	@echo WARNING: "Support for shar distribution archives is" \
-	               "deprecated." >&2
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
 	$(am__post_remove_distdir)
 
 dist-shar: distdir
-	@echo WARNING: "Support for distribution archives compressed with" \
-		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
 dist-zip: distdir
@@ -655,7 +672,7 @@ dist dist-all:
 distcheck: dist
 	case '$(DIST_ARCHIVES)' in \
 	*.tar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
 	*.tar.bz2*) \
 	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
 	*.tar.lz*) \
@@ -665,22 +682,23 @@ distcheck: dist
 	*.tar.Z*) \
 	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
 	*.shar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
 	chmod -R a-w $(distdir)
 	chmod u+w $(distdir)
-	mkdir $(distdir)/_build $(distdir)/_inst
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
 	chmod a-w $(distdir)
 	test -d $(distdir)/_build || exit 0; \
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
-	  && $(am__cd) $(distdir)/_build \
-	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
@@ -857,6 +875,19 @@ uninstall-am:
 	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
 	ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
+#
+doc/cdo.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdf ; cp cdo.pdf ..
+doc/cdo_cmor.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfcmor ; cp cdo_cmor.pdf ..
+doc/cdo_eca.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfeca ; cp cdo_eca.pdf ..
+doc/cdo_magics.pdf:
+	cd doc/tex ; ./makedoc ; ./makepdfmagics ; cp cdo_magics.pdf ..
+doc/cdo_refcard.pdf:
+	cd doc/tex ; ./makedoc ; ./makerefcard ; cp cdo_refcard.pdf ..
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/NEWS b/NEWS
index f938a48..09510bb 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,14 @@
 CDO NEWS
 --------
 
+Version 1.9.2 (23 November 2017):
+
+   Fixed bugs:
+     * sign of grid size increment changes [Bug #7974]
+     * compilation fails on OpenBSD [Bug #7961]
+     * expr: nesting of ?: operator lost in cdo-1.9.1 [Bug #7992]
+     * select with start=end range aborts with 'Invalid character' [Bug #7976]
+
 Version 1.9.1 (27 September 2017):
 
    New features:
diff --git a/OPERATORS b/OPERATORS
index 15828bc..3078e86 100644
--- a/OPERATORS
+++ b/OPERATORS
@@ -583,6 +583,11 @@ Operator catalog:
    Hurr          hurr            Hurricane days index per time period
    CMORlite      cmorlite        CMOR lite
 -------------------------------------------------------------
+   NCL
+-------------------------------------------------------------
+   NCL_wind      uv2vr_cfd       U and V wind to relative vorticity
+   NCL_wind      uv2dv_cfd       U and V wind to divergence
+-------------------------------------------------------------
    CMOR
 -------------------------------------------------------------
    CMOR          cmor            Climate Model Output Rewriting
diff --git a/aclocal.m4 b/aclocal.m4
index 5d21d17..47fbefd 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,13 +14,51 @@
 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
-[m4_warning([this file was generated for autoconf 2.68.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
 You have another version of autoconf.  It may work, but is not guaranteed to.
 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'.])])
 
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# ===========================================================================
+#    https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+#   AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+#   been defined and thus are available for use.  This avoids random issues
+#   where a macro isn't expanded.  Instead the configure script emits a
+#   non-fatal:
+#
+#     ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+#   It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+#   Here's an example:
+#
+#     AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+#   Copyright (c) 2014 Mike Frysinger <vapier at gentoo.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 2
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+  m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -32,10 +70,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.14'
+[am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14], [],
+m4_if([$1], [1.15.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,12 +89,12 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
-# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -118,7 +156,7 @@ AC_SUBST([AR])dnl
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -163,15 +201,14 @@ AC_SUBST([AR])dnl
 # configured tree to be moved without reconfiguration.
 
 AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 ])
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -202,7 +239,7 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -393,7 +430,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -469,7 +506,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -559,8 +596,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([AC_PROG_MAKE_SET])dnl
 AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -633,7 +670,11 @@ to "yes", and re-run configure.
 END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
-fi])
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
 dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
@@ -662,7 +703,7 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -673,7 +714,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -683,7 +724,7 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -705,7 +746,7 @@ AC_SUBST([am__leading_dot])])
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -740,7 +781,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -790,7 +831,7 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -829,7 +870,7 @@ fi
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -858,7 +899,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -905,7 +946,7 @@ AC_LANG_POP([C])])
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -924,7 +965,7 @@ AC_DEFUN([AM_RUN_LOG],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1005,7 +1046,7 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1065,7 +1106,7 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1093,7 +1134,7 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1112,7 +1153,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1243,6 +1284,8 @@ AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([m4/acx_cfortran_flags.m4])
+m4_include([m4/acx_check_cfortran.m4])
 m4_include([m4/acx_options.m4])
 m4_include([m4/ax_cxx_compile_stdcxx.m4])
 m4_include([m4/ax_cxx_compile_stdcxx_11.m4])
diff --git a/cdo.settings.in b/cdo.settings.in
index 514d0c5..6492811 100644
--- a/cdo.settings.in
+++ b/cdo.settings.in
@@ -1,54 +1,68 @@
 {
-   "CXX"                : "@CXX@",
-   "CC"                 : "@CC@",
-   "CPP"                : "@CPP@",
-   "CPPFLAGS"           : "@CPPFLAGS@",
-   "CXXFLAGS"           : "@CXXFLAGS@",
-   "CFLAGS"             : "@CFLAGS@",
-   "LDFLAGS"            : "@LDFLAGS@",
-   "LIBS"               : "@LIBS@",
-   "FCFLAGS"            : "@FCFLAGS@",
-   "INCLUDES"           : "@INCLUDES@",
-   "LD"                 : "@LD@",
-   "NM"                 : "@NM@",
-   "AR"                 : "@AR@",
-   "AS"                 : "@AS@",
-   "DLLTOOL"            : "@DLLTOOL@",
-   "OBJDUMP"            : "@OBJDUMP@",
-   "STRIP"              : "@STRIP@",
-   "RANLIB"             : "@RANLIB@",
-   "INSTALL"            : "@INSTALL@",
-   "cdi"                : {
-     "enable_cdi_lib" : @ENABLE_CDI_LIB@
-   },
-  "threads"    : {
-    "lib"      : "@THREADS_LIBS@",
-    "include"  : "@THREADS_INCLUDE@"
-  "szlib"      : {
-    "lib"      : "@SZLIB_LIBS@",
-    "include"  : "@SZLIB_INCLUDE@"
+  "build" : {
+    "tools" : {
+      "CXX"                : "@CXX@",
+      "CC"                 : "@CC@",
+      "CPP"                : "@CPP@",
+      "CPPFLAGS"           : "@CPPFLAGS@",
+      "CXXFLAGS"           : "@CXXFLAGS@",
+      "CFLAGS"             : "@CFLAGS@",
+      "F77"                : "@F77@",
+      "FFLAGS"             : "@FFLAGS@",
+      "LDFLAGS"            : "@LDFLAGS@",
+      "LIBS"               : "@LIBS@",
+      "FCFLAGS"            : "@FCFLAGS@",
+      "INCLUDES"           : "@INCLUDES@",
+      "LD"                 : "@LD@",
+      "NM"                 : "@NM@",
+      "AR"                 : "@AR@",
+      "AS"                 : "@AS@",
+      "DLLTOOL"            : "@DLLTOOL@",
+      "OBJDUMP"            : "@OBJDUMP@",
+      "STRIP"              : "@STRIP@",
+      "RANLIB"             : "@RANLIB@",
+      "INSTALL"            : "@INSTALL@",
+    },
+    "libraries" : {
+      "threads"    : {
+        "lib"      : "@THREADS_LIBS@",
+        "include"  : "@THREADS_INCLUDE@"
+      },
+      "szlib"      : {
+        "lib"      : "@SZLIB_LIBS@",
+        "include"  : "@SZLIB_INCLUDE@"
+      },
+      "hdf5"       : {
+        "lib"      : "@HDF5_LIBS@",
+        "include"  : "@HDF5_INCLUDE@"
+      },
+      "netcdf"     : {
+        "lib"      : "@NETCDF_LIBS@",
+        "include"  : "@NETCDF_INCLUDE@"
+      },
+      "udunits2"   : {
+        "lib"      : "@UDUNITS_LDFLAGS@",
+        "include"  : "@UDUNITS_INCLUDE@"
+      },
+      "proj"       : {
+        "lib"      : "@PROJ_LDFLAGS@",
+        "include"  : "@PROJ_INCLUDE@"
+      },
+      "magics"       : {
+        "lib"      : "@MAGICS_LIBS@",
+        "include"  : "@MAGICS_INCLUDE@"
+      }
+    },
+    "platform" : {
+      "USER_NAME"   : "@USER_NAME@",
+      "HOST_NAME"   : "@HOST_NAME@",
+      "SYSTEM_TYPE" : "@SYSTEM_TYPE@"
+    },
   },
-  "hdf5"       : {
-    "lib"      : "@HDF5_LIBS@",
-    "include"  : "@HDF5_INCLUDE@"
-  },
-  "netcdf"     : {
-    "lib"      : "@NETCDF_LIBS@",
-    "include"  : "@NETCDF_INCLUDE@"
-  },
-  "udunits2"   : {
-    "lib"      : "@UDUNITS_LDFLAGS@",
-    "include"  : "@UDUNITS_INCLUDE@"
-  },
-  "proj"       : {
-    "lib"      : "@PROJ_LDFLAGS@",
-    "include"  : "@PROJ_INCLUDE@"
-  },
-  "magics"       : {
-    "lib"      : "@MAGICS_LIBS@",
-    "include"  : "@MAGICS_INCLUDE@"
-  },
-  "USER_NAME"          : "@USER_NAME@",
-  "HOST_NAME"          : "@HOST_NAME@",
-  "SYSTEM_TYPE"        : "@SYSTEM_TYPE@"
+  "features" : {
+    "enable_cdi_lib" : @ENABLE_CDI_LIB@,
+    "enable_data"    : @ENABLE_DATA@,
+    "enable_fortran" : @ENABLE_FORTRAN@,
+    "fortran_works"  : "@FORTRAN_WORKS@",
+  }
 }
diff --git a/cdo.spec b/cdo.spec
index 501232c..41a1c25 100644
--- a/cdo.spec
+++ b/cdo.spec
@@ -4,7 +4,7 @@
 
 Name:           cdo
 #BuildRequires:  
-Version:        1.9.1
+Version:        1.9.2rc1
 Release:        1
 Summary:        Climate Data Operators
 License:        GNU GENERAL PUBLIC LICENSE Version 2, June 1991
diff --git a/config/default b/config/default
index e5600d6..9bc02aa 100755
--- a/config/default
+++ b/config/default
@@ -109,7 +109,8 @@ case "${HOSTNAME}" in
 	            CXX=icpc CXXFLAGS="-g -Wall -O2 -qopt-report=5 -march=native" \
 	            CC=icc   CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
         elif  test "$COMP" = clang ; then
-	  ${CONFPATH}configure \
+	  ${CONFPATH}configure --prefix=$HOME/local \
+                    --enable-maintainer-mode \
                     $CDOLIBS LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.3.0/lib" \
 	            CXX=clang++ CXXFLAGS="-g -Wall -pedantic -O3" \
 	            CC=clang    CFLAGS="-g -Wall -pedantic -O3"
@@ -127,8 +128,9 @@ case "${HOSTNAME}" in
 	  ${CONFPATH}configure --prefix=$HOME/local \
                     --enable-maintainer-mode \
                     $CDOLIBS LDFLAGS="-Wl,-rpath,$HOME/local/eccodes-2.3.0/lib" \
-	            CXX=g++ CXXFLAGS="-g -pipe -Wall -W -Wfloat-equal -pedantic -O3 -march=native -Wa,-q -fstack-protector" \
-	            CC=gcc  CFLAGS="-g -pipe -Wall -W -Wfloat-equal -pedantic -O3 -march=native -Wa,-q -fstack-protector"
+                    F77=gfortran FFLAGS="-g -O2" \
+	            CXX=g++ CXXFLAGS="-g -pipe -Wall -W -Wfloat-equal -pedantic -O3  -fstack-protector" \
+	            CC=gcc  CFLAGS="-g -pipe -Wall -W -Wfloat-equal -pedantic -O3  -fstack-protector"
 #                    --with-libxml2=/usr \
 #                    --with-magics=/Users/m214003/local/Magics-2.18.14nio \
         fi
@@ -231,6 +233,7 @@ case "${HOSTNAME}" in
                     --with-fftw3 \
                     $CDOLIBS \
                     LDFLAGS="-Wl,-rpath,/sw/rhel6-x64/eccodes/eccodes-2.3.0-gcc48/lib" \
+                    F77=ifort FFLAGS="-g -O2" \
 	            CXX=icpc CXXFLAGS="-g -Wall -O2 -qopt-report=5 -march=core-avx2" \
 	            CC=icc   CFLAGS="-g -Wall -O2 -qopt-report=5 -march=core-avx2"
         elif  test "$COMP" = pgi ; then
@@ -244,6 +247,7 @@ case "${HOSTNAME}" in
                     --with-fftw3 \
                     $CDOLIBS \
                     LDFLAGS="-Wl,-rpath,/sw/rhel6-x64/eccodes/eccodes-2.3.0-gcc48/lib" \
+                    F77=gfortran FFLAGS="-g -O2" \
                     CXX=g++ CXXFLAGS='-g -Wall -O3 -march=native -mavx2' \
                     CC=gcc  CFLAGS='-g -Wall -O3 -march=native -mavx2'
 	fi
@@ -279,7 +283,7 @@ case "${HOSTNAME}" in
                     CC=icc CFLAGS="-g -O2 -Wall -fno-alias"
 	;;
 # x86_64-archlinux
-    luthien*)
+    melian)
       case "$COMP" in
       gcc|clang)
  	${CONFPATH}configure --prefix=$HOME/local \
diff --git a/configure b/configure
index a5ddc92..d2e8b4c 100755
--- a/configure
+++ b/configure
@@ -1,13 +1,11 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdo 1.9.1.
+# Generated by GNU Autoconf 2.69 for cdo 1.9.2rc1.
 #
 # Report bugs to <http://mpimet.mpg.de/cdo>.
 #
 #
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -136,6 +134,31 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -169,7 +192,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -222,21 +246,25 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  # We cannot yet assume a decent shell, so we have to provide a
-	# neutralization value for shells without unset; and this also
-	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
-	BASH_ENV=/dev/null
-	ENV=/dev/null
-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
 fi
 
     if test x$as_have_required = xno; then :
@@ -339,6 +367,14 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -460,6 +496,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -494,16 +534,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -515,28 +555,8 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -570,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdo'
 PACKAGE_TARNAME='cdo'
-PACKAGE_VERSION='1.9.1'
-PACKAGE_STRING='cdo 1.9.1'
+PACKAGE_VERSION='1.9.2rc1'
+PACKAGE_STRING='cdo 1.9.2rc1'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdo'
 PACKAGE_URL=''
 
@@ -620,7 +640,6 @@ LIBOBJS
 AM_CPPFLAGS
 CLIBS
 CLDFLAGS
-FCFLAGS
 BUILD_AVX2_TESTS_FALSE
 BUILD_AVX2_TESTS_TRUE
 BUILD_AVX_TESTS_FALSE
@@ -679,12 +698,22 @@ PTHREAD_LIBS
 PTHREAD_CC
 ax_pthread_config
 ENABLE_DATA
+ENABLE_NEARPT3_FALSE
+ENABLE_NEARPT3_TRUE
+ENABLE_NEARPT3
+FORTRAN_WORKS
+USE_F77_FALSE
+USE_F77_TRUE
+ENABLE_FORTRAN
 SYSTEM_TYPE
 HOST_NAME
 USER_NAME
 AS
 OPENMP_CFLAGS
 HAVE_CXX11
+ac_ct_F77
+FFLAGS
+F77
 CXXCPP
 am__fastdepCXX_FALSE
 am__fastdepCXX_TRUE
@@ -823,6 +852,8 @@ with_sysroot
 enable_libtool_lock
 enable_openmp
 enable_largefile
+enable_fortran
+enable_nearpt3
 enable_data
 with_threads
 with_szlib
@@ -858,7 +889,9 @@ CPP
 CXX
 CXXFLAGS
 CCC
-CXXCPP'
+CXXCPP
+F77
+FFLAGS'
 ac_subdirs_all='libcdi'
 
 # Initialize some variables set by options.
@@ -1314,8 +1347,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1401,7 +1432,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 cdo 1.9.1 to adapt to many kinds of systems.
+\`configure' configures cdo 1.9.2rc1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1471,7 +1502,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdo 1.9.1:";;
+     short | recursive ) echo "Configuration of cdo 1.9.2rc1:";;
    esac
   cat <<\_ACEOF
 
@@ -1495,6 +1526,8 @@ Optional Features:
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --disable-openmp        do not use OpenMP
   --disable-largefile     omit support for large files
+  --disable-fortran       Omit building of Fortran routines
+  --enable-nearpt3        nearpt3 support [default=no]
   --enable-data           DATA support [default=yes]
   --enable-grib           GRIB support [default=yes]
   --enable-cgribex        Use the CGRIBEX library [default=yes]
@@ -1556,6 +1589,8 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CXXCPP      C++ preprocessor
+  F77         Fortran 77 compiler command
+  FFLAGS      Fortran 77 compiler flags
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -1623,10 +1658,10 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdo configure 1.9.1
-generated by GNU Autoconf 2.68
+cdo configure 1.9.2rc1
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1702,7 +1737,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2000,7 +2035,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2019,6 +2054,90 @@ fi
 
 } # ac_fn_cxx_try_link
 
+# ac_fn_f77_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_f77_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_f77_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_f77_try_compile
+
+# ac_fn_f77_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_f77_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_f77_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_f77_try_link
+
 # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
 # ----------------------------------------------------
 # Tries to find if the field MEMBER exists in type AGGR, after including
@@ -2212,12 +2331,54 @@ $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
 } # ac_fn_c_check_decl
+
+# ac_fn_f77_try_run LINENO
+# ------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_f77_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_f77_try_run
 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 cdo $as_me 1.9.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+It was created by cdo $as_me 1.9.2rc1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
@@ -2679,7 +2840,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
 
 # AM_INIT_AUTOMAKE([foreign -Wall -Werror])
-am__api_version='1.14'
+am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -2718,7 +2879,7 @@ case $as_dir/ in #((
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
 	  if test $ac_prog = install &&
 	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
 	    # AIX install.  It has an incompatible calling convention.
@@ -2851,8 +3012,8 @@ test "$program_suffix" != NONE &&
 ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
 program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
 
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
   case $am_aux_dir in
@@ -2871,7 +3032,7 @@ else
 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -2902,7 +3063,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2942,7 +3103,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -2993,7 +3154,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_prog in mkdir gmkdir; do
 	 for ac_exec_ext in '' $ac_executable_extensions; do
-	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
 	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
 	     'mkdir (GNU coreutils) '* | \
 	     'mkdir (coreutils) '* | \
@@ -3040,7 +3201,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3165,7 +3326,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdo'
- VERSION='1.9.1'
+ VERSION='1.9.2rc1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3199,8 +3360,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 mkdir_p='$(MKDIR_P)'
 
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 # Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
@@ -3257,6 +3418,7 @@ END
     as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
   fi
 fi
+
 ac_config_headers="$ac_config_headers src/config.h"
 
 
@@ -3369,7 +3531,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3409,7 +3571,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3462,7 +3624,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3503,7 +3665,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -3561,7 +3723,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3605,7 +3767,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4051,8 +4213,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -4344,7 +4505,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4388,7 +4549,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4615,7 +4776,7 @@ do
     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"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+      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
@@ -4691,7 +4852,7 @@ do
     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"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+      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
@@ -4757,7 +4918,7 @@ do
     for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+      as_fn_executable_p "$ac_path_EGREP" || continue
 # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -4824,7 +4985,7 @@ do
     for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+      as_fn_executable_p "$ac_path_FGREP" || continue
 # Check for GNU ac_path_FGREP and select it if it is found.
   # Check for GNU $ac_path_FGREP
 case `"$ac_path_FGREP" --version 2>&1` in
@@ -5080,7 +5241,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5124,7 +5285,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5548,7 +5709,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5588,7 +5749,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5894,7 +6055,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5934,7 +6095,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6037,7 +6198,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6081,7 +6242,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6206,7 +6367,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6246,7 +6407,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6305,7 +6466,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6345,7 +6506,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6994,7 +7155,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7034,7 +7195,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7114,7 +7275,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7154,7 +7315,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7206,7 +7367,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7246,7 +7407,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7298,7 +7459,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7338,7 +7499,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7390,7 +7551,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7430,7 +7591,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL="otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7482,7 +7643,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7522,7 +7683,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL64="otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12030,7 +12191,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_BASH="$as_dir/$ac_word$ac_exec_ext"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12073,7 +12234,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_ac_pt_BASH="$as_dir/$ac_word$ac_exec_ext"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12128,7 +12289,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12168,7 +12329,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12220,7 +12381,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CXX="${ac_tool_prefix}g++"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12260,7 +12421,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CXX="g++"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12441,7 +12602,7 @@ main ()
   return 0;
 }
 _ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
 do
   CC="$ac_save_CC $ac_arg"
   if ac_fn_c_try_compile "$LINENO"; then :
@@ -12501,7 +12662,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -12545,7 +12706,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CXX="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -16057,86 +16218,3015 @@ 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 C/C++ restrict keyword" >&5
-$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
-if ${ac_cv_c_restrict+:} false; then :
+ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_F77+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  ac_cv_c_restrict=no
-   # The order here caters to the fact that C++ does not require restrict.
-   for ac_kw in __restrict __restrict__ _Restrict restrict; do
-     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-typedef int * int_ptr;
-	int foo (int_ptr $ac_kw ip) {
-	return ip[0];
-       }
-int
-main ()
-{
-int s[1];
-	int * $ac_kw t = s;
-	t[0] = 0;
-	return foo(t)
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_c_restrict=$ac_kw
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-     test "$ac_cv_c_restrict" != no && break
-   done
+  if test -n "$F77"; then
+  ac_cv_prog_F77="$F77" # Let the user override the test.
+else
+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_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
-$as_echo "$ac_cv_c_restrict" >&6; }
+fi
+F77=$ac_cv_prog_F77
+if test -n "$F77"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F77" >&5
+$as_echo "$F77" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
- case $ac_cv_c_restrict in
-   restrict) ;;
-   no) $as_echo "#define restrict /**/" >>confdefs.h
- ;;
-   *)  cat >>confdefs.h <<_ACEOF
-#define restrict $ac_cv_c_restrict
-_ACEOF
- ;;
- esac
 
-  ax_cxx_compile_alternatives="11 0x"    ax_cxx_compile_cxx11_required=true
-  ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-  ac_success=no
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
-$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
-if ${ax_cv_cxx_compile_cxx11+:} false; then :
+    test -n "$F77" && break
+  done
+fi
+if test -z "$F77"; then
+  ac_ct_F77=$F77
+  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_F77+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-// If the compiler admits that it is not ready for C++11, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
+  if test -n "$ac_ct_F77"; then
+  ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test.
+else
+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_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_F77="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
-#error "This is not a C++ compiler"
+fi
+fi
+ac_ct_F77=$ac_cv_prog_ac_ct_F77
+if test -n "$ac_ct_F77"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_F77" >&5
+$as_echo "$ac_ct_F77" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
-#elif __cplusplus < 201103L
 
-#error "This is not a C++11 compiler"
+  test -n "$ac_ct_F77" && break
+done
 
-#else
+  if test "x$ac_ct_F77" = x; then
+    F77=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    F77=$ac_ct_F77
+  fi
+fi
 
-namespace cxx11
-{
 
-  namespace test_static_assert
-  {
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+rm -f a.out
+
+# If we don't use `.F' as extension, the preprocessor is not run on the
+# input file.  (Note that this only needs to work for GNU compilers.)
+ac_save_ext=$ac_ext
+ac_ext=F
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5
+$as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; }
+if ${ac_cv_f77_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.$ac_ext <<_ACEOF
+      program main
+#ifndef __GNUC__
+       choke me
+#endif
+
+      end
+_ACEOF
+if ac_fn_f77_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_f77_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_compiler_gnu" >&5
+$as_echo "$ac_cv_f77_compiler_gnu" >&6; }
+ac_ext=$ac_save_ext
+ac_test_FFLAGS=${FFLAGS+set}
+ac_save_FFLAGS=$FFLAGS
+FFLAGS=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5
+$as_echo_n "checking whether $F77 accepts -g... " >&6; }
+if ${ac_cv_prog_f77_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  FFLAGS=-g
+cat > conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+if ac_fn_f77_try_compile "$LINENO"; then :
+  ac_cv_prog_f77_g=yes
+else
+  ac_cv_prog_f77_g=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_g" >&5
+$as_echo "$ac_cv_prog_f77_g" >&6; }
+if test "$ac_test_FFLAGS" = set; then
+  FFLAGS=$ac_save_FFLAGS
+elif test $ac_cv_prog_f77_g = yes; then
+  if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+    FFLAGS="-g -O2"
+  else
+    FFLAGS="-g"
+  fi
+else
+  if test "x$ac_cv_f77_compiler_gnu" = xyes; then
+    FFLAGS="-O2"
+  else
+    FFLAGS=
+  fi
+fi
+
+if test $ac_compiler_gnu = yes; then
+  G77=yes
+else
+  G77=
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+      ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+archive_cmds_need_lc_F77=no
+allow_undefined_flag_F77=
+always_export_symbols_F77=no
+archive_expsym_cmds_F77=
+export_dynamic_flag_spec_F77=
+hardcode_direct_F77=no
+hardcode_direct_absolute_F77=no
+hardcode_libdir_flag_spec_F77=
+hardcode_libdir_separator_F77=
+hardcode_minus_L_F77=no
+hardcode_automatic_F77=no
+inherit_rpath_F77=no
+module_cmds_F77=
+module_expsym_cmds_F77=
+link_all_deplibs_F77=unknown
+old_archive_cmds_F77=$old_archive_cmds
+reload_flag_F77=$reload_flag
+reload_cmds_F77=$reload_cmds
+no_undefined_flag_F77=
+whole_archive_flag_spec_F77=
+enable_shared_with_static_runtimes_F77=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+objext_F77=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+  # save warnings/boilerplate of simple test code
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  compiler_F77=$CC
+  for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+  GCC=$G77
+  if test -n "$compiler"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[4-9]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+    GCC_F77="$G77"
+    LD_F77="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    lt_prog_compiler_wl_F77=
+lt_prog_compiler_pic_F77=
+lt_prog_compiler_static_F77=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl_F77='-Wl,'
+    lt_prog_compiler_static_F77='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_F77='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_F77='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_F77='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static_F77=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_F77='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared_F77=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_F77='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_F77=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic_F77='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl_F77='-Xlinker '
+      if test -n "$lt_prog_compiler_pic_F77"; then
+        lt_prog_compiler_pic_F77="-Xcompiler $lt_prog_compiler_pic_F77"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_F77='-Bstatic'
+      else
+	lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic_F77='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic_F77='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static_F77='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static_F77='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='-KPIC'
+	lt_prog_compiler_static_F77='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='-fPIC'
+	lt_prog_compiler_static_F77='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='--shared'
+	lt_prog_compiler_static_F77='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl_F77='-Wl,-Wl,,'
+	lt_prog_compiler_pic_F77='-PIC'
+	lt_prog_compiler_static_F77='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='-fpic'
+	lt_prog_compiler_static_F77='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl_F77='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static_F77='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl_F77='-Wl,'
+	lt_prog_compiler_pic_F77='-qpic'
+	lt_prog_compiler_static_F77='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic_F77='-KPIC'
+	  lt_prog_compiler_static_F77='-Bstatic'
+	  lt_prog_compiler_wl_F77=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic_F77='-KPIC'
+	  lt_prog_compiler_static_F77='-Bstatic'
+	  lt_prog_compiler_wl_F77='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic_F77='-KPIC'
+	  lt_prog_compiler_static_F77='-Bstatic'
+	  lt_prog_compiler_wl_F77='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl_F77='-Wl,'
+	  lt_prog_compiler_pic_F77='-fPIC'
+	  lt_prog_compiler_static_F77='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl_F77='-Wl,'
+	  lt_prog_compiler_pic_F77='-fpic'
+	  lt_prog_compiler_static_F77='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_F77='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static_F77='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static_F77='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl_F77='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl_F77='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl_F77='-Qoption ld '
+      lt_prog_compiler_pic_F77='-PIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic_F77='-Kconform_pic'
+	lt_prog_compiler_static_F77='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      lt_prog_compiler_pic_F77='-KPIC'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl_F77='-Wl,'
+      lt_prog_compiler_can_build_shared_F77=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic_F77='-pic'
+      lt_prog_compiler_static_F77='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared_F77=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_F77=
+    ;;
+  *)
+    lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_F77=$lt_prog_compiler_pic_F77
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_F77" >&5
+$as_echo "$lt_cv_prog_compiler_pic_F77" >&6; }
+lt_prog_compiler_pic_F77=$lt_cv_prog_compiler_pic_F77
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_F77"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_F77=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_F77"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works_F77=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_F77" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_F77" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_F77" = xyes; then
+    case $lt_prog_compiler_pic_F77 in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;;
+     esac
+else
+    lt_prog_compiler_pic_F77=
+     lt_prog_compiler_can_build_shared_F77=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_F77=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works_F77=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_F77=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_F77" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_F77" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_F77" = xyes; then
+    :
+else
+    lt_prog_compiler_static_F77=
+fi
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_F77=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_F77=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_F77" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_F77" >&6; }
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_F77=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_F77=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_F77" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_F77" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag_F77=
+  always_export_symbols_F77=no
+  archive_cmds_F77=
+  archive_expsym_cmds_F77=
+  compiler_needs_object_F77=no
+  enable_shared_with_static_runtimes_F77=no
+  export_dynamic_flag_spec_F77=
+  export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic_F77=no
+  hardcode_direct_F77=no
+  hardcode_direct_absolute_F77=no
+  hardcode_libdir_flag_spec_F77=
+  hardcode_libdir_separator_F77=
+  hardcode_minus_L_F77=no
+  hardcode_shlibpath_var_F77=unsupported
+  inherit_rpath_F77=no
+  link_all_deplibs_F77=unknown
+  module_cmds_F77=
+  module_expsym_cmds_F77=
+  old_archive_from_new_cmds_F77=
+  old_archive_from_expsyms_cmds_F77=
+  thread_safe_flag_spec_F77=
+  whole_archive_flag_spec_F77=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms_F77=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms_F77='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs_F77=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec_F77='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec_F77=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs_F77=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds_F77=''
+        ;;
+      m68k)
+            archive_cmds_F77='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec_F77='-L$libdir'
+            hardcode_minus_L_F77=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag_F77=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      export_dynamic_flag_spec_F77='${wl}--export-all-symbols'
+      allow_undefined_flag_F77=unsupported
+      always_export_symbols_F77=no
+      enable_shared_with_static_runtimes_F77=yes
+      export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms_F77='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs_F77=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct_F77=no
+      hardcode_shlibpath_var_F77=no
+      hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec_F77='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec_F77=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object_F77=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec_F77='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object_F77=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds_F77='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds_F77='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec_F77='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+	  archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds_F77='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs_F77=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs_F77=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs_F77=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+	    archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs_F77=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs_F77" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec_F77=
+      export_dynamic_flag_spec_F77=
+      whole_archive_flag_spec_F77=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag_F77=unsupported
+      always_export_symbols_F77=yes
+      archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L_F77=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct_F77=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds_F77=''
+      hardcode_direct_F77=yes
+      hardcode_direct_absolute_F77=yes
+      hardcode_libdir_separator_F77=':'
+      link_all_deplibs_F77=yes
+      file_list_spec_F77='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct_F77=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L_F77=yes
+	  hardcode_libdir_flag_spec_F77='-L$libdir'
+	  hardcode_libdir_separator_F77=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec_F77='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols_F77=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag_F77='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+if ac_fn_f77_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__F77=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__F77"; then
+    lt_cv_aix_libpath__F77=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__F77"; then
+    lt_cv_aix_libpath__F77="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__F77
+fi
+
+        hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds_F77='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag_F77="-z nodefs"
+	  archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+if ac_fn_f77_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__F77=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__F77"; then
+    lt_cv_aix_libpath__F77=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__F77"; then
+    lt_cv_aix_libpath__F77="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__F77
+fi
+
+	 hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag_F77=' ${wl}-bernotok'
+	  allow_undefined_flag_F77=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec_F77='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec_F77='$convenience'
+	  fi
+	  archive_cmds_need_lc_F77=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds_F77=''
+        ;;
+      m68k)
+            archive_cmds_F77='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec_F77='-L$libdir'
+            hardcode_minus_L_F77=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec_F77=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec_F77=' '
+	allow_undefined_flag_F77=unsupported
+	always_export_symbols_F77=yes
+	file_list_spec_F77='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds_F77='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, F77)='true'
+	enable_shared_with_static_runtimes_F77=yes
+	exclude_expsyms_F77='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds_F77='chmod 644 $oldlib'
+	postlink_cmds_F77='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec_F77=' '
+	allow_undefined_flag_F77=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds_F77='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds_F77='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes_F77=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_F77=no
+  hardcode_direct_F77=no
+  hardcode_automatic_F77=yes
+  hardcode_shlibpath_var_F77=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec_F77='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    compiler_needs_object_F77=yes
+  else
+    whole_archive_flag_spec_F77=''
+  fi
+  link_all_deplibs_F77=yes
+  allow_undefined_flag_F77="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds_F77="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds_F77="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds_F77="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds_F77="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs_F77=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_F77=yes
+      hardcode_minus_L_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds_F77='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      hardcode_direct_F77=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L_F77=yes
+      export_dynamic_flag_spec_F77='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds_F77='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator_F77=:
+	hardcode_direct_F77=yes
+	hardcode_direct_absolute_F77=yes
+	export_dynamic_flag_spec_F77='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L_F77=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds_F77='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_F77='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator_F77=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct_F77=no
+	  hardcode_shlibpath_var_F77=no
+	  ;;
+	*)
+	  hardcode_direct_F77=yes
+	  hardcode_direct_absolute_F77=yes
+	  export_dynamic_flag_spec_F77='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L_F77=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   cat > conftest.$ac_ext <<_ACEOF
+
+      subroutine foo
+      end
+_ACEOF
+if ac_fn_f77_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc_F77='no'
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      inherit_rpath_F77=yes
+      link_all_deplibs_F77=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_direct_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    newsos6)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct_F77=yes
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct_F77=yes
+	hardcode_shlibpath_var_F77=no
+	hardcode_direct_absolute_F77=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec_F77='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec_F77='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs_F77=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_minus_L_F77=yes
+      allow_undefined_flag_F77=unsupported
+      archive_cmds_F77='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag_F77=' -expect_unresolved \*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc_F77='no'
+      hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator_F77=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag_F77=' -expect_unresolved \*'
+	archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec_F77='-rpath $libdir'
+      fi
+      archive_cmds_need_lc_F77='no'
+      hardcode_libdir_separator_F77=:
+      ;;
+
+    solaris*)
+      no_undefined_flag_F77=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds_F77='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds_F77='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds_F77='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_F77='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec_F77='-R$libdir'
+      hardcode_shlibpath_var_F77=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec_F77='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs_F77=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_direct_F77=yes
+      hardcode_minus_L_F77=yes
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_F77=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds_F77='$CC -r -o $output$reload_objs'
+	  hardcode_direct_F77=no
+        ;;
+	motorola)
+	  archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var_F77=no
+      export_dynamic_flag_spec_F77='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var_F77=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs_F77=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_F77='${wl}-z,text'
+      archive_cmds_need_lc_F77=no
+      hardcode_shlibpath_var_F77=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag_F77='${wl}-z,text'
+      allow_undefined_flag_F77='${wl}-z,nodefs'
+      archive_cmds_need_lc_F77=no
+      hardcode_shlibpath_var_F77=no
+      hardcode_libdir_flag_spec_F77='${wl}-R,$libdir'
+      hardcode_libdir_separator_F77=':'
+      link_all_deplibs_F77=yes
+      export_dynamic_flag_spec_F77='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec_F77='-L$libdir'
+      hardcode_shlibpath_var_F77=no
+      ;;
+
+    *)
+      ld_shlibs_F77=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec_F77='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_F77" >&5
+$as_echo "$ld_shlibs_F77" >&6; }
+test "$ld_shlibs_F77" = no && can_build_shared=no
+
+with_gnu_ld_F77=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_F77" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_F77=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_F77 in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_F77+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl_F77
+	  pic_flag=$lt_prog_compiler_pic_F77
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag_F77
+	  allow_undefined_flag_F77=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_F77 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds_F77 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc_F77=no
+	  else
+	    lt_cv_archive_cmds_need_lc_F77=yes
+	  fi
+	  allow_undefined_flag_F77=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_F77" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_F77" >&6; }
+      archive_cmds_need_lc_F77=$lt_cv_archive_cmds_need_lc_F77
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_F77\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_F77\""
+    cat > conftest.$ac_ext <<_ACEOF
+      program main
+
+      end
+_ACEOF
+if ac_fn_f77_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_F77=
+if test -n "$hardcode_libdir_flag_spec_F77" ||
+   test -n "$runpath_var_F77" ||
+   test "X$hardcode_automatic_F77" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct_F77" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, F77)" != no &&
+     test "$hardcode_minus_L_F77" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_F77=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_F77=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_F77=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_F77" >&5
+$as_echo "$hardcode_action_F77" >&6; }
+
+if test "$hardcode_action_F77" = relink ||
+   test "$inherit_rpath_F77" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
+$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
+if ${ac_cv_c_restrict+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_restrict=no
+   # The order here caters to the fact that C++ does not require restrict.
+   for ac_kw in __restrict __restrict__ _Restrict restrict; do
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+typedef int * int_ptr;
+	int foo (int_ptr $ac_kw ip) {
+	return ip[0];
+       }
+int
+main ()
+{
+int s[1];
+	int * $ac_kw t = s;
+	t[0] = 0;
+	return foo(t)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_restrict=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+     test "$ac_cv_c_restrict" != no && break
+   done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
+$as_echo "$ac_cv_c_restrict" >&6; }
+
+ case $ac_cv_c_restrict in
+   restrict) ;;
+   no) $as_echo "#define restrict /**/" >>confdefs.h
+ ;;
+   *)  cat >>confdefs.h <<_ACEOF
+#define restrict $ac_cv_c_restrict
+_ACEOF
+ ;;
+ esac
+
+  ax_cxx_compile_alternatives="11 0x"    ax_cxx_compile_cxx11_required=true
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+  ac_success=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
 
     template <typename T>
     struct check
@@ -17115,7 +20205,8 @@ if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_prog_c_openmp='none needed'
 else
   ac_cv_prog_c_openmp='unsupported'
-	  	  	  	  	  	  	  	  	  	  	  	  	  for ac_option in -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp; do
+	  	  	  	  	  	  	                                	  	  	  	  	  	  for ac_option in -fopenmp -xopenmp -openmp -mp -omp -qsmp=omp -homp \
+                           -Popenmp --openmp; do
 	    ac_save_CFLAGS=$CFLAGS
 	    CFLAGS="$CFLAGS $ac_option"
 	    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -17170,7 +20261,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17210,7 +20301,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17262,7 +20353,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CPP="${ac_tool_prefix}cpp"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17302,7 +20393,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CPP="cpp"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17354,7 +20445,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LD="${ac_tool_prefix}ld"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17394,7 +20485,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LD="ld"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17446,7 +20537,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NM="${ac_tool_prefix}nm"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17486,7 +20577,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NM="nm"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17538,7 +20629,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="${ac_tool_prefix}ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17578,7 +20669,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="ar"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17630,7 +20721,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AS="${ac_tool_prefix}as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17670,7 +20761,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AS="as"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17722,7 +20813,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17762,7 +20853,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17814,7 +20905,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17854,7 +20945,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17906,7 +20997,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17946,7 +21037,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -17998,7 +21089,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -18038,7 +21129,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -18077,6 +21168,7 @@ fi
 #
 FC=no
 export FC
+#
 #  ----------------------------------------------------------------------
 # Check large file support on 32 bit system
 # Check whether --enable-largefile was given.
@@ -18275,6 +21367,8 @@ _ACEOF
 esac
 rm -rf conftest*
   fi
+
+
 fi
 
 #  ----------------------------------------------------------------------
@@ -18697,6 +21791,12 @@ case "$CC" in
   *)      C_VERSION=`$CC -V 2>&1   | head -n 1 | grep -v error`;;
 esac
 
+case "$F77" in
+  pgf*)      F77_VERSION=`$F77 -V | head -2 | tail -n 1`;;
+  gfortran*) F77_VERSION=`$F77 --version | head -n 1`;;
+  *)         F77_VERSION=`$F77 -V 2>&1   | head -n 1 | grep -v error`;;
+esac
+
 if test -z "$CXX_VERSION" ; then CXX_VERSION="unknown"; fi;
 
 cat >>confdefs.h <<_ACEOF
@@ -18711,6 +21811,13 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+if test -z "$F77_VERSION" ; then F77_VERSION="unknown"; fi;
+
+cat >>confdefs.h <<_ACEOF
+#define F77_VERSION "$F77_VERSION"
+_ACEOF
+
+
 # Checks for username, hostname and system type
 USERNAME=$LOGNAME
 if test -z "$USERNAME" ; then USERNAME=$USER; fi;
@@ -18728,143 +21835,524 @@ if test -z "$HOST"; then :
        if test -x /bin/hostname; then :
   HOST=$(hostname)
 else
-  if test -x /bin/uname; then :
-  HOST=$(uname -n)
-fi
+  if test -x /bin/uname; then :
+  HOST=$(uname -n)
+fi
+fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HOST_NAME "$HOST"
+_ACEOF
+
+HOST_NAME="$HOST"
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SYSTEM_TYPE "$ac_cv_build"
+_ACEOF
+
+SYSTEM_TYPE="$ac_cv_build"
+
+#  ----------------------------------------------------------------------
+#  Check for math library
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for floor in -lm" >&5
+$as_echo_n "checking for floor in -lm... " >&6; }
+if ${ac_cv_lib_m_floor+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char floor ();
+int
+main ()
+{
+return floor ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_floor=yes
+else
+  ac_cv_lib_m_floor=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floor" >&5
+$as_echo "$ac_cv_lib_m_floor" >&6; }
+if test "x$ac_cv_lib_m_floor" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+#  ----------------------------------------------------------------------
+# Checks for the availability of ANSI-C99 math functions
+ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "$ac_includes_default
+#include <math.h>
+"
+if test "x$ac_cv_have_decl_isnan" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_ISNAN $ac_have_decl
+_ACEOF
+
+for ac_func in sqrtl
+do :
+  ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl"
+if test "x$ac_cv_func_sqrtl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SQRTL 1
+_ACEOF
+
+fi
+done
+
+for ac_func in feenableexcept
+do :
+  ac_fn_c_check_func "$LINENO" "feenableexcept" "ac_cv_func_feenableexcept"
+if test "x$ac_cv_func_feenableexcept" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_FEENABLEEXCEPT 1
+_ACEOF
+
+fi
+done
+
+#
+ac_fn_c_check_member "$LINENO" "fenv_t" "__control" "ac_cv_member_fenv_t___control" "#include <fenv.h>
+"
+if test "x$ac_cv_member_fenv_t___control" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_T___CONTROL 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "fenv_t" "__mxcsr" "ac_cv_member_fenv_t___mxcsr" "#include <fenv.h>
+"
+if test "x$ac_cv_member_fenv_t___mxcsr" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_T___MXCSR 1
+_ACEOF
+
+
+fi
+
+
+#  ----------------------------------------------------------------------
+#  Create the Interface to Fortran77 routines via cfortran.h
+# Check whether --enable-fortran was given.
+if test "${enable_fortran+set}" = set; then :
+  enableval=$enable_fortran; enable_fortran=${enableval}
+else
+  enable_fortran=yes
+fi
+
+if test "x${enable_fortran}" = "xyes"; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking C preprocessor flags for Fortran calling convention cfortran.h" >&5
+$as_echo_n "checking C preprocessor flags for Fortran calling convention cfortran.h... " >&6; }
+if ${acx_cv_cf_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  acx_cv_cf_flag=''
+      for macro in pgiFortran NAGf90Fortran f2cFortran hpuxFortran apolloFortran sunFortran IBMR2Fortran CRAYFortran PATHSCALE_COMPILER gFortran mipsFortran DECFortran vmsFortran CONVEXFortran PowerStationFortran AbsoftUNIXFortran AbsoftProFortran SXFortran
+do :
+  acx_temp=`echo "$CPPFLAGS $CFLAGS" | sed -n 's/^\(.* \)*-D\('"$macro"'\)\( .*\)*$/\2/;t print
+b
+: print
+p'`
+         if test x"$acx_temp" != x; then :
+  if test x"$acx_cv_cf_flag" = x; then :
+  acx_cv_cf_flag="$acx_temp (user-specified)"
+else
+  echo ; echo '"'"$acx_cv_cf_flag $acx_temp"'"'
+               as_fn_error $? "Multiple specification of cfortran.h flags" "$LINENO" 5
+fi
+fi
+done
+      if test x"$acx_cv_cf_flag" = x; then :
+
+         if test -n "$F77" -a X"$F77" != Xno; then :
+  ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+
+
+
+   save_F77=$F77 ; acx_FC=$F77
+   case $host in #(
+  x86_64-*-linux-*|i*86-*-linux-*|*-apple-darwin*|ia64-*-linux-*|x86_64-*-freebsd*|i*86-*-freebsd*) :
+    acx_temp=`$acx_FC -V 2>&1`
+      if echo "$acx_temp" | grep '^Copyright.*\(The Portland Group\|NVIDIA CORPORATION\)' >/dev/null; then :
+  acx_cv_f77_cf_flag=-DgFortran
+elif echo "$acx_temp" | grep '^NAG Fortran Compiler Release' >/dev/null; then :
+  acx_cv_f77_cf_flag=-DNAGf90Fortran
+elif echo "$acx_temp" | grep '^Intel(R) Fortran.*Compiler' >/dev/null; then :
+  acx_cv_f77_cf_flag=-DgFortran
+elif echo "$acx_temp" | grep '^Cray Fortran' >/dev/null; then :
+  acx_cv_f77_cf_flag=-DgFortran
+elif acx_temp=`$acx_FC --version 2>&1` \
+         && echo $acx_temp | grep '^GNU Fortran' >/dev/null; then :
+  if echo $acx_temp | grep g77 >/dev/null; then :
+  acx_cv_f77_cf_flag=-Dg77Fortran
+else
+              if echo "$FFLAGS" | grep '^\(.* \)*-ff2c\( .*\)*$' >/dev/null; then :
+  acx_cv_f77_cf_flag=-Df2cFortran
+else
+  acx_cv_f77_cf_flag=-DgFortran
+fi
+fi
+elif acx_temp=`$acx_FC -v 2>&1` \
+         && echo $acx_temp | grep '^f2c'; then :
+  acx_cv_f77_cf_flag=-Df2cFortran
+fi ;; #(
+  *-ibm-aix*) :
+          if $CC -qversion 2>&1 | grep '^IBM XL C' >/dev/null; then :
+
+else
+           acx_cv_f77_cf_flag=-DIBMR2Fortran
+fi
+      ;; #(
+  *-*-hpux*) :
+    acx_cv_f77_cf_flag=-DhpuxFortran ;; #(
+  sx*-*-*|es*-*-*) :
+          acx_cv_f77_cf_flag=-DSXFortran ;; #(
+  *) :
+     ;;
+esac
+
+               ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+         acx_cv_cf_flag="$acx_cv_f77_cf_flag (probed)"
+
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_cf_flag" >&5
+$as_echo "$acx_cv_cf_flag" >&6; }
+   if echo "$acx_cv_cf_flag" | grep ' (probed)$' >/dev/null; then :
+  CPPFLAGS="${CPPFLAGS+$CPPFLAGS }`echo "$acx_cv_cf_flag" | sed 's/ (probed)$//'`"
+fi
+
+case $host in #(
+  *-ibm-aix*) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if -Dappendus needs to be added to CPPFLAGS for cfortran.h" >&5
+$as_echo_n "checking if -Dappendus needs to be added to CPPFLAGS for cfortran.h... " >&6; }
+      if $CC -qversion 2>&1 | grep '^IBM XL C' >/dev/null; then :
+  acx_temp_qextname_f77flags=`echo "$FFLAGS" | sed -n '/-qextname/{ s/^\(.* \)*-qextname\( .*\)*$/-qextname/;p;}'`
+         acx_temp_qextname_fcflags=`echo "$FCFLAGS" | sed -n '/-qextname/{ s/^\(.* \)*-qextname\( .*\)*$/-qextname/;p;}'`
+
+               acx_temp_qextname_fcflags=$acx_temp_qextname_f77flags
+         case x"$acx_temp_qextname_fcflags$acx_temp_qextname_f77flags" in #(
+  x-qextname) :
+    as_fn_error $? "Option -qextname must be provided consistently to F77 and FC" "$LINENO" 5 ;; #(
+  x-qextname-qextname) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+            CPPFLAGS="${CPPFLAGS+$CPPFLAGS }-Dappendus" ;; #(
+  *) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; } ;;
+esac
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi ;; #(
+  *) :
+     ;;
+esac
+if test -n "$F77" -a X"$F77" != Xno; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if C externals constructed with cfortran.h work" >&5
+$as_echo_n "checking if C externals constructed with cfortran.h work... " >&6; }
+if ${acx_cv_cfortran_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  acx_cv_cfortran_works=no
+      save_CPPFLAGS=$CPPFLAGS
+      CPPFLAGS="-I$srcdir/src $CPPFLAGS"
+      ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include "cfortran.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+PROTOCCALLSFFUN1(FLOAT,CFTSTF,cftstf,FLOAT)
+#define conftest_F(v) \
+  CCALLSFFUN1(CFTSTF,cftstf,FLOAT,(v));
+
+static float
+cftstC(int i, float v, int *p, float *q)
+{
+  float f;
+  *p = (int)roundf(v * i);
+  *q = f = conftest_F(v * i);
+  return f;
+}
+
+FCALLSCFUN4(FLOAT,cftstC,CFTSTC,cftstc,INT,FLOAT,PINT,PFLOAT)
+
+/* test string returns */
+static const char *
+conftest_str_C(void)
+{
+  static const char msg[100] = "AAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+  return msg;
+}
+
+FCALLSCFUN0(STRING,conftest_str_C,CHTST,chtst)
+
+/* This function is required simply because some Fortran compilers
+ * won't stop with exit code n when encountering STOP n */
+static void
+errExit(void)
+{
+  exit(1);
+}
+
+FCALLSCSUB0(errExit,ERR_EXIT,err_exit)
+
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: Renaming C object file." >&5; } >&5
+  (mv "conftest.$ac_objext" "conftest_c.$ac_objext") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+
+         ac_ext=f
+ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
+ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_f77_compiler_gnu
+
+         cat > conftest.$ac_ext <<_ACEOF
+      REAL FUNCTION CFTSTF(v)
+      REAL RI
+      COMMON /CFTSTD/ RI
+      REAL V
+      REAL R
+      CFTSTF = V * 100.0
+      RI = 1.0 / V
+      END FUNCTION CFTSTF
+_ACEOF
+if ac_fn_f77_try_compile "$LINENO"; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: Renaming Fortran object file." >&5; } >&5
+  (mv "conftest.$ac_objext" "conftest_f.$ac_objext") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+            save_LIBS=$LIBS
+            LIBS="conftest_c.$ac_objext conftest_f.$ac_objext $LIBS"
+            if test "$cross_compiling" = yes; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: Skipping run test for cfortran.h in cross-compilation mode," >&5
+$as_echo "$as_me: Skipping run test for cfortran.h in cross-compilation mode," >&6;}
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: link test succeeded." >&5
+$as_echo "$as_me: link test succeeded." >&6;}
+               acx_cv_cfortran_works=yes
+else
+  cat > conftest.$ac_ext <<_ACEOF
+      program main
+      REAL RI
+      COMMON /CFTSTD/ RI
+      REAL EPS
+      PARAMETER(EPS=10E-6)
+      REAL FOO, BOO, TOO
+      INTEGER BAR, BAZ, I
+      CHARACTER(99) AAAAAA
+      EXTERNAL CFTSTC, CFTSTF, CHTST, ERR_EXIT
+      REAL CFTSTC, CFTSTF
+      CHARACTER(99) CHTST
+      BAR = 5
+      FOO = 0.3
+      TOO = CFTSTC(BAR, FOO, BAZ, BOO)
+      IF (ABS(BAZ - NINT(BAR * FOO)) /= 0) THEN
+        WRITE (0, '(2(A,I0))') "ERROR CHECKING, WHEN BAZ, BAZ=", BAZ,
+     &       ", NINT(BAR * FOO) =", NINT(BAR * FOO)
+        CALL ERR_EXIT
+      END IF
+      IF (ABS((RI - 1.0 / (BAR * FOO)) / ABS(RI)) > EPS)  THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING RI, RI=", RI, ",
+     &       1.0 / (BAR * FOO) = ", 1.0 / (BAR * FOO)
+        CALL err_exit
+      END IF
+      IF (ABS((BOO - (BAR * FOO * 100.0))/ABS(BOO)) > EPS)  THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING BOO, BOO=", BOO,
+     &       ", BAR * FOO * 100.0 = ", BAR * FOO * 100.0
+        CALL ERR_EXIT
+      END IF
+      IF (TOO /= BOO) THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING TOO VS. BOO, TOO=",
+     &       TOO, ", BOO = ", BOO
+        CALL ERR_EXIT
+      END IF
+      AAAAAA = CHTST()
+      DO i = 1, 99
+        IF (AAAAAA(I:I) /= 'A') THEN
+          WRITE (0, '(A,I0,2A)') "ERROR CHECKING AAAAAA(", I, ")=",
+     &        AAAAAA(I:I)
+          CALL ERR_EXIT
+        END IF
+      END DO
+      end
+_ACEOF
+if ac_fn_f77_try_run "$LINENO"; then :
+  acx_cv_cfortran_works=yes
+else
+  acx_cv_cfortran_works="error"
 fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-cat >>confdefs.h <<_ACEOF
-#define HOST_NAME "$HOST"
-_ACEOF
+	    LIBS=$save_LIBS
+else
+  acx_cv_cfortran_works="error compiling Fortran subroutine"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+         ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
-HOST_NAME="$HOST"
 
+else
+  acx_cv_cfortran_works="compiling with cfortran.h failed"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
+      CPPFLAGS=$save_CPPFLAGS
 
-cat >>confdefs.h <<_ACEOF
-#define SYSTEM_TYPE "$ac_cv_build"
-_ACEOF
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_cfortran_works" >&5
+$as_echo "$acx_cv_cfortran_works" >&6; }
+   if test x"$acx_cv_cfortran_works" = xyes; then :
 
-SYSTEM_TYPE="$ac_cv_build"
+$as_echo "#define HAVE_CF_INTERFACE 1" >>confdefs.h
 
-#  ----------------------------------------------------------------------
-#  Check for math library
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for floor in -lm" >&5
-$as_echo_n "checking for floor in -lm... " >&6; }
-if ${ac_cv_lib_m_floor+:} false; then :
-  $as_echo_n "(cached) " >&6
 else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lm  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+  case x"$acx_cv_cfortran_works" in #(
+  x"error") :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Linking/Running with C EXTERNAL built with cfortran.h does not work!" >&5
+$as_echo "$as_me: Linking/Running with C EXTERNAL built with cfortran.h does not work!" >&6;} ;; #(
+  x"compiling with cfortran.h failed") :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Compilation with cfortran.h is not working!" >&5
+$as_echo "$as_me: Compilation with cfortran.h is not working!" >&6;} ;; #(
+  x"error compiling Fortran subroutine") :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: compilation of simple Fortran source failed!" >&5
+$as_echo "$as_me: compilation of simple Fortran source failed!" >&6;} ;; #(
+  *) :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Unexpected error when linking C and Fortran via cfortran.h!" >&5
+$as_echo "$as_me: Unexpected error when linking C and Fortran via cfortran.h!" >&6;} ;;
+esac
+     { $as_echo "$as_me:${as_lineno-$LINENO}: Disabling cfortran.h bindings generation" >&5
+$as_echo "$as_me: Disabling cfortran.h bindings generation" >&6;}
+     acx_cv_cfortran_works=no
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char floor ();
-int
-main ()
-{
-return floor ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_floor=yes
-else
-  ac_cv_lib_m_floor=no
 fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
+
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floor" >&5
-$as_echo "$ac_cv_lib_m_floor" >&6; }
-if test "x$ac_cv_lib_m_floor" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBM 1
-_ACEOF
+if test x$enable_fortran = 'xno'; then :
+  ENABLE_FORTRAN=false
 
-  LIBS="-lm $LIBS"
+else
+  ENABLE_FORTRAN=true
 
 fi
-
-#  ----------------------------------------------------------------------
-# Checks for the availability of ANSI-C99 math functions
-ac_fn_c_check_decl "$LINENO" "isnan" "ac_cv_have_decl_isnan" "$ac_includes_default
-#include <math.h>
-"
-if test "x$ac_cv_have_decl_isnan" = xyes; then :
-  ac_have_decl=1
+#
+ if test -n "$F77" -a X"$F77" != Xno -a x"$acx_cv_cfortran_works" = xyes; then
+  USE_F77_TRUE=
+  USE_F77_FALSE='#'
 else
-  ac_have_decl=0
+  USE_F77_TRUE='#'
+  USE_F77_FALSE=
 fi
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_ISNAN $ac_have_decl
-_ACEOF
+if test x$acx_cv_cfortran_works = 'xno'; then :
+  FORTRAN_WORKS=no
 
-for ac_func in sqrtl
-do :
-  ac_fn_c_check_func "$LINENO" "sqrtl" "ac_cv_func_sqrtl"
-if test "x$ac_cv_func_sqrtl" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_SQRTL 1
-_ACEOF
+else
+  FORTRAN_WORKS=yes
 
 fi
-done
-
-for ac_func in feenableexcept
-do :
-  ac_fn_c_check_func "$LINENO" "feenableexcept" "ac_cv_func_feenableexcept"
-if test "x$ac_cv_func_feenableexcept" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_FEENABLEEXCEPT 1
-_ACEOF
+#  ----------------------------------------------------------------------
 
+#  ----------------------------------------------------------------------
+#  Enable NEARPT3 support
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nearpt3 support" >&5
+$as_echo_n "checking for nearpt3 support... " >&6; }
+# Check whether --enable-nearpt3 was given.
+if test "${enable_nearpt3+set}" = set; then :
+  enableval=$enable_nearpt3;
 fi
-done
-
-#
-ac_fn_c_check_member "$LINENO" "fenv_t" "__control" "ac_cv_member_fenv_t___control" "#include <fenv.h>
-"
-if test "x$ac_cv_member_fenv_t___control" = xyes; then :
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FENV_T___CONTROL 1
-_ACEOF
+if test "x$enable_nearpt3" = "xyes"; then :
 
 
-fi
-ac_fn_c_check_member "$LINENO" "fenv_t" "__mxcsr" "ac_cv_member_fenv_t___mxcsr" "#include <fenv.h>
-"
-if test "x$ac_cv_member_fenv_t___mxcsr" = xyes; then :
+$as_echo "#define ENABLE_NEARPT3 1" >>confdefs.h
 
-cat >>confdefs.h <<_ACEOF
-#define HAVE_FENV_T___MXCSR 1
-_ACEOF
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_nearpt3" >&5
+$as_echo "$enable_nearpt3" >&6; }
+ENABLE_NEARPT3=$enable_nearpt3
 
+ if test x$enable_nearpt3 = 'xyes'; then
+  ENABLE_NEARPT3_TRUE=
+  ENABLE_NEARPT3_FALSE='#'
+else
+  ENABLE_NEARPT3_TRUE='#'
+  ENABLE_NEARPT3_FALSE=
 fi
 
 #  ----------------------------------------------------------------------
-#  Enable NEARPT3 support
-# AC_MSG_CHECKING([for nearpt3 support])
-# AC_ARG_ENABLE([nearpt3], AS_HELP_STRING([--enable-nearpt3],[nearpt3 support [default=no]]))
-# AS_IF([test "x$enable_nearpt3" = "xyes"], [
-#   AC_DEFINE(ENABLE_NEARPT3, [1], [Define to 1 for nearpt3 support])
-# ])
-# AC_MSG_RESULT([$enable_nearpt3])
-# AC_SUBST([ENABLE_NEARPT3],[$enable_nearpt3])
-# AM_CONDITIONAL([ENABLE_NEARPT3],[test x$enable_nearpt3 = 'xyes'])
-#  ----------------------------------------------------------------------
 #  Enable DATA support
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DATA support" >&5
 $as_echo_n "checking for DATA support... " >&6; }
@@ -18882,8 +22370,13 @@ $as_echo "#define ENABLE_DATA 1" >>confdefs.h
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_data" >&5
 $as_echo "$enable_data" >&6; }
-ENABLE_DATA=$enable_data
+if test x$enable_data = 'xno'; then :
+  ENABLE_DATA=false
+
+else
+  ENABLE_DATA=true
 
+fi
 #  ----------------------------------------------------------------------
 CFLAGS="$CFLAGS ${OPENMP_CFLAGS}"
 CXXFLAGS="$CXXFLAGS ${OPENMP_CFLAGS}"
@@ -19084,7 +22577,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ax_pthread_config="yes"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -19276,7 +22769,7 @@ fi
     #handle absolute path differently from PATH based program lookup
                    case "x$CC" in #(
   x/*) :
-    if { test -f ${CC}_r && $as_test_x ${CC}_r; }; then :
+    if as_fn_executable_p ${CC}_r; then :
   PTHREAD_CC="${CC}_r"
 fi ;; #(
   *) :
@@ -19298,7 +22791,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_PTHREAD_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -20035,7 +23528,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NC_CONFIG="nc-config"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -20209,7 +23702,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NC_CONFIG="$NETCDF_ROOT/bin/nc-config"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -22163,8 +25656,6 @@ fi
 #
 
 
-#  ----------------------------------------------------------------------
-
 # configure code from valgrind
 
 # does the x86/amd64 assembler understand SSE 4.2 instructions?
@@ -22338,6 +25829,12 @@ cat >>confdefs.h <<_ACEOF
 #define CXX_COMPILER "$CXX_COMPILER"
 _ACEOF
 
+F77_COMPILER="$F77 $FFLAGS"
+
+cat >>confdefs.h <<_ACEOF
+#define F77_COMPILER "$F77_COMPILER"
+_ACEOF
+
 
 
 for ac_prog in gawk mawk nawk awk
@@ -22358,7 +25855,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -22403,7 +25900,7 @@ ac_config_files="$ac_config_files test/Gradsdes.test test/Collgrid.test test/thr
 
 ac_config_files="$ac_config_files test/MapReduce.test test/Ninfo.test"
 
-ac_config_files="$ac_config_files Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings"
+ac_config_files="$ac_config_files Makefile src/lib/ncl/Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -22546,6 +26043,14 @@ if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
   as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${USE_F77_TRUE}" && test -z "${USE_F77_FALSE}"; then
+  as_fn_error $? "conditional \"USE_F77\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_NEARPT3_TRUE}" && test -z "${ENABLE_NEARPT3_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_NEARPT3\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${ENABLE_MAGICS_TRUE}" && test -z "${ENABLE_MAGICS_FALSE}"; then
   as_fn_error $? "conditional \"ENABLE_MAGICS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -22872,16 +26377,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -22941,28 +26446,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -22983,8 +26476,8 @@ 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 cdo $as_me 1.9.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+This file was extended by cdo $as_me 1.9.2rc1, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -23049,11 +26542,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdo config.status 1.9.1
-configured by $0, generated by GNU Autoconf 2.68,
+cdo config.status 1.9.2rc1
+configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -23144,7 +26637,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
@@ -23315,53 +26808,101 @@ predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
 postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
 compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
 LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+LD_F77='`$ECHO "$LD_F77" | $SED "$delay_single_quote_subst"`'
 reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_F77='`$ECHO "$reload_flag_F77" | $SED "$delay_single_quote_subst"`'
 reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_F77='`$ECHO "$reload_cmds_F77" | $SED "$delay_single_quote_subst"`'
 old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_F77='`$ECHO "$old_archive_cmds_F77" | $SED "$delay_single_quote_subst"`'
 compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_F77='`$ECHO "$compiler_F77" | $SED "$delay_single_quote_subst"`'
 GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_F77='`$ECHO "$GCC_F77" | $SED "$delay_single_quote_subst"`'
 lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_F77='`$ECHO "$lt_prog_compiler_no_builtin_flag_F77" | $SED "$delay_single_quote_subst"`'
 lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_F77='`$ECHO "$lt_prog_compiler_pic_F77" | $SED "$delay_single_quote_subst"`'
 lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_F77='`$ECHO "$lt_prog_compiler_wl_F77" | $SED "$delay_single_quote_subst"`'
 lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_F77='`$ECHO "$lt_prog_compiler_static_F77" | $SED "$delay_single_quote_subst"`'
 lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_F77='`$ECHO "$lt_cv_prog_compiler_c_o_F77" | $SED "$delay_single_quote_subst"`'
 archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_F77='`$ECHO "$archive_cmds_need_lc_F77" | $SED "$delay_single_quote_subst"`'
 enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_F77='`$ECHO "$enable_shared_with_static_runtimes_F77" | $SED "$delay_single_quote_subst"`'
 export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_F77='`$ECHO "$export_dynamic_flag_spec_F77" | $SED "$delay_single_quote_subst"`'
 whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_F77='`$ECHO "$whole_archive_flag_spec_F77" | $SED "$delay_single_quote_subst"`'
 compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_F77='`$ECHO "$compiler_needs_object_F77" | $SED "$delay_single_quote_subst"`'
 old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_F77='`$ECHO "$old_archive_from_new_cmds_F77" | $SED "$delay_single_quote_subst"`'
 old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_F77='`$ECHO "$old_archive_from_expsyms_cmds_F77" | $SED "$delay_single_quote_subst"`'
 archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_F77='`$ECHO "$archive_cmds_F77" | $SED "$delay_single_quote_subst"`'
 archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_F77='`$ECHO "$archive_expsym_cmds_F77" | $SED "$delay_single_quote_subst"`'
 module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_F77='`$ECHO "$module_cmds_F77" | $SED "$delay_single_quote_subst"`'
 module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_F77='`$ECHO "$module_expsym_cmds_F77" | $SED "$delay_single_quote_subst"`'
 with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_F77='`$ECHO "$with_gnu_ld_F77" | $SED "$delay_single_quote_subst"`'
 allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_F77='`$ECHO "$allow_undefined_flag_F77" | $SED "$delay_single_quote_subst"`'
 no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_F77='`$ECHO "$no_undefined_flag_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_F77='`$ECHO "$hardcode_libdir_flag_spec_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_F77='`$ECHO "$hardcode_libdir_separator_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_F77='`$ECHO "$hardcode_direct_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_F77='`$ECHO "$hardcode_direct_absolute_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_F77='`$ECHO "$hardcode_minus_L_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_F77='`$ECHO "$hardcode_shlibpath_var_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_F77='`$ECHO "$hardcode_automatic_F77" | $SED "$delay_single_quote_subst"`'
 inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_F77='`$ECHO "$inherit_rpath_F77" | $SED "$delay_single_quote_subst"`'
 link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_F77='`$ECHO "$link_all_deplibs_F77" | $SED "$delay_single_quote_subst"`'
 always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_F77='`$ECHO "$always_export_symbols_F77" | $SED "$delay_single_quote_subst"`'
 export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_F77='`$ECHO "$export_symbols_cmds_F77" | $SED "$delay_single_quote_subst"`'
 exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_F77='`$ECHO "$exclude_expsyms_F77" | $SED "$delay_single_quote_subst"`'
 include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_F77='`$ECHO "$include_expsyms_F77" | $SED "$delay_single_quote_subst"`'
 prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_F77='`$ECHO "$prelink_cmds_F77" | $SED "$delay_single_quote_subst"`'
 postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+postlink_cmds_F77='`$ECHO "$postlink_cmds_F77" | $SED "$delay_single_quote_subst"`'
 file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_F77='`$ECHO "$file_list_spec_F77" | $SED "$delay_single_quote_subst"`'
 hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_F77='`$ECHO "$hardcode_action_F77" | $SED "$delay_single_quote_subst"`'
 compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_F77='`$ECHO "$compiler_lib_search_dirs_F77" | $SED "$delay_single_quote_subst"`'
 predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_F77='`$ECHO "$predep_objects_F77" | $SED "$delay_single_quote_subst"`'
 postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_F77='`$ECHO "$postdep_objects_F77" | $SED "$delay_single_quote_subst"`'
 predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_F77='`$ECHO "$predeps_F77" | $SED "$delay_single_quote_subst"`'
 postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_F77='`$ECHO "$postdeps_F77" | $SED "$delay_single_quote_subst"`'
 compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_F77='`$ECHO "$compiler_lib_search_path_F77" | $SED "$delay_single_quote_subst"`'
 
 LTCC='$LTCC'
 LTCFLAGS='$LTCFLAGS'
@@ -23448,30 +26989,55 @@ predeps \
 postdeps \
 compiler_lib_search_path \
 LD_CXX \
+LD_F77 \
 reload_flag_CXX \
+reload_flag_F77 \
 compiler_CXX \
+compiler_F77 \
 lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_no_builtin_flag_F77 \
 lt_prog_compiler_pic_CXX \
+lt_prog_compiler_pic_F77 \
 lt_prog_compiler_wl_CXX \
+lt_prog_compiler_wl_F77 \
 lt_prog_compiler_static_CXX \
+lt_prog_compiler_static_F77 \
 lt_cv_prog_compiler_c_o_CXX \
+lt_cv_prog_compiler_c_o_F77 \
 export_dynamic_flag_spec_CXX \
+export_dynamic_flag_spec_F77 \
 whole_archive_flag_spec_CXX \
+whole_archive_flag_spec_F77 \
 compiler_needs_object_CXX \
+compiler_needs_object_F77 \
 with_gnu_ld_CXX \
+with_gnu_ld_F77 \
 allow_undefined_flag_CXX \
+allow_undefined_flag_F77 \
 no_undefined_flag_CXX \
+no_undefined_flag_F77 \
 hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_flag_spec_F77 \
 hardcode_libdir_separator_CXX \
+hardcode_libdir_separator_F77 \
 exclude_expsyms_CXX \
+exclude_expsyms_F77 \
 include_expsyms_CXX \
+include_expsyms_F77 \
 file_list_spec_CXX \
+file_list_spec_F77 \
 compiler_lib_search_dirs_CXX \
+compiler_lib_search_dirs_F77 \
 predep_objects_CXX \
+predep_objects_F77 \
 postdep_objects_CXX \
+postdep_objects_F77 \
 predeps_CXX \
+predeps_F77 \
 postdeps_CXX \
-compiler_lib_search_path_CXX; do
+postdeps_F77 \
+compiler_lib_search_path_CXX \
+compiler_lib_search_path_F77; do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
       eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
@@ -23503,16 +27069,27 @@ finish_cmds \
 sys_lib_search_path_spec \
 sys_lib_dlsearch_path_spec \
 reload_cmds_CXX \
+reload_cmds_F77 \
 old_archive_cmds_CXX \
+old_archive_cmds_F77 \
 old_archive_from_new_cmds_CXX \
+old_archive_from_new_cmds_F77 \
 old_archive_from_expsyms_cmds_CXX \
+old_archive_from_expsyms_cmds_F77 \
 archive_cmds_CXX \
+archive_cmds_F77 \
 archive_expsym_cmds_CXX \
+archive_expsym_cmds_F77 \
 module_cmds_CXX \
+module_cmds_F77 \
 module_expsym_cmds_CXX \
+module_expsym_cmds_F77 \
 export_symbols_cmds_CXX \
+export_symbols_cmds_F77 \
 prelink_cmds_CXX \
-postlink_cmds_CXX; do
+prelink_cmds_F77 \
+postlink_cmds_CXX \
+postlink_cmds_F77; do
     case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
     *[\\\\\\\`\\"\\\$]*)
       eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
@@ -23545,6 +27122,8 @@ fi
 
 
 
+
+
 _ACEOF
 
 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
@@ -23600,6 +27179,7 @@ do
     "test/MapReduce.test") CONFIG_FILES="$CONFIG_FILES test/MapReduce.test" ;;
     "test/Ninfo.test") CONFIG_FILES="$CONFIG_FILES test/Ninfo.test" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "src/lib/ncl/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/ncl/Makefile" ;;
     "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
     "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
     "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
@@ -24344,7 +27924,7 @@ $as_echo X"$file" |
 
 
 # The names of the tagged configurations supported by this script.
-available_tags="CXX "
+available_tags="CXX F77 "
 
 # ### BEGIN LIBTOOL CONFIG
 
@@ -25090,6 +28670,159 @@ compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
 # ### END LIBTOOL TAG CONFIG: CXX
 _LT_EOF
 
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: F77
+
+# The linker used to build libraries.
+LD=$lt_LD_F77
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_F77
+reload_cmds=$lt_reload_cmds_F77
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_F77
+
+# A language specific compiler.
+CC=$lt_compiler_F77
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_F77
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_F77
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_F77
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_F77
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_F77
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_F77
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_F77
+archive_expsym_cmds=$lt_archive_expsym_cmds_F77
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_F77
+module_expsym_cmds=$lt_module_expsym_cmds_F77
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_F77
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_F77
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_F77
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_F77
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_F77
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_F77
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_F77
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_F77
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_F77
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_F77
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_F77
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_F77
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_F77
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_F77
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_F77
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_F77
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_F77
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_F77
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_F77
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_F77
+postdep_objects=$lt_postdep_objects_F77
+predeps=$lt_predeps_F77
+postdeps=$lt_postdeps_F77
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_F77
+
+# ### END LIBTOOL TAG CONFIG: F77
+_LT_EOF
+
  ;;
     "test/File.test":F) chmod a+x "$ac_file" ;;
     "test/Read_grib.test":F) chmod a+x "$ac_file" ;;
diff --git a/configure.ac b/configure.ac
index 0e21606..c5bcd2f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdo], [1.9.1], [http://mpimet.mpg.de/cdo])
+AC_INIT([cdo], [1.9.2rc1], [http://mpimet.mpg.de/cdo])
 
 AC_DEFINE_UNQUOTED(CDO, ["$PACKAGE_VERSION"], [CDO version])
 
@@ -34,6 +34,7 @@ AC_CHECK_TOOL([CXX],[g++],[:])
 AC_PROG_CC_C99
 AM_PROG_CC_C_O
 AC_PROG_CXX
+AC_PROG_F77
 AC_C_RESTRICT
 AX_CXX_COMPILE_STDCXX_11
 AC_OPENMP
@@ -51,6 +52,7 @@ AC_PROG_INSTALL
 #
 FC=no
 export FC
+#
 #  ----------------------------------------------------------------------
 # Check large file support on 32 bit system
 AC_SYS_LARGEFILE
@@ -104,12 +106,21 @@ case "$CC" in
   *)      C_VERSION=`$CC -V 2>&1   | head -n 1 | grep -v error`;;
 esac
 
+case "$F77" in
+  pgf*)      F77_VERSION=`$F77 -V | head -2 | tail -n 1`;;
+  gfortran*) F77_VERSION=`$F77 --version | head -n 1`;;
+  *)         F77_VERSION=`$F77 -V 2>&1   | head -n 1 | grep -v error`;;
+esac
+
 if test -z "$CXX_VERSION" ; then CXX_VERSION="unknown"; fi;
 AC_DEFINE_UNQUOTED(CXX_VERSION, ["$CXX_VERSION"], [CXX Compiler version])
 
 if test -z "$C_VERSION" ; then C_VERSION="unknown"; fi;
 AC_DEFINE_UNQUOTED(C_VERSION, ["$C_VERSION"], [C Compiler version])
 
+if test -z "$F77_VERSION" ; then F77_VERSION="unknown"; fi;
+AC_DEFINE_UNQUOTED(F77_VERSION, ["$F77_VERSION"], [F77 Compiler version])
+
 # Checks for username, hostname and system type
 USERNAME=$LOGNAME
 if test -z "$USERNAME" ; then USERNAME=$USER; fi;
@@ -138,16 +149,50 @@ AC_CHECK_FUNCS(sqrtl)
 AC_CHECK_FUNCS(feenableexcept)
 #
 AC_CHECK_MEMBERS([fenv_t.__control, fenv_t.__mxcsr],,,[[#include <fenv.h>]])
+
+#  ----------------------------------------------------------------------
+#  Create the Interface to Fortran77 routines via cfortran.h
+AC_ARG_ENABLE([fortran],
+              [AS_HELP_STRING([--disable-fortran],
+                              [Omit building of Fortran routines])],
+              [enable_fortran=${enableval}],[enable_fortran=yes])
+AS_IF([test "x${enable_fortran}" = "xyes"], [
+dnl ######################################################################
+dnl Test whether cfortran.h works correctly
+dnl ######################################################################
+ACX_FIND_CFORTRAN_DEF
+ACX_XLF_QEXTNAME_ADD_APPENDUS
+AS_IF([test -n "$F77" -a X"$F77" != Xno],
+  [ACX_CHECK_CFORTRAN([$srcdir/src],
+    [AC_DEFINE([HAVE_CF_INTERFACE],[1],
+       [Defined to 1 if C / Fortran interface cfortran.h works])],
+    [AS_CASE([x"$acx_cv_cfortran_works"],
+       [x"error"],
+       [AC_MSG_NOTICE([Linking/Running with C EXTERNAL built with cfortran.h does not work!])],
+       [x"compiling with cfortran.h failed"],
+       [AC_MSG_NOTICE([Compilation with cfortran.h is not working!])],
+       [x"error compiling Fortran subroutine"],
+       [AC_MSG_NOTICE([compilation of simple Fortran source failed!])],
+       [AC_MSG_NOTICE([Unexpected error when linking C and Fortran via cfortran.h!])])
+     AC_MSG_NOTICE([Disabling cfortran.h bindings generation])
+     acx_cv_cfortran_works=no])])
+])
+AS_IF([test x$enable_fortran = 'xno'],[AC_SUBST([ENABLE_FORTRAN],[false])],[AC_SUBST([ENABLE_FORTRAN],[true])])
+#
+AM_CONDITIONAL([USE_F77],[test -n "$F77" -a X"$F77" != Xno -a x"$acx_cv_cfortran_works" = xyes])
+AS_IF([test x$acx_cv_cfortran_works = 'xno'],[AC_SUBST([FORTRAN_WORKS],[no])],[AC_SUBST([FORTRAN_WORKS],[yes])])
+#  ----------------------------------------------------------------------
+
 #  ----------------------------------------------------------------------
 #  Enable NEARPT3 support
-# AC_MSG_CHECKING([for nearpt3 support])
-# AC_ARG_ENABLE([nearpt3], AS_HELP_STRING([--enable-nearpt3],[nearpt3 support [default=no]]))
-# AS_IF([test "x$enable_nearpt3" = "xyes"], [
-#   AC_DEFINE(ENABLE_NEARPT3, [1], [Define to 1 for nearpt3 support])
-# ])
-# AC_MSG_RESULT([$enable_nearpt3])
-# AC_SUBST([ENABLE_NEARPT3],[$enable_nearpt3])
-# AM_CONDITIONAL([ENABLE_NEARPT3],[test x$enable_nearpt3 = 'xyes'])
+AC_MSG_CHECKING([for nearpt3 support])
+AC_ARG_ENABLE([nearpt3], AS_HELP_STRING([--enable-nearpt3],[nearpt3 support [default=no]]))
+AS_IF([test "x$enable_nearpt3" = "xyes"], [
+  AC_DEFINE(ENABLE_NEARPT3, [1], [Define to 1 for nearpt3 support])
+])
+AC_MSG_RESULT([$enable_nearpt3])
+AC_SUBST([ENABLE_NEARPT3],[$enable_nearpt3])
+AM_CONDITIONAL([ENABLE_NEARPT3],[test x$enable_nearpt3 = 'xyes'])
 #  ----------------------------------------------------------------------
 #  Enable DATA support
 AC_MSG_CHECKING([for DATA support])
@@ -156,7 +201,7 @@ AS_IF([test "x$enable_data" != 'xno'], [
   AC_DEFINE(ENABLE_DATA, [1], [Define to 1 for DATA support])
 ])
 AC_MSG_RESULT([$enable_data])
-AC_SUBST([ENABLE_DATA],[$enable_data])
+AS_IF([test x$enable_data = 'xno'],[AC_SUBST([ENABLE_DATA],[false])],[AC_SUBST([ENABLE_DATA],[true])])
 #  ----------------------------------------------------------------------
 CFLAGS="$CFLAGS ${OPENMP_CFLAGS}"
 CXXFLAGS="$CXXFLAGS ${OPENMP_CFLAGS}"
@@ -165,8 +210,6 @@ CXXFLAGS="$CXXFLAGS ${OPENMP_CFLAGS}"
 # Add configure options
 ACX_OPTIONS
 
-#  ----------------------------------------------------------------------
-
 # configure code from valgrind
 
 # does the x86/amd64 assembler understand SSE 4.2 instructions?
@@ -242,7 +285,7 @@ AM_CONDITIONAL(BUILD_AVX2_TESTS, test x$ac_have_as_avx2 = xyes)
 #  ----------------------------------------------------------------------
 AC_SUBST([CXXFLAGS])
 AC_SUBST([CPPFLAGS])
-AC_SUBST([FCFLAGS])
+AC_SUBST([FFLAGS])
 AC_SUBST([CLDFLAGS])
 AC_SUBST([CLIBS])
 #AC_SUBST([INCLUDES])
@@ -254,6 +297,8 @@ C_COMPILER="$CC $CFLAGS"
 AC_DEFINE_UNQUOTED(C_COMPILER, ["$C_COMPILER"], [C Compiler])
 CXX_COMPILER="$CXX $CXXFLAGS"
 AC_DEFINE_UNQUOTED(CXX_COMPILER, ["$CXX_COMPILER"], [CXX Compiler])
+F77_COMPILER="$F77 $FFLAGS"
+AC_DEFINE_UNQUOTED(F77_COMPILER, ["$F77_COMPILER"], [F77 Compiler])
 
 AC_REQUIRE_AUX_FILE([tap-driver.sh])
 AC_PROG_AWK
@@ -268,7 +313,7 @@ AC_CONFIG_FILES([test/Merstat.test test/Zonstat.test test/Mergetime.test],[chmod
 AC_CONFIG_FILES([test/Afterburner.test test/Detrend.test test/Arithc.test test/Arith.test test/Expr.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([test/Gradsdes.test test/Collgrid.test test/threads.test test/tsformat.test test/wildcard.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([test/MapReduce.test test/Ninfo.test],[chmod a+x "$ac_file"])
-AC_CONFIG_FILES([Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings])
+AC_CONFIG_FILES([Makefile src/lib/ncl/Makefile src/Makefile contrib/Makefile test/Makefile test/data/Makefile cdo.spec cdo.settings])
 AC_OUTPUT
 
 #  ----------------------------------------------------------------------
diff --git a/contrib/Makefile.in b/contrib/Makefile.in
index a9577ba..e41e590 100644
--- a/contrib/Makefile.in
+++ b/contrib/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,10 +88,10 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = contrib
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs COPYING
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -90,6 +100,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -114,6 +125,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/config/mkinstalldirs COPYING
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -156,18 +169,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -243,6 +260,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -307,7 +325,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign contrib/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -484,6 +501,8 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
 	uninstall-am
 
+.PRECIOUS: Makefile
+
 
 completions:
 	if hash ruby >/dev/null 2>&1 ; then \
diff --git a/contrib/cdoCompletion.bash b/contrib/cdoCompletion.bash
index 4bc3ce8..4ab1698 100644
--- a/contrib/cdoCompletion.bash
+++ b/contrib/cdoCompletion.bash
@@ -8,7 +8,6 @@ complete -W "
 --percentile \
 --precision \
 --reduce_dim \
---remap_genweights \
 --sortname \
 --timestat_date \
 -C, \
@@ -693,7 +692,9 @@ tstepcount -tstepcount \
 unsetgridmask -unsetgridmask \
 usegridnumber -usegridnumber \
 uv2dv -uv2dv \
+uv2dv_cfd -uv2dv_cfd \
 uv2dvl -uv2dvl \
+uv2vr_cfd -uv2vr_cfd \
 uvDestag -uvDestag \
 vardes -vardes \
 varquot2test -varquot2test \
diff --git a/contrib/cdoCompletion.tcsh b/contrib/cdoCompletion.tcsh
index 73da97f..f15535c 100644
--- a/contrib/cdoCompletion.tcsh
+++ b/contrib/cdoCompletion.tcsh
@@ -8,7 +8,6 @@ set cdoCmpl = (\
 -percentile \
 -precision \
 -reduce_dim \
--remap_genweights \
 -sortname \
 -timestat_date \
 C, \
@@ -693,7 +692,9 @@ tstepcount \
 unsetgridmask \
 usegridnumber \
 uv2dv \
+uv2dv_cfd \
 uv2dvl \
+uv2vr_cfd \
 uvDestag \
 vardes \
 varquot2test \
diff --git a/contrib/cdoCompletion.zsh b/contrib/cdoCompletion.zsh
index 8179992..3547109 100644
--- a/contrib/cdoCompletion.zsh
+++ b/contrib/cdoCompletion.zsh
@@ -8,7 +8,6 @@ compctl -k "(
 --percentile \
 --precision \
 --reduce_dim \
---remap_genweights \
 --sortname \
 --timestat_date \
 -C, \
@@ -693,7 +692,9 @@ tstepcount -tstepcount \
 unsetgridmask -unsetgridmask \
 usegridnumber -usegridnumber \
 uv2dv -uv2dv \
+uv2dv_cfd -uv2dv_cfd \
 uv2dvl -uv2dvl \
+uv2vr_cfd -uv2vr_cfd \
 uvDestag -uvDestag \
 vardes -vardes \
 varquot2test -varquot2test \
diff --git a/doc/cdo.pdf b/doc/cdo.pdf
index 582f288..f2b53c4 100644
Binary files a/doc/cdo.pdf and b/doc/cdo.pdf differ
diff --git a/doc/cdo_cmor.pdf b/doc/cdo_cmor.pdf
index a7d3022..5a1fdf0 100644
Binary files a/doc/cdo_cmor.pdf and b/doc/cdo_cmor.pdf differ
diff --git a/doc/cdo_eca.pdf b/doc/cdo_eca.pdf
index 9478a28..49b17e2 100644
Binary files a/doc/cdo_eca.pdf and b/doc/cdo_eca.pdf differ
diff --git a/doc/cdo_magics.pdf b/doc/cdo_magics.pdf
index 641c3d4..c94fe9f 100644
Binary files a/doc/cdo_magics.pdf and b/doc/cdo_magics.pdf differ
diff --git a/doc/cdo_refcard.pdf b/doc/cdo_refcard.pdf
index 554fb87..de51b2f 100644
Binary files a/doc/cdo_refcard.pdf and b/doc/cdo_refcard.pdf differ
diff --git a/libcdi/ChangeLog b/libcdi/ChangeLog
index 54014e4..29ed032 100644
--- a/libcdi/ChangeLog
+++ b/libcdi/ChangeLog
@@ -1,3 +1,11 @@
+2017-11-05  Uwe Schulzweida
+
+	* Version 1.9.2 released
+
+2017-10-09  Uwe Schulzweida
+
+	* changed type of gridsize from int to size_t
+
 2017-10-05  Uwe Schulzweida
 
         * using CGRIBEX library version 1.9.0
diff --git a/libcdi/Makefile.in b/libcdi/Makefile.in
index 93e11e7..1a630ff 100644
--- a/libcdi/Makefile.in
+++ b/libcdi/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,21 +88,6 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = .
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/configure $(am__configure_deps) \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/tables/gen_tableheaderfile.in \
-	$(top_srcdir)/util/serialrun.in $(srcdir)/cdi.settings.in \
-	$(top_srcdir)/src/pkgconfig/cdi.pc.in \
-	$(top_srcdir)/src/pkgconfig/cdipio.pc.in AUTHORS COPYING \
-	ChangeLog INSTALL NEWS README config/compile \
-	config/config.guess config/config.sub config/depcomp \
-	config/install-sh config/missing config/mkinstalldirs \
-	config/ltmain.sh $(top_srcdir)/config/compile \
-	$(top_srcdir)/config/config.guess \
-	$(top_srcdir)/config/config.sub \
-	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
-	$(top_srcdir)/config/missing
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -124,6 +119,8 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__DIST_COMMON)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
@@ -187,6 +184,19 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/cdi.settings.in \
+	$(top_srcdir)/config/compile $(top_srcdir)/config/config.guess \
+	$(top_srcdir)/config/config.sub \
+	$(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
+	$(top_srcdir)/config/missing \
+	$(top_srcdir)/config/mkinstalldirs \
+	$(top_srcdir)/src/pkgconfig/cdi.pc.in \
+	$(top_srcdir)/src/pkgconfig/cdipio.pc.in \
+	$(top_srcdir)/tables/gen_tableheaderfile.in \
+	$(top_srcdir)/util/serialrun.in AUTHORS COPYING ChangeLog \
+	INSTALL NEWS README config/compile config/config.guess \
+	config/config.sub config/depcomp config/install-sh \
+	config/ltmain.sh config/missing config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -450,7 +460,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -660,7 +669,7 @@ distdir: $(DISTFILES)
 	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
 	|| chmod -R a+r "$(distdir)"
 dist-gzip: distdir
-	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
 	$(am__post_remove_distdir)
 
 dist-bzip2: distdir
@@ -676,17 +685,17 @@ dist-xz: distdir
 	$(am__post_remove_distdir)
 
 dist-tarZ: distdir
-	@echo WARNING: "Support for shar distribution archives is" \
-	               "deprecated." >&2
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
 	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
 	$(am__post_remove_distdir)
 
 dist-shar: distdir
-	@echo WARNING: "Support for distribution archives compressed with" \
-		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
 dist-zip: distdir
@@ -704,7 +713,7 @@ dist dist-all:
 distcheck: dist
 	case '$(DIST_ARCHIVES)' in \
 	*.tar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
 	*.tar.bz2*) \
 	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
 	*.tar.lz*) \
@@ -714,22 +723,23 @@ distcheck: dist
 	*.tar.Z*) \
 	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
 	*.shar.gz*) \
-	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	  eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
 	chmod -R a-w $(distdir)
 	chmod u+w $(distdir)
-	mkdir $(distdir)/_build $(distdir)/_inst
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
 	chmod a-w $(distdir)
 	test -d $(distdir)/_build || exit 0; \
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
-	  && $(am__cd) $(distdir)/_build \
-	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
@@ -906,6 +916,8 @@ uninstall-am:
 	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
 	ps ps-am tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 #
 doc/cdi_cman.pdf: 
 	(cd $(top_srcdir)/doc/tex ; ./makepdf_c ; mv cdi_cman.pdf .. ; ./cleanup)
diff --git a/libcdi/aclocal.m4 b/libcdi/aclocal.m4
index 74a336f..ca9ecf4 100644
--- a/libcdi/aclocal.m4
+++ b/libcdi/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.14 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,13 +14,13 @@
 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
-[m4_warning([this file was generated for autoconf 2.68.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
 You have another version of autoconf.  It may work, but is not guaranteed to.
 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'.])])
 
-# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
 # generated from the m4 files accompanying Automake X.Y.
 # (This private macro should not be called outside this file.)
 AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.14'
+[am__api_version='1.15'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14], [],
+m4_if([$1], [1.15.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -103,15 +103,14 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 # configured tree to be moved without reconfiguration.
 
 AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 ])
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -142,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE(
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -333,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -409,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -499,8 +498,8 @@ AC_REQUIRE([AC_PROG_MKDIR_P])dnl
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 AC_REQUIRE([AC_PROG_AWK])dnl
 AC_REQUIRE([AC_PROG_MAKE_SET])dnl
 AC_REQUIRE([AM_SET_LEADING_DOT])dnl
@@ -573,7 +572,11 @@ to "yes", and re-run configure.
 END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
-fi])
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
 dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
@@ -602,7 +605,7 @@ for _am_header in $config_headers :; do
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -613,7 +616,7 @@ echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_co
 # Define $install_sh.
 AC_DEFUN([AM_PROG_INSTALL_SH],
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -623,7 +626,7 @@ if test x"${install_sh}" != xset; then
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -645,7 +648,7 @@ AC_SUBST([am__leading_dot])])
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -680,7 +683,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -730,7 +733,7 @@ rm -f confinc confmf
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -769,7 +772,7 @@ fi
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -798,7 +801,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -845,7 +848,7 @@ AC_LANG_POP([C])])
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -864,7 +867,7 @@ AC_DEFUN([AM_RUN_LOG],
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -945,7 +948,7 @@ AC_CONFIG_COMMANDS_PRE(
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1005,7 +1008,7 @@ AC_SUBST([AM_BACKSLASH])dnl
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1033,7 +1036,7 @@ fi
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1052,7 +1055,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
diff --git a/libcdi/app/Makefile.in b/libcdi/app/Makefile.in
index f3c05a5..9d99541 100644
--- a/libcdi/app/Makefile.in
+++ b/libcdi/app/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -83,9 +93,6 @@ noinst_PROGRAMS = $(am__EXEEXT_2) createtable$(EXEEXT)
 @ENABLE_CDI_LIB_TRUE at am__append_1 = cdi
 @ENABLE_CDI_LIB_FALSE at am__append_2 = cdi
 subdir = app
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -117,6 +124,7 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -201,6 +209,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -416,7 +426,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign app/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign app/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -745,6 +754,8 @@ uninstall-am: uninstall-binPROGRAMS
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
 
+.PRECIOUS: Makefile
+
 #
 clean-local: clean-local-dirs
 .PHONY: clean-local-dirs
diff --git a/libcdi/app/cdi.c b/libcdi/app/cdi.c
index 701a204..87526c6 100644
--- a/libcdi/app/cdi.c
+++ b/libcdi/app/cdi.c
@@ -184,10 +184,10 @@ void usage(void)
 
 static
 void printInfo(int vdate, int vtime, char *varname, double level,
-	       int datasize, int number, int nmiss, double missval, const double *data, int vardis)
+	       size_t datasize, int number, size_t nmiss, double missval, const double *data, int vardis)
 {
   static int rec = 0;
-  int i, ivals = 0, imiss = 0;
+  size_t ivals = 0, imiss = 0;
   double arrmean, arrmin, arrmax;
   char vdatestr[32], vtimestr[32];
 
@@ -208,9 +208,9 @@ void printInfo(int vdate, int vtime, char *varname, double level,
 
   fprintf(stdout, "%6d :%s %s %7g ", ++rec, vdatestr, vtimestr, level);
 
-  fprintf(stdout, "%8d ", datasize);
+  fprintf(stdout, "%8zu ", datasize);
 
-  fprintf(stdout, "%7d :", nmiss);
+  fprintf(stdout, "%7zu :", nmiss);
 
   if ( number == CDI_REAL )
     {
@@ -219,7 +219,7 @@ void printInfo(int vdate, int vtime, char *varname, double level,
 	  arrmean = 0;
 	  arrmin  =  1.e300;
 	  arrmax  = -1.e300;
-	  for ( i = 0; i < datasize; i++ )
+	  for ( size_t i = 0; i < datasize; i++ )
 	    {
 	      if ( !DBL_IS_EQUAL(data[i], missval) )
 		{
@@ -237,7 +237,7 @@ void printInfo(int vdate, int vtime, char *varname, double level,
 	  arrmean = data[0];
 	  arrmin  = data[0];
 	  arrmax  = data[0];
-	  for ( i = 1; i < datasize; i++ )
+	  for ( size_t i = 1; i < datasize; i++ )
 	    {
 	      if ( data[i] < arrmin ) arrmin = data[i];
 	      if ( data[i] > arrmax ) arrmax = data[i];
@@ -251,10 +251,10 @@ void printInfo(int vdate, int vtime, char *varname, double level,
     }
   else
     {
-      int nvals_r = 0, nvals_i = 0;
+      size_t nvals_r = 0, nvals_i = 0;
       double arrsum_r = 0, arrsum_i = 0, arrmean_r = 0, arrmean_i = 0;
 
-      for ( i = 0; i < datasize; i++ )
+      for ( size_t i = 0; i < datasize; i++ )
 	{
 	  if ( !DBL_IS_EQUAL(data[i*2], missval) )
 	    {
@@ -278,7 +278,7 @@ void printInfo(int vdate, int vtime, char *varname, double level,
   fprintf(stdout, " : %-14s\n", varname);
 
   if ( imiss != nmiss && nmiss > 0 )
-    fprintf(stdout, "Found %d of %d missing values!\n", imiss, nmiss);
+    fprintf(stdout, "Found %zu of %zu missing values!\n", imiss, nmiss);
 }
 
 static const char *tunit2str(int tunits)
@@ -406,8 +406,8 @@ void printShortinfo(int streamID, int vlistID, int vardis)
 	  fprintf(stdout, "%3d ", vlistZaxisIndex(vlistID, zaxisID) + 1);
 
 	  /* grid info */
-	  int gridsize = gridInqSize(gridID);
-	  fprintf(stdout, "%9d ", gridsize);
+	  size_t gridsize = gridInqSize(gridID);
+	  fprintf(stdout, "%9zu ", gridsize);
 	  fprintf(stdout, "%3d ", vlistGridIndex(vlistID, gridID) + 1);
 
 	  /* datatype */
@@ -836,9 +836,9 @@ int main(int argc, char *argv[])
 
   if ( fname1 )
     {
-      int nmiss;
+      size_t nmiss;
       int number;
-      int datasize = 0;
+      size_t datasize = 0;
       int streamID2 = CDI_UNDEFID;
       int filetype;
       int gridID, zaxisID;
@@ -846,7 +846,7 @@ int main(int argc, char *argv[])
       int nrecs;
       int levelID, levelsize;
       int nts = 0;
-      int gridsize = 0;
+      size_t gridsize = 0;
       int recID;
       int taxisID2 = CDI_UNDEFID;
       int vlistID2 = CDI_UNDEFID;
@@ -911,7 +911,7 @@ int main(int argc, char *argv[])
 	}
 
       if ( vlistNumber(vlistID1) != CDI_REAL ) datasize *= 2;
-      double *data = (double *) malloc((size_t)datasize * sizeof (double));
+      double *data = (double *) malloc(datasize * sizeof (double));
 
       /*
 	nts = cdiInqTimeSize(streamID1);
@@ -925,6 +925,7 @@ int main(int argc, char *argv[])
 	  printShortinfo(streamID1, vlistID1, Vardis);
 	}
 
+      size_t idum;
       int tsID = 0;
       if ( Info || fname2 )
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) > 0 )
@@ -945,7 +946,8 @@ int main(int argc, char *argv[])
 	      for ( recID = 0; recID < nrecs; recID++ )
 		{
 		  streamInqRecord(streamID1, &varID, &levelID);
-		  streamReadRecord(streamID1, data, &nmiss);
+		  streamReadRecord(streamID1, data, &idum);
+                  nmiss = idum;
 
 		  number   = vlistInqVarNumber(vlistID1, varID);
 		  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -973,7 +975,7 @@ int main(int argc, char *argv[])
 		      if ( Move )
 			streamCopyRecord(streamID2, streamID1);
 		      else
-			streamWriteRecord(streamID2, data, nmiss);
+			streamWriteRecord(streamID2, data, idum);
 		    }
 	      	}
 	    }
@@ -1004,7 +1006,8 @@ int main(int argc, char *argv[])
 		  for ( levelID = 0; levelID < levelsize; levelID++ )
 		    {
                       double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) : levelID+1;
-		      streamReadVarSlice(streamID1, varID, levelID, data, &nmiss);
+		      streamReadVarSlice(streamID1, varID, levelID, data, &idum);
+                      nmiss = idum;
 
 		      if ( Info )
 			printInfo(vdate, vtime, varname, level, gridsize, number, nmiss, missval, data, Vardis);
diff --git a/libcdi/configure b/libcdi/configure
index 436c24f..c453347 100755
--- a/libcdi/configure
+++ b/libcdi/configure
@@ -1,13 +1,11 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdi 1.9.1.
+# Generated by GNU Autoconf 2.69 for cdi 1.9.2.
 #
 # Report bugs to <http://mpimet.mpg.de/cdi>.
 #
 #
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
-# Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
 #
 #
 # This configure script is free software; the Free Software Foundation
@@ -136,6 +134,31 @@ export LANGUAGE
 # CDPATH.
 (unset CDPATH) >/dev/null 2>&1 && unset CDPATH
 
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
 if test "x$CONFIG_SHELL" = x; then
   as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
@@ -169,7 +192,8 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
 else
   exitcode=1; echo positional parameters were not saved.
 fi
-test x\$exitcode = x0 || exit 1"
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
   as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
@@ -222,21 +246,25 @@ IFS=$as_save_IFS
 
 
       if test "x$CONFIG_SHELL" != x; then :
-  # We cannot yet assume a decent shell, so we have to provide a
-	# neutralization value for shells without unset; and this also
-	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
-	BASH_ENV=/dev/null
-	ENV=/dev/null
-	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
 fi
 
     if test x$as_have_required = xno; then :
@@ -339,6 +367,14 @@ $as_echo X"$as_dir" |
 
 
 } # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
 # as_fn_append VAR VALUE
 # ----------------------
 # Append the text in VALUE to the end of the definition contained in VAR. Take
@@ -460,6 +496,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
   chmod +x "$as_me.lineno" ||
     { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
   # original and so on.  Autoconf is especially sensitive to this).
@@ -494,16 +534,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -515,28 +555,8 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -570,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdi'
 PACKAGE_TARNAME='cdi'
-PACKAGE_VERSION='1.9.1'
-PACKAGE_STRING='cdi 1.9.1'
+PACKAGE_VERSION='1.9.2'
+PACKAGE_STRING='cdi 1.9.2'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdi'
 PACKAGE_URL=''
 
@@ -1379,8 +1399,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -1466,7 +1484,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 cdi 1.9.1 to adapt to many kinds of systems.
+\`configure' configures cdi 1.9.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1536,7 +1554,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdi 1.9.1:";;
+     short | recursive ) echo "Configuration of cdi 1.9.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1735,10 +1753,10 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdi configure 1.9.1
-generated by GNU Autoconf 2.68
+cdi configure 1.9.2
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
@@ -1928,7 +1946,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2188,7 +2206,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2234,7 +2252,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2280,7 +2298,7 @@ $as_echo "$ac_try_echo"; } >&5
 	 test ! -s conftest.err
        } && test -s conftest$ac_exeext && {
 	 test "$cross_compiling" = yes ||
-	 $as_test_x conftest$ac_exeext
+	 test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
@@ -2580,8 +2598,8 @@ 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 cdi $as_me 1.9.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+It was created by cdi $as_me 1.9.2, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
@@ -3046,7 +3064,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
 
 
-am__api_version='1.14'
+am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
@@ -3085,7 +3103,7 @@ case $as_dir/ in #((
     # by default.
     for ac_prog in ginstall scoinst install; do
       for ac_exec_ext in '' $ac_executable_extensions; do
-	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
 	  if test $ac_prog = install &&
 	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
 	    # AIX install.  It has an incompatible calling convention.
@@ -3218,8 +3236,8 @@ test "$program_suffix" != NONE &&
 ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
 program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
 
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
   case $am_aux_dir in
@@ -3238,7 +3256,7 @@ else
 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
 fi
 
-if test x"${install_sh}" != xset; then
+if test x"${install_sh+set}" != xset; then
   case $am_aux_dir in
   *\ * | *\	*)
     install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
@@ -3269,7 +3287,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3309,7 +3327,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3360,7 +3378,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_prog in mkdir gmkdir; do
 	 for ac_exec_ext in '' $ac_executable_extensions; do
-	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
 	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
 	     'mkdir (GNU coreutils) '* | \
 	     'mkdir (coreutils) '* | \
@@ -3407,7 +3425,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3532,7 +3550,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdi'
- VERSION='1.9.1'
+ VERSION='1.9.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3566,8 +3584,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
 mkdir_p='$(MKDIR_P)'
 
-# We need awk for the "check" target.  The system "awk" is bad on
-# some platforms.
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
 # Always define AMTAR for backward compatibility.  Yes, it's still used
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
@@ -3624,6 +3642,7 @@ END
     as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
   fi
 fi
+
 ac_config_headers="$ac_config_headers src/config.h"
 
 
@@ -3668,7 +3687,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3708,7 +3727,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3828,7 +3847,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3868,7 +3887,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3921,7 +3940,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -3962,7 +3981,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
@@ -4020,7 +4039,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4064,7 +4083,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -4510,8 +4529,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -4929,7 +4947,7 @@ main ()
   return 0;
 }
 _ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
 do
   CC="$ac_save_CC $ac_arg"
   if ac_fn_c_try_compile "$LINENO"; then :
@@ -5061,7 +5079,7 @@ ac_compile='$FC -c $FCFLAGS $ac_fcflags_srcext conftest.$ac_ext >&5'
 ac_link='$FC -o conftest$ac_exeext $FCFLAGS $LDFLAGS $ac_fcflags_srcext conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_fc_compiler_gnu
 if test -n "$ac_tool_prefix"; then
-  for ac_prog in gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn xlf90 f90 pgf90 pghpf epcf90 g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77
+  for ac_prog in gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor xlf90 f90 pgf90 pghpf epcf90 g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
@@ -5079,7 +5097,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_FC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5105,7 +5123,7 @@ fi
 fi
 if test -z "$FC"; then
   ac_ct_FC=$FC
-  for ac_prog in gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn xlf90 f90 pgf90 pghpf epcf90 g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77
+  for ac_prog in gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor xlf90 f90 pgf90 pghpf epcf90 g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
@@ -5123,7 +5141,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_FC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -5256,6 +5274,11 @@ else
   fi
 fi
 
+if test $ac_compiler_gnu = yes; then
+  GFC=yes
+else
+  GFC=
+fi
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -5277,7 +5300,11 @@ else
 ac_fcflags_srcext_save=$ac_fcflags_srcext
 ac_fcflags_srcext=
 ac_cv_fc_srcext_f90=unknown
-for ac_flag in none -qsuffix=f=f90 -Tf; do
+case $ac_ext in #(
+  [fF]77) ac_try=f77;; #(
+  *) ac_try=f95;;
+esac
+for ac_flag in none -qsuffix=f=f90 -Tf "-x $ac_try"; do
   test "x$ac_flag" != xnone && ac_fcflags_srcext="$ac_flag"
   cat > conftest.$ac_ext <<_ACEOF
       program conftest
@@ -6041,7 +6068,7 @@ ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5'
 ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_f77_compiler_gnu
 if test -n "$ac_tool_prefix"; then
-  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn
+  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
@@ -6059,7 +6086,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_F77="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6085,7 +6112,7 @@ fi
 fi
 if test -z "$F77"; then
   ac_ct_F77=$F77
-  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn
+  for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
@@ -6103,7 +6130,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_F77="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6275,7 +6302,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6319,7 +6346,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CXX="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -6849,7 +6876,7 @@ do
     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"
-      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+      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
@@ -6925,7 +6952,7 @@ do
     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"
-      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+      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
@@ -6991,7 +7018,7 @@ do
     for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+      as_fn_executable_p "$ac_path_EGREP" || continue
 # Check for GNU ac_path_EGREP and select it if it is found.
   # Check for GNU $ac_path_EGREP
 case `"$ac_path_EGREP" --version 2>&1` in
@@ -7058,7 +7085,7 @@ do
     for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
       ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+      as_fn_executable_p "$ac_path_FGREP" || continue
 # Check for GNU ac_path_FGREP and select it if it is found.
   # Check for GNU $ac_path_FGREP
 case `"$ac_path_FGREP" --version 2>&1` in
@@ -7314,7 +7341,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7358,7 +7385,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7782,7 +7809,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -7822,7 +7849,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OBJDUMP="objdump"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8128,7 +8155,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8168,7 +8195,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DLLTOOL="dlltool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8271,7 +8298,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8315,7 +8342,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_AR="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8440,7 +8467,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_STRIP="${ac_tool_prefix}strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8480,7 +8507,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_STRIP="strip"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8539,7 +8566,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -8579,7 +8606,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9228,7 +9255,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9268,7 +9295,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9348,7 +9375,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9388,7 +9415,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9440,7 +9467,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9480,7 +9507,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9532,7 +9559,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9572,7 +9599,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9624,7 +9651,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9664,7 +9691,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL="otool"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9716,7 +9743,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -9756,7 +9783,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_OTOOL64="otool64"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -23318,16 +23345,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -23387,28 +23414,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -23449,8 +23464,8 @@ Usage: $0 [OPTIONS]
 Report bugs to <bug-libtool at gnu.org>."
 
 lt_cl_version="\
-cdi config.lt 1.9.1
-configured by $0, generated by GNU Autoconf 2.68.
+cdi config.lt 1.9.2
+configured by $0, generated by GNU Autoconf 2.69.
 
 Copyright (C) 2011 Free Software Foundation, Inc.
 This config.lt script is free software; the Free Software Foundation
@@ -25586,6 +25601,8 @@ _ACEOF
 esac
 rm -rf conftest*
   fi
+
+
 fi
 
 #  ----------------------------------------------------------------------
@@ -26553,7 +26570,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ax_pthread_config="yes"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -26745,7 +26762,7 @@ fi
     #handle absolute path differently from PATH based program lookup
                    case "x$CC" in #(
   x/*) :
-    if { test -f ${CC}_r && $as_test_x ${CC}_r; }; then :
+    if as_fn_executable_p ${CC}_r; then :
   PTHREAD_CC="${CC}_r"
 fi ;; #(
   *) :
@@ -26767,7 +26784,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_PTHREAD_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -27188,7 +27205,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NC_CONFIG="nc-config"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -27362,7 +27379,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_NC_CONFIG="$NETCDF_ROOT/bin/nc-config"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -28702,7 +28719,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -28745,7 +28762,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -28819,7 +28836,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_MPI_LAUNCH="$as_dir/$ac_word$ac_exec_ext"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -29161,7 +29178,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RUBY="ruby"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -29451,7 +29468,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_SWIG="swig"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -29555,7 +29572,7 @@ do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_PYTHON="python"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
@@ -30697,16 +30714,16 @@ if (echo >conf$$.file) 2>/dev/null; then
     # ... but there are two gotchas:
     # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
     # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -p'.
+    # In both cases, we have to default to `cp -pR'.
     ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -p'
+      as_ln_s='cp -pR'
   elif ln conf$$.file conf$$ 2>/dev/null; then
     as_ln_s=ln
   else
-    as_ln_s='cp -p'
+    as_ln_s='cp -pR'
   fi
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
 rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
 rmdir conf$$.dir 2>/dev/null
@@ -30766,28 +30783,16 @@ else
   as_mkdir_p=false
 fi
 
-if test -x / >/dev/null 2>&1; then
-  as_test_x='test -x'
-else
-  if ls -dL / >/dev/null 2>&1; then
-    as_ls_L_option=L
-  else
-    as_ls_L_option=
-  fi
-  as_test_x='
-    eval sh -c '\''
-      if test -d "$1"; then
-	test -d "$1/.";
-      else
-	case $1 in #(
-	-*)set "./$1";;
-	esac;
-	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
-	???[sx]*):;;*)false;;esac;fi
-    '\'' sh
-  '
-fi
-as_executable_p=$as_test_x
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -30808,8 +30813,8 @@ 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 cdi $as_me 1.9.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+This file was extended by cdi $as_me 1.9.2, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -30874,11 +30879,11 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdi config.status 1.9.1
-configured by $0, generated by GNU Autoconf 2.68,
+cdi config.status 1.9.2
+configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2010 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
 
@@ -30969,7 +30974,7 @@ fi
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
   shift
   \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
   CONFIG_SHELL='$SHELL'
diff --git a/libcdi/configure.ac b/libcdi/configure.ac
index eea364f..8aac01a 100644
--- a/libcdi/configure.ac
+++ b/libcdi/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdi], [1.9.1], [http://mpimet.mpg.de/cdi])
+AC_INIT([cdi], [1.9.2], [http://mpimet.mpg.de/cdi])
 
 AC_DEFINE_UNQUOTED(CDI, ["$PACKAGE_VERSION"], [CDI version])
 
diff --git a/libcdi/doc/cdi_cman.pdf b/libcdi/doc/cdi_cman.pdf
index 2e09c38..7f864f3 100644
Binary files a/libcdi/doc/cdi_cman.pdf and b/libcdi/doc/cdi_cman.pdf differ
diff --git a/libcdi/doc/cdi_fman.pdf b/libcdi/doc/cdi_fman.pdf
index 85d3e4d..9a1ecc6 100644
Binary files a/libcdi/doc/cdi_fman.pdf and b/libcdi/doc/cdi_fman.pdf differ
diff --git a/libcdi/examples/Makefile.in b/libcdi/examples/Makefile.in
index efcfe5f..f414a4c 100644
--- a/libcdi/examples/Makefile.in
+++ b/libcdi/examples/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -85,9 +95,6 @@ noinst_PROGRAMS = cdi_write$(EXEEXT) cdi_write_relativ$(EXEEXT) \
 @CREATE_ISOC_TRUE at am__append_1 = cdi_read_f2003 cdi_write_f2003
 @ENABLE_NETCDF_TRUE at am__append_2 = cdi_write_const
 subdir = examples
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -119,6 +126,7 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -267,6 +275,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -504,7 +514,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign examples/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -821,6 +830,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 cdi_read_f2003.$(OBJEXT): $(top_builddir)/src/mo_cdi.$(FCMODEXT)
 cdi_write_f2003.$(OBJEXT): $(top_builddir)/src/mo_cdi.$(FCMODEXT)
 #
diff --git a/libcdi/examples/cdi_copy.c b/libcdi/examples/cdi_copy.c
index 3de9a1c..fd63393 100644
--- a/libcdi/examples/cdi_copy.c
+++ b/libcdi/examples/cdi_copy.c
@@ -7,7 +7,7 @@ int main(void)
   const int nlat =  6; // Number of latitudes 
   const int nlev =  5; // Number of levels    
   const int nts  =  3; // Number of time steps
-  int nmiss;
+  size_t nmiss;
   double var1[nlon*nlat];
   double var2[nlon*nlat*nlev];
 
diff --git a/libcdi/examples/cdi_read.c b/libcdi/examples/cdi_read.c
index 9c1d238..395bc2a 100644
--- a/libcdi/examples/cdi_read.c
+++ b/libcdi/examples/cdi_read.c
@@ -7,7 +7,7 @@ int main(void)
   const int nlat =  6; // Number of latitudes
   const int nlev =  5; // Number of levels
   const int nts  =  3; // Number of time steps
-  int nmiss, vdate, vtime;
+  size_t nmiss;
   double var1[nlon*nlat];
   double var2[nlon*nlat*nlev];
 
@@ -37,8 +37,8 @@ int main(void)
       streamInqTimestep(streamID, tsID);
 
       // Get the verification date and time 
-      vdate = taxisInqVdate(taxisID);
-      vtime = taxisInqVtime(taxisID);
+      int vdate = taxisInqVdate(taxisID);
+      int vtime = taxisInqVtime(taxisID);
       printf("read timestep %d:  date=%d  time=%d\n", tsID+1, vdate, vtime);
 
       // Read var1 and var2 
diff --git a/libcdi/examples/cdi_read_f2003.f90 b/libcdi/examples/cdi_read_f2003.f90
index 1281e1b..3cfd36f 100644
--- a/libcdi/examples/cdi_read_f2003.f90
+++ b/libcdi/examples/cdi_read_f2003.f90
@@ -4,8 +4,9 @@ PROGRAM CDIREADF2003
 
   IMPLICIT NONE
 
-  INTEGER :: gsize, nlevel, nvars, code
-  INTEGER :: vdate, vtime, nmiss, status, ilev
+  INTEGER(c_size_t) :: gsize, nmiss
+  INTEGER :: nlevel, nvars, code
+  INTEGER :: vdate, vtime, status, ilev
   INTEGER :: streamID, varID, gridID, zaxisID
   INTEGER :: tsID, vlistID, taxisID
   DOUBLE PRECISION, ALLOCATABLE :: field(:,:)
diff --git a/libcdi/examples/cdi_write.c b/libcdi/examples/cdi_write.c
index acc1500..e99698d 100644
--- a/libcdi/examples/cdi_write.c
+++ b/libcdi/examples/cdi_write.c
@@ -7,7 +7,7 @@ int main(void)
   const int nlat =  6; // Number of latitudes
   const int nlev =  5; // Number of levels
   const int nts  =  3; // Number of time steps
-  int nmiss = 0;
+  size_t nmiss = 0;
   double lons[] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
   double lats[] = {-75, -45, -15, 15, 45, 75};
   double levs[] = {101300, 92500, 85000, 50000, 20000};
@@ -68,8 +68,8 @@ int main(void)
       streamDefTimestep(streamID, tsID);
 
       // Init var1 and var2
-      for ( int i = 0; i < nlon*nlat;      i++ ) var1[i] = 1.1;
-      for ( int i = 0; i < nlon*nlat*nlev; i++ ) var2[i] = 2.2;
+      for ( size_t i = 0; i < nlon*nlat;      i++ ) var1[i] = 1.1;
+      for ( size_t i = 0; i < nlon*nlat*nlev; i++ ) var2[i] = 2.2;
 
       // Write var1 and var2
       streamWriteVar(streamID, varID1, var1, nmiss);
diff --git a/libcdi/examples/cdi_write_const.c b/libcdi/examples/cdi_write_const.c
index 7520c6e..61c68a0 100644
--- a/libcdi/examples/cdi_write_const.c
+++ b/libcdi/examples/cdi_write_const.c
@@ -9,7 +9,7 @@ int main(void)
 {
   int gridID, zaxisID1, zaxisID2;
   int vlistID, varID1, varID2, streamID;
-  int i, nmiss = 0;
+  size_t i, nmiss = 0;
   double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
   double lats[nlat] = {-75, -45, -15, 15, 45, 75};
   double levs[nlev] = {101300, 92500, 85000, 50000, 20000};
diff --git a/libcdi/examples/cdi_write_ens.c b/libcdi/examples/cdi_write_ens.c
index 2fea3c9..3e5a5f0 100644
--- a/libcdi/examples/cdi_write_ens.c
+++ b/libcdi/examples/cdi_write_ens.c
@@ -18,7 +18,7 @@ int main(void)
   int tsID;
   int levelID;
   int vlistID, taxisID;
-  int nmiss;
+  size_t nmiss;
 
   int instID;
   int i1,i2,i3;
diff --git a/libcdi/examples/cdi_write_f2003.f90 b/libcdi/examples/cdi_write_f2003.f90
index 8c53a33..cf4ad53 100644
--- a/libcdi/examples/cdi_write_f2003.f90
+++ b/libcdi/examples/cdi_write_f2003.f90
@@ -5,7 +5,8 @@
 
       IMPLICIT NONE
 
-      INTEGER nlon, nlat, nlev, nts
+      INTEGER :: nlev, nts
+      INTEGER(c_size_t) ::  nlon, nlat, nmiss
       PARAMETER (nlon = 12)   ! Number of longitudes
       PARAMETER (nlat =  6)   ! Number of latitudes
       PARAMETER (nlev =  5)   ! Number of levels
@@ -13,7 +14,7 @@
 
       INTEGER gridID, zaxisID1, zaxisID2, taxisID
       INTEGER vlistID, varID1, varID2, streamID, tsID
-      INTEGER i, nmiss, status
+      INTEGER i, status
       DOUBLE PRECISION lons(nlon), lats(nlat), levs(nlev)
       DOUBLE PRECISION var1(nlon*nlat), var2(nlon*nlat*nlev)
       CHARACTER(len=256, kind=c_char) :: varname
diff --git a/libcdi/examples/cdi_write_hybrid.c b/libcdi/examples/cdi_write_hybrid.c
index 24504c8..f9b9a90 100644
--- a/libcdi/examples/cdi_write_hybrid.c
+++ b/libcdi/examples/cdi_write_hybrid.c
@@ -10,8 +10,8 @@
 int main(void)
 {
   int gridID, zaxisID1, zaxisID2, zaxisID3, zaxisID4, taxisID;
-  int vlistID, varID1, varID2, varID3, varID4, streamID, tsID;
-  int i, k, nmiss = 0;
+  int vlistID, varID1, varID2, varID3, varID4, streamID;
+  size_t nmiss = 0;
   double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
   double lats[nlat] = {-75, -45, -15, 15, 45, 75};
   double levs[nhlev] = {1, 2, 3, 4, 5, 6};
@@ -83,7 +83,7 @@ int main(void)
   streamDefVlist(streamID, vlistID);
 
   // Loop over the number of time steps
-  for ( tsID = 0; tsID < nts; tsID++ )
+  for ( int tsID = 0; tsID < nts; tsID++ )
     {
       // Set the verification date to 1985-01-01 + tsID
       taxisDefVdate(taxisID, 19850101+tsID);
@@ -93,13 +93,13 @@ int main(void)
       streamDefTimestep(streamID, tsID);
 
       // Init var1 and var2
-      for ( i = 0; i < nlon*nlat; ++i ) var1[i] = 1.1;
-      for ( k = 0; k < nflev; ++k )
-	for ( i = 0; i < nlon*nlat; ++i ) var2[i+k*nlon*nlat] = 2.2+k;
-      for ( k = 0; k < nhlev; ++k )
-	for ( i = 0; i < nlon*nlat; ++i ) var3[i+k*nlon*nlat] = -2.2-k;
-      for ( k = 0; k < nflev; ++k )
-	for ( i = 0; i < nlon*nlat; ++i ) var4[i+k*nlon*nlat] = 100+k;
+      for ( size_t i = 0; i < nlon*nlat; ++i ) var1[i] = 1.1;
+      for ( size_t k = 0; k < nflev; ++k )
+	for ( size_t i = 0; i < nlon*nlat; ++i ) var2[i+k*nlon*nlat] = 2.2+k;
+      for ( size_t k = 0; k < nhlev; ++k )
+	for ( size_t i = 0; i < nlon*nlat; ++i ) var3[i+k*nlon*nlat] = -2.2-k;
+      for ( size_t k = 0; k < nflev; ++k )
+	for ( size_t i = 0; i < nlon*nlat; ++i ) var4[i+k*nlon*nlat] = 100+k;
  
       // Write var1 and var2
       streamWriteVar(streamID, varID1, var1, nmiss);
diff --git a/libcdi/examples/pio/Makefile.in b/libcdi/examples/pio/Makefile.in
index ebd9c3f..2ab872d 100644
--- a/libcdi/examples/pio/Makefile.in
+++ b/libcdi/examples/pio/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,17 @@
 @SET_MAKE@
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -84,9 +94,6 @@ noinst_PROGRAMS = collectData$(EXEEXT) collectDataNStreams$(EXEEXT) \
 @USE_MPI_TRUE at am__append_2 = $(FPP_DEFOPT)USE_MPI
 @USE_FC_TRUE at am__append_3 = collectData2003
 subdir = examples/pio
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -118,6 +125,7 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -243,6 +251,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -458,7 +468,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/pio/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign examples/pio/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -751,6 +760,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 #
 clean-local: clean-local-dirs
 .PHONY: clean-local-dirs
diff --git a/libcdi/interfaces/Makefile.in b/libcdi/interfaces/Makefile.in
index 38722a6..de0727f 100644
--- a/libcdi/interfaces/Makefile.in
+++ b/libcdi/interfaces/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -90,9 +100,6 @@ noinst_PROGRAMS = $(am__EXEEXT_1)
 # =========================================================
 @ENABLE_PYTHON_TRUE at am__append_5 = pythonObj
 subdir = interfaces
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -124,6 +131,7 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -227,6 +235,8 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -464,7 +474,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign interfaces/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign interfaces/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -803,6 +812,8 @@ uninstall-am: uninstall-binPROGRAMS
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
 
+.PRECIOUS: Makefile
+
 # Ruby ====================================================
 @ENABLE_RUBY_TRUE at rubyLibMakefile:
 @ENABLE_RUBY_TRUE@	cd ruby; CFLAGS="$(CFLAGS)" LIBS="$(LIBS)" LDFLAGS="$(locallibs) $(LDFLAGS)" INCFLAGS="-I../../src" ruby extconfLib.rb
diff --git a/libcdi/interfaces/cdi.cpp b/libcdi/interfaces/cdi.cpp
index 7d69e11..835ca2e 100644
--- a/libcdi/interfaces/cdi.cpp
+++ b/libcdi/interfaces/cdi.cpp
@@ -270,14 +270,13 @@ CdiVariable::sinfo() { std::cout << "code:"  << std::endl; }
 double *
 CdiVariable::getValuesAsPointer()
 {
-  int levelID = 0, tsID = 0, nmiss;
-  int vdate, vtime, nrecs;
-  double *field;
-
-  nrecs = streamInqTimestep(streamID, tsID);
-  vdate = taxisInqVdate(taxisID);
-  vtime = taxisInqVtime(taxisID);
-  field = (double *) malloc(grid.size*sizeof(double));
+  int levelID = 0, tsID = 0;
+  size_t nmiss;
+
+  int nrecs = streamInqTimestep(streamID, tsID);
+  int vdate = taxisInqVdate(taxisID);
+  int vtime = taxisInqVtime(taxisID);
+  double *field = (double *) malloc(grid.size*sizeof(double));
   streamReadVarSlice(streamID, varID, levelID, field, &nmiss);
 
   return field;
@@ -286,7 +285,8 @@ CdiVariable::getValuesAsPointer()
 double **
 CdiVariable::getValuesWithLevelAsPointer(int tsID)
 {
-  int    levelID, nmiss, nrecs;
+  int    levelID, nrecs;
+  size_t nmiss;
   double **fieldWithLevel, *field;
 
   nrecs          = streamInqTimestep(streamID, tsID);
diff --git a/libcdi/src/Makefile.in b/libcdi/src/Makefile.in
index 4990e5f..f9c969b 100644
--- a/libcdi/src/Makefile.in
+++ b/libcdi/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -99,9 +109,6 @@ host_triplet = @host@
 @ENABLE_CDI_LIB_TRUE@@USE_MPI_TRUE at am__append_13 = pkgconfig/cdipio.pc
 @ENABLE_CDI_LIB_TRUE@@USE_MPI_TRUE at am__append_14 = pkgconfig/cdipio.pc
 subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/config.h.in $(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp $(am__include_HEADERS_DIST)
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -133,6 +140,8 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__include_HEADERS_DIST) \
+	$(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES =
@@ -314,6 +323,9 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -594,7 +606,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign src/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -947,8 +958,8 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
- at ENABLE_CDI_LIB_FALSE@uninstall-local:
 @ENABLE_CDI_LIB_FALSE at install-exec-local:
+ at ENABLE_CDI_LIB_FALSE@uninstall-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
@@ -1043,6 +1054,8 @@ uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
 	tags tags-am uninstall uninstall-am uninstall-includeHEADERS \
 	uninstall-libLTLIBRARIES uninstall-local
 
+.PRECIOUS: Makefile
+
 #
 mo_cdi.f90: $(top_srcdir)/src/cdi.h $(top_srcdir)/interfaces/f2003/bindGen.rb
 	$(RUBY) $(top_srcdir)/interfaces/f2003/bindGen.rb $(top_srcdir)/src/cdi.h $@
diff --git a/libcdi/src/cdf_lazy_grid.c b/libcdi/src/cdf_lazy_grid.c
index d287df2..9b104fe 100644
--- a/libcdi/src/cdf_lazy_grid.c
+++ b/libcdi/src/cdf_lazy_grid.c
@@ -198,22 +198,22 @@ cdfLazyGridDefYVals(grid_t *grid, const double *vals)
 }
 
 static double
-cdfLazyGridInqXVal(grid_t *grid, int index)
+cdfLazyGridInqXVal(grid_t *grid, size_t index)
 {
   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
   lock_lazy_load(lazyGrid);
-  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->xValsGet,
+  double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->xValsGet,
                                   grid->x.vals, grid->vtable->inqXValsPtr);
   unlock_lazy_load(lazyGrid);
   return rv;
 }
 
 static double
-cdfLazyGridInqYVal(grid_t *grid, int index)
+cdfLazyGridInqYVal(grid_t *grid, size_t index)
 {
   struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
   lock_lazy_load(lazyGrid);
-  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->yValsGet,
+  double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->yValsGet,
                                   grid->y.vals, grid->vtable->inqYValsPtr);
   unlock_lazy_load(lazyGrid);
   return rv;
diff --git a/libcdi/src/cdf_read.c b/libcdi/src/cdf_read.c
index fc72912..50c3de7 100644
--- a/libcdi/src/cdf_read.c
+++ b/libcdi/src/cdf_read.c
@@ -72,8 +72,8 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
     } while(0)
   if ( timetype != TIME_CONSTANT ) addDimension((size_t)tsID, 1);
   if ( zid != CDI_UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
-  if ( yid != CDI_UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
-  if ( xid != CDI_UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
+  if ( yid != CDI_UNDEFID ) addDimension(0, gridInqYsize(gridID));
+  if ( xid != CDI_UNDEFID ) addDimension(0, gridInqXsize(gridID));
 #undef addDimension
 
   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
@@ -421,7 +421,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
 
   int gridId = vlistInqVarGrid(vlistId, varId);
   int timetype = vlistInqVarTimetype(vlistId, varId);
-  int gridsize = gridInqSize(gridId);
+  size_t gridsize = gridInqSize(gridId);
 
   streamptr->numvals += gridsize;
 
@@ -487,7 +487,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
 }
 
 static
-void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void cdfReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -505,7 +505,7 @@ void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 
   cdf_get_vara_double(fileID, ncvarid, start, count, data);
 
-  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
+  size_t size = gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
   double missval = vlistInqVarMissval(vlistID, varID);
   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
@@ -519,7 +519,7 @@ void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 }
 
 static
-void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
+void cdfReadVarSP(stream_t *streamptr, int varID, float *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -537,7 +537,7 @@ void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
 
   cdf_get_vara_float(fileID, ncvarid, start, count, data);
 
-  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
+  size_t size = gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
   double missval = vlistInqVarMissval(vlistID, varID);
   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
@@ -551,7 +551,7 @@ void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
 }
 
 
-void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss)
+void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss)
 {
   if ( memtype == MEMTYPE_DOUBLE )
     cdfReadVarDP(streamptr, varID, (double*) data, nmiss);
@@ -560,7 +560,7 @@ void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *
 }
 
 static
-void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
+void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
@@ -574,9 +574,9 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
 
   int ncvarid = streamptr->vars[varID].ncvarid;
   int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
+  size_t gridsize = gridInqSize(gridId);
+  size_t xsize = gridInqXsize(gridId);
+  size_t ysize = gridInqYsize(gridId);
 
   if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_FLT32 )
     {
@@ -617,7 +617,7 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
 }
 
 static
-void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
+void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, size_t *nmiss)
 {
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
@@ -631,9 +631,9 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
 
   int ncvarid = streamptr->vars[varID].ncvarid;
   int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
+  size_t gridsize = gridInqSize(gridId);
+  size_t xsize = gridInqXsize(gridId);
+  size_t ysize = gridInqYsize(gridId);
 
   if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_FLT64 )
     {
@@ -674,7 +674,7 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
 }
 
 
-void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
 {
   if ( memtype == MEMTYPE_DOUBLE )
     cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
@@ -683,7 +683,7 @@ void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
 }
 
 
-void cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss)
+void cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
 
diff --git a/libcdi/src/cdf_write.c b/libcdi/src/cdf_write.c
index 49484fe..2852d66 100644
--- a/libcdi/src/cdf_write.c
+++ b/libcdi/src/cdf_write.c
@@ -355,7 +355,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
   vlistInqVarDimorder(vlistID, varID, &dimorder);
 
-  size_t gridsize  = (size_t)(gridInqSize(gridID));
+  size_t gridsize = gridInqSize(gridID);
   bool lchunk = (gridsize >= 16);
   int gridtype  = gridInqType(gridID);
   int gridindex = nc_grid_index(streamptr, gridID);
@@ -808,7 +808,7 @@ void cdfWriteGridTraj(stream_t *streamptr, int gridID)
 
 static
 void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, size_t nvals, size_t xsize, size_t ysize,
-                        bool swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
+                        bool swapxy, size_t *start, size_t *count, int memtype, const void *data, size_t nmiss)
 {
   const double *pdata_dp = (const double *) data;
   double *mdata_dp = NULL;
@@ -984,7 +984,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
 }
 
 
-void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
@@ -1070,14 +1070,14 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+  size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
 void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                         const int rect[][2], const void *data, int nmiss)
+                         const int rect[][2], const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
@@ -1168,14 +1168,14 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+  size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
                      xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
-void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
@@ -1256,13 +1256,13 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID));
+  size_t nvals = gridInqSize(gridID);
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
-void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+void cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
 {
   int varID   = streamptr->record->varID;
   int levelID = streamptr->record->levelID;
diff --git a/libcdi/src/cdi.h b/libcdi/src/cdi.h
index 4ad9bc0..673a9a2 100644
--- a/libcdi/src/cdi.h
+++ b/libcdi/src/cdi.h
@@ -386,39 +386,39 @@ int     streamInqCurTimestepID(int streamID);
 const char *streamFilename(int streamID);
 const char *streamFilesuffix(int filetype);
 
-off_t   streamNvals(int streamID);
+size_t  streamNvals(int streamID);
 
 int     streamInqNvars(int streamID);
 
 /* STREAM var I/O routines (random access) */
 
 /*      streamWriteVar: Write a variable */
-void    streamWriteVar(int streamID, int varID, const double data[], int nmiss);
-void    streamWriteVarF(int streamID, int varID, const float data[], int nmiss);
+void    streamWriteVar(int streamID, int varID, const double data[], size_t nmiss);
+void    streamWriteVarF(int streamID, int varID, const float data[], size_t nmiss);
 
 /*      streamReadVar: Read a variable */
-void    streamReadVar(int streamID, int varID, double data[], int *nmiss);
-void    streamReadVarF(int streamID, int varID, float data[], int *nmiss);
+void    streamReadVar(int streamID, int varID, double data[], size_t *nmiss);
+void    streamReadVarF(int streamID, int varID, float data[], size_t *nmiss);
 
 /*      streamWriteVarSlice: Write a horizontal slice of a variable */
-void    streamWriteVarSlice(int streamID, int varID, int levelID, const double data[], int nmiss);
-void    streamWriteVarSliceF(int streamID, int varID, int levelID, const float data[], int nmiss);
+void    streamWriteVarSlice(int streamID, int varID, int levelID, const double data[], size_t nmiss);
+void    streamWriteVarSliceF(int streamID, int varID, int levelID, const float data[], size_t nmiss);
 
 /*      streamReadVarSlice: Read a horizontal slice of a variable */
-void    streamReadVarSlice(int streamID, int varID, int levelID, double data[], int *nmiss);
-void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[], int *nmiss);
+void    streamReadVarSlice(int streamID, int varID, int levelID, double data[], size_t *nmiss);
+void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[], size_t *nmiss);
 
-void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], int nmiss);
+void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], size_t nmiss);
 
 
 /* STREAM record I/O routines (sequential access) */
 
 void    streamDefRecord(int streamID, int  varID, int  levelID);
 void    streamInqRecord(int streamID, int *varID, int *levelID);
-void    streamWriteRecord(int streamID, const double data[], int nmiss);
-void    streamWriteRecordF(int streamID, const float data[], int nmiss);
-void    streamReadRecord(int streamID, double data[], int *nmiss);
-void    streamReadRecordF(int streamID, float data[], int *nmiss);
+void    streamWriteRecord(int streamID, const double data[], size_t nmiss);
+void    streamWriteRecordF(int streamID, const float data[], size_t nmiss);
+void    streamReadRecord(int streamID, double data[], size_t *nmiss);
+void    streamReadRecordF(int streamID, float data[], size_t *nmiss);
 void    streamCopyRecord(int streamIDdest, int streamIDsrc);
 
 void    streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum);
@@ -526,7 +526,7 @@ int     vlistNsubtypes(int vlistID);
 
 void    vlistDefNtsteps(int vlistID, int nts);
 int     vlistNtsteps(int vlistID);
-int     vlistGridsizeMax(int vlistID);
+size_t  vlistGridsizeMax(int vlistID);
 int     vlistGrid(int vlistID, int index);
 int     vlistGridIndex(int vlistID, int gridID);
 void    vlistChangeGridIndex(int vlistID, int index, int gridID);
@@ -672,7 +672,7 @@ int     vlistInqVarTypeOfGeneratingProcess(int vlistID, int varID);
 void    vlistDefVarProductDefinitionTemplate(int vlistID, int varID, int productDefinitionTemplate);
 int     vlistInqVarProductDefinitionTemplate(int vlistID, int varID);
 
-int     vlistInqVarSize(int vlistID, int varID);
+size_t  vlistInqVarSize(int vlistID, int varID);
 
 void    vlistDefIndex(int vlistID, int varID, int levID, int index);
 int     vlistInqIndex(int vlistID, int varID, int levID);
@@ -745,7 +745,7 @@ int     gridInqMask(int gridID, int mask[]);
 void    gridPrint(int gridID, int opt);
 
 /*      gridCreate: Create a horizontal Grid */
-int     gridCreate(int gridtype, int size);
+int     gridCreate(int gridtype, size_t size);
 
 /*      gridDestroy: Destroy a horizontal Grid */
 void    gridDestroy(int gridID);
@@ -766,19 +766,19 @@ int     gridInqProjType(int gridID);
 int     gridInqType(int gridID);
 
 /*      gridInqSize: Get the size of a Grid */
-int     gridInqSize(int gridID);
+size_t  gridInqSize(int gridID);
 
 /*      gridDefXsize: Define the size of a X-axis */
-void    gridDefXsize(int gridID, int xsize);
+void    gridDefXsize(int gridID, size_t xsize);
 
 /*      gridInqXsize: Get the size of a X-axis */
-int     gridInqXsize(int gridID);
+size_t  gridInqXsize(int gridID);
 
 /*      gridDefYsize: Define the size of a Y-axis */
-void    gridDefYsize(int gridID, int ysize);
+void    gridDefYsize(int gridID, size_t ysize);
 
 /*      gridInqYsize: Get the size of a Y-axis */
-int     gridInqYsize(int gridID);
+size_t  gridInqYsize(int gridID);
 
 /*      gridDefNP: Define the number of parallels between a pole and the equator */
 void    gridDefNP(int gridID, int np);
@@ -790,25 +790,25 @@ int     gridInqNP(int gridID);
 void    gridDefXvals(int gridID, const double xvals[]);
 
 /*      gridInqXvals: Get all values of a X-axis */
-int     gridInqXvals(int gridID, double xvals[]);
+size_t  gridInqXvals(int gridID, double xvals[]);
 
 /*      gridInqXIsc: Find out whether X-coordinate is of type CHAR */
 int     gridInqXIsc(int gridID);
 
 /*      gridInqXCvals: Get strings from X-axis in case grid is of type GRID_CHARXY */
-int     gridInqXCvals(int gridID, char *xcvals[]);
+size_t  gridInqXCvals(int gridID, char *xcvals[]);
 
 /*      gridDefYvals: Define the values of a Y-axis */
 void    gridDefYvals(int gridID, const double yvals[]);
 
 /*      gridInqYvals: Get all values of a Y-axis */
-int     gridInqYvals(int gridID, double yvals[]);
+size_t  gridInqYvals(int gridID, double yvals[]);
 
 /*      gridInqYIsc: Find out whether Y-coordinate is of type CHAR */
 int     gridInqYIsc(int gridID);
 
 /*      gridInqYCvals: Get strings from Y-axis in case grid is of type GRID_CHARXY */
-int     gridInqYCvals(int gridID, char *ycvals[]);
+size_t  gridInqYCvals(int gridID, char *ycvals[]);
 
 /* CDI grid string key values */
 #define  CDI_KEY_XNAME       901  // X-axis name
@@ -893,10 +893,10 @@ void    gridDefDatatype(int gridID, int prec);
 int     gridInqDatatype(int gridID);
 
 /*      gridInqXval: Get one value of a X-axis */
-double  gridInqXval(int gridID, int index);
+double  gridInqXval(int gridID, size_t index);
 
 /*      gridInqYval: Get one value of a Y-axis */
-double  gridInqYval(int gridID, int index);
+double  gridInqYval(int gridID, size_t index);
 
 double  gridInqXinc(int gridID);
 double  gridInqYinc(int gridID);
@@ -966,13 +966,13 @@ int     gridInqNvertex(int gridID);
 void    gridDefXbounds(int gridID, const double xbounds[]);
 
 /*      gridInqXbounds: Get the bounds of a X-axis */
-int     gridInqXbounds(int gridID, double xbounds[]);
+size_t  gridInqXbounds(int gridID, double xbounds[]);
 
 /*      gridDefYbounds: Define the bounds of a Y-axis */
 void    gridDefYbounds(int gridID, const double ybounds[]);
 
 /*      gridInqYbounds: Get the bounds of a Y-axis */
-int     gridInqYbounds(int gridID, double ybounds[]);
+size_t  gridInqYbounds(int gridID, double ybounds[]);
 
 void    gridDefRowlon(int gridID, int nrowlon, const int rowlon[]);
 void    gridInqRowlon(int gridID, int rowlon[]);
@@ -1013,7 +1013,7 @@ void    zaxisPrint(int zaxisID);
 void    zaxisDefLevels(int zaxisID, const double levels[]);
 
 /*      zaxisDefCvals: Define area types of a Z-axis */
-void    zaxisDefCvals(int zaxisID, const char *cvals[], size_t clength);
+void    zaxisDefCvals(int zaxisID, const char *cvals[], int clength);
 
 /*      zaxisInqLevels: Get all levels of a Z-axis */
 int     zaxisInqLevels(int zaxisID, double levels[]);
diff --git a/libcdi/src/cdi.inc b/libcdi/src/cdi.inc
index bb59831..2769887 100644
--- a/libcdi/src/cdi.inc
+++ b/libcdi/src/cdi.inc
@@ -653,6 +653,10 @@
 !                                    (INTEGER         filetype)
       EXTERNAL        streamFilesuffix
 
+      INTEGER         streamNvals
+!                                    (INTEGER         streamID)
+      EXTERNAL        streamNvals
+
       INTEGER         streamInqNvars
 !                                    (INTEGER         streamID)
       EXTERNAL        streamInqNvars
diff --git a/libcdi/src/cdiFortran.c b/libcdi/src/cdiFortran.c
index 6b8e702..8de51ed 100644
--- a/libcdi/src/cdiFortran.c
+++ b/libcdi/src/cdiFortran.c
@@ -154,28 +154,105 @@ FCALLSCFUN2 (INT, streamInqTimestep, STREAMINQTIMESTEP, streaminqtimestep, INT,
 FCALLSCFUN1 (INT, streamInqCurTimestepID, STREAMINQCURTIMESTEPID, streaminqcurtimestepid, INT)
 FCALLSCFUN1 (STRING, streamFilename, STREAMFILENAME, streamfilename, INT)
 FCALLSCFUN1 (STRING, streamFilesuffix, STREAMFILESUFFIX, streamfilesuffix, INT)
+static int streamNvals_fwrap(int streamID)
+{
+  size_t v;
+  v = streamNvals(streamID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, streamNvals_fwrap, STREAMNVALS, streamnvals, INT)
 FCALLSCFUN1 (INT, streamInqNvars, STREAMINQNVARS, streaminqnvars, INT)
 
 /*  STREAM var I/O routines (random access)  */
 
-FCALLSCSUB4 (streamWriteVar, STREAMWRITEVAR, streamwritevar, INT, INT, DOUBLEV, INT)
-FCALLSCSUB4 (streamWriteVarF, STREAMWRITEVARF, streamwritevarf, INT, INT, FLOATV, INT)
-FCALLSCSUB4 (streamReadVar, STREAMREADVAR, streamreadvar, INT, INT, DOUBLEV, PINT)
-FCALLSCSUB4 (streamReadVarF, STREAMREADVARF, streamreadvarf, INT, INT, FLOATV, PINT)
-FCALLSCSUB5 (streamWriteVarSlice, STREAMWRITEVARSLICE, streamwritevarslice, INT, INT, INT, DOUBLEV, INT)
-FCALLSCSUB5 (streamWriteVarSliceF, STREAMWRITEVARSLICEF, streamwritevarslicef, INT, INT, INT, FLOATV, INT)
-FCALLSCSUB5 (streamReadVarSlice, STREAMREADVARSLICE, streamreadvarslice, INT, INT, INT, DOUBLEV, PINT)
-FCALLSCSUB5 (streamReadVarSliceF, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
-FCALLSCSUB5 (streamWriteVarChunk, STREAMWRITEVARCHUNK, streamwritevarchunk, INT, INT, INTVV, DOUBLEV, INT)
+static void streamWriteVar_fwrap(int streamID, int varID, const double data[], int nmiss)
+{
+  streamWriteVar(streamID, varID, data, (size_t)nmiss);
+}
+FCALLSCSUB4 (streamWriteVar_fwrap, STREAMWRITEVAR, streamwritevar, INT, INT, DOUBLEV, INT)
+static void streamWriteVarF_fwrap(int streamID, int varID, const float data[], int nmiss)
+{
+  streamWriteVarF(streamID, varID, data, (size_t)nmiss);
+}
+FCALLSCSUB4 (streamWriteVarF_fwrap, STREAMWRITEVARF, streamwritevarf, INT, INT, FLOATV, INT)
+static void streamReadVar_fwrap(int streamID, int varID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVar(streamID, varID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB4 (streamReadVar_fwrap, STREAMREADVAR, streamreadvar, INT, INT, DOUBLEV, PINT)
+static void streamReadVarF_fwrap(int streamID, int varID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarF(streamID, varID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB4 (streamReadVarF_fwrap, STREAMREADVARF, streamreadvarf, INT, INT, FLOATV, PINT)
+static void streamWriteVarSlice_fwrap(int streamID, int varID, int levelID, const double data[], int nmiss)
+{
+  streamWriteVarSlice(streamID, varID, levelID, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarSlice_fwrap, STREAMWRITEVARSLICE, streamwritevarslice, INT, INT, INT, DOUBLEV, INT)
+static void streamWriteVarSliceF_fwrap(int streamID, int varID, int levelID, const float data[], int nmiss)
+{
+  streamWriteVarSliceF(streamID, varID, levelID, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarSliceF_fwrap, STREAMWRITEVARSLICEF, streamwritevarslicef, INT, INT, INT, FLOATV, INT)
+static void streamReadVarSlice_fwrap(int streamID, int varID, int levelID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarSlice(streamID, varID, levelID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB5 (streamReadVarSlice_fwrap, STREAMREADVARSLICE, streamreadvarslice, INT, INT, INT, DOUBLEV, PINT)
+static void streamReadVarSliceF_fwrap(int streamID, int varID, int levelID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarSliceF(streamID, varID, levelID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB5 (streamReadVarSliceF_fwrap, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
+static void streamWriteVarChunk_fwrap(int streamID, int varID, const int rect[3][2], const double data[], int nmiss)
+{
+  streamWriteVarChunk(streamID, varID, rect, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarChunk_fwrap, STREAMWRITEVARCHUNK, streamwritevarchunk, INT, INT, INTVV, DOUBLEV, INT)
 
 /*  STREAM record I/O routines (sequential access)  */
 
 FCALLSCSUB3 (streamDefRecord, STREAMDEFRECORD, streamdefrecord, INT, INT, INT)
 FCALLSCSUB3 (streamInqRecord, STREAMINQRECORD, streaminqrecord, INT, PINT, PINT)
-FCALLSCSUB3 (streamWriteRecord, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
-FCALLSCSUB3 (streamWriteRecordF, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
-FCALLSCSUB3 (streamReadRecord, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
-FCALLSCSUB3 (streamReadRecordF, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
+static void streamWriteRecord_fwrap(int streamID, const double data[], int nmiss)
+{
+  streamWriteRecord(streamID, data, (size_t)nmiss);
+}
+FCALLSCSUB3 (streamWriteRecord_fwrap, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
+static void streamWriteRecordF_fwrap(int streamID, const float data[], int nmiss)
+{
+  streamWriteRecordF(streamID, data, (size_t)nmiss);
+}
+FCALLSCSUB3 (streamWriteRecordF_fwrap, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
+static void streamReadRecord_fwrap(int streamID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadRecord(streamID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB3 (streamReadRecord_fwrap, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
+static void streamReadRecordF_fwrap(int streamID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadRecordF(streamID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB3 (streamReadRecordF_fwrap, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
 FCALLSCSUB2 (streamCopyRecord, STREAMCOPYRECORD, streamcopyrecord, INT, INT)
 
 /*  File driven I/O (may yield better performance than using the streamXXX functions)  */
@@ -199,7 +276,13 @@ FCALLSCFUN1 (INT, vlistNzaxis, VLISTNZAXIS, vlistnzaxis, INT)
 FCALLSCFUN1 (INT, vlistNsubtypes, VLISTNSUBTYPES, vlistnsubtypes, INT)
 FCALLSCSUB2 (vlistDefNtsteps, VLISTDEFNTSTEPS, vlistdefntsteps, INT, INT)
 FCALLSCFUN1 (INT, vlistNtsteps, VLISTNTSTEPS, vlistntsteps, INT)
-FCALLSCFUN1 (INT, vlistGridsizeMax, VLISTGRIDSIZEMAX, vlistgridsizemax, INT)
+static int vlistGridsizeMax_fwrap(int vlistID)
+{
+  size_t v;
+  v = vlistGridsizeMax(vlistID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, vlistGridsizeMax_fwrap, VLISTGRIDSIZEMAX, vlistgridsizemax, INT)
 FCALLSCFUN2 (INT, vlistGrid, VLISTGRID, vlistgrid, INT, INT)
 FCALLSCFUN2 (INT, vlistGridIndex, VLISTGRIDINDEX, vlistgridindex, INT, INT)
 FCALLSCSUB3 (vlistChangeGridIndex, VLISTCHANGEGRIDINDEX, vlistchangegridindex, INT, INT, INT)
@@ -283,7 +366,13 @@ FCALLSCSUB3 (vlistDefVarTypeOfGeneratingProcess, VLISTDEFVARTYPEOFGENERATINGPROC
 FCALLSCFUN2 (INT, vlistInqVarTypeOfGeneratingProcess, VLISTINQVARTYPEOFGENERATINGPROCESS, vlistinqvartypeofgeneratingprocess, INT, INT)
 FCALLSCSUB3 (vlistDefVarProductDefinitionTemplate, VLISTDEFVARPRODUCTDEFINITIONTEMPLATE, vlistdefvarproductdefinitiontemplate, INT, INT, INT)
 FCALLSCFUN2 (INT, vlistInqVarProductDefinitionTemplate, VLISTINQVARPRODUCTDEFINITIONTEMPLATE, vlistinqvarproductdefinitiontemplate, INT, INT)
-FCALLSCFUN2 (INT, vlistInqVarSize, VLISTINQVARSIZE, vlistinqvarsize, INT, INT)
+static int vlistInqVarSize_fwrap(int vlistID, int varID)
+{
+  size_t v;
+  v = vlistInqVarSize(vlistID, varID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, vlistInqVarSize_fwrap, VLISTINQVARSIZE, vlistinqvarsize, INT, INT)
 FCALLSCSUB4 (vlistDefIndex, VLISTDEFINDEX, vlistdefindex, INT, INT, INT, INT)
 FCALLSCFUN3 (INT, vlistInqIndex, VLISTINQINDEX, vlistinqindex, INT, INT, INT)
 FCALLSCSUB4 (vlistDefFlag, VLISTDEFFLAG, vlistdefflag, INT, INT, INT, INT)
@@ -328,25 +417,69 @@ FCALLSCFUN2 (INT, gridInqMaskGME, GRIDINQMASKGME, gridinqmaskgme, INT, INTV)
 FCALLSCSUB2 (gridDefMask, GRIDDEFMASK, griddefmask, INT, INTV)
 FCALLSCFUN2 (INT, gridInqMask, GRIDINQMASK, gridinqmask, INT, INTV)
 FCALLSCSUB2 (gridPrint, GRIDPRINT, gridprint, INT, INT)
-FCALLSCFUN2 (INT, gridCreate, GRIDCREATE, gridcreate, INT, INT)
+static int gridCreate_fwrap(int gridtype, int size)
+{
+  int v;
+  v = gridCreate(gridtype, (size_t)size);
+  return v;
+}
+FCALLSCFUN2 (INT, gridCreate_fwrap, GRIDCREATE, gridcreate, INT, INT)
 FCALLSCSUB1 (gridDestroy, GRIDDESTROY, griddestroy, INT)
 FCALLSCFUN1 (INT, gridDuplicate, GRIDDUPLICATE, gridduplicate, INT)
 FCALLSCSUB2 (gridDefProj, GRIDDEFPROJ, griddefproj, INT, INT)
 FCALLSCFUN1 (INT, gridInqProj, GRIDINQPROJ, gridinqproj, INT)
 FCALLSCFUN1 (INT, gridInqProjType, GRIDINQPROJTYPE, gridinqprojtype, INT)
 FCALLSCFUN1 (INT, gridInqType, GRIDINQTYPE, gridinqtype, INT)
-FCALLSCFUN1 (INT, gridInqSize, GRIDINQSIZE, gridinqsize, INT)
-FCALLSCSUB2 (gridDefXsize, GRIDDEFXSIZE, griddefxsize, INT, INT)
-FCALLSCFUN1 (INT, gridInqXsize, GRIDINQXSIZE, gridinqxsize, INT)
-FCALLSCSUB2 (gridDefYsize, GRIDDEFYSIZE, griddefysize, INT, INT)
-FCALLSCFUN1 (INT, gridInqYsize, GRIDINQYSIZE, gridinqysize, INT)
+static int gridInqSize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqSize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqSize_fwrap, GRIDINQSIZE, gridinqsize, INT)
+static void gridDefXsize_fwrap(int gridID, int xsize)
+{
+  gridDefXsize(gridID, (size_t)xsize);
+}
+FCALLSCSUB2 (gridDefXsize_fwrap, GRIDDEFXSIZE, griddefxsize, INT, INT)
+static int gridInqXsize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqXsize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqXsize_fwrap, GRIDINQXSIZE, gridinqxsize, INT)
+static void gridDefYsize_fwrap(int gridID, int ysize)
+{
+  gridDefYsize(gridID, (size_t)ysize);
+}
+FCALLSCSUB2 (gridDefYsize_fwrap, GRIDDEFYSIZE, griddefysize, INT, INT)
+static int gridInqYsize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqYsize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqYsize_fwrap, GRIDINQYSIZE, gridinqysize, INT)
 FCALLSCSUB2 (gridDefNP, GRIDDEFNP, griddefnp, INT, INT)
 FCALLSCFUN1 (INT, gridInqNP, GRIDINQNP, gridinqnp, INT)
 FCALLSCSUB2 (gridDefXvals, GRIDDEFXVALS, griddefxvals, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqXvals, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV)
+static int gridInqXvals_fwrap(int gridID, double xvals[])
+{
+  size_t v;
+  v = gridInqXvals(gridID, xvals);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqXvals_fwrap, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV)
 FCALLSCFUN1 (INT, gridInqXIsc, GRIDINQXISC, gridinqxisc, INT)
 FCALLSCSUB2 (gridDefYvals, GRIDDEFYVALS, griddefyvals, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqYvals, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
+static int gridInqYvals_fwrap(int gridID, double yvals[])
+{
+  size_t v;
+  v = gridInqYvals(gridID, yvals);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqYvals_fwrap, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
 FCALLSCFUN1 (INT, gridInqYIsc, GRIDINQYISC, gridinqyisc, INT)
 
 /*  CDI grid string key values  */
@@ -374,8 +507,20 @@ FCALLSCSUB2 (gridInqXstdname, GRIDINQXSTDNAME, gridinqxstdname, INT, PSTRING)
 FCALLSCSUB2 (gridInqYstdname, GRIDINQYSTDNAME, gridinqystdname, INT, PSTRING)
 FCALLSCSUB2 (gridDefDatatype, GRIDDEFDATATYPE, griddefdatatype, INT, INT)
 FCALLSCFUN1 (INT, gridInqDatatype, GRIDINQDATATYPE, gridinqdatatype, INT)
-FCALLSCFUN2 (DOUBLE, gridInqXval, GRIDINQXVAL, gridinqxval, INT, INT)
-FCALLSCFUN2 (DOUBLE, gridInqYval, GRIDINQYVAL, gridinqyval, INT, INT)
+static double gridInqXval_fwrap(int gridID, int index)
+{
+  double v;
+  v = gridInqXval(gridID, (size_t)index);
+  return v;
+}
+FCALLSCFUN2 (DOUBLE, gridInqXval_fwrap, GRIDINQXVAL, gridinqxval, INT, INT)
+static double gridInqYval_fwrap(int gridID, int index)
+{
+  double v;
+  v = gridInqYval(gridID, (size_t)index);
+  return v;
+}
+FCALLSCFUN2 (DOUBLE, gridInqYval_fwrap, GRIDINQYVAL, gridinqyval, INT, INT)
 FCALLSCFUN1 (DOUBLE, gridInqXinc, GRIDINQXINC, gridinqxinc, INT)
 FCALLSCFUN1 (DOUBLE, gridInqYinc, GRIDINQYINC, gridinqyinc, INT)
 FCALLSCFUN1 (INT, gridIsCircular, GRIDISCIRCULAR, gridiscircular, INT)
@@ -413,9 +558,21 @@ FCALLSCFUN1 (INT, gridHasArea, GRIDHASAREA, gridhasarea, INT)
 FCALLSCSUB2 (gridDefNvertex, GRIDDEFNVERTEX, griddefnvertex, INT, INT)
 FCALLSCFUN1 (INT, gridInqNvertex, GRIDINQNVERTEX, gridinqnvertex, INT)
 FCALLSCSUB2 (gridDefXbounds, GRIDDEFXBOUNDS, griddefxbounds, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqXbounds, GRIDINQXBOUNDS, gridinqxbounds, INT, DOUBLEV)
+static int gridInqXbounds_fwrap(int gridID, double xbounds[])
+{
+  size_t v;
+  v = gridInqXbounds(gridID, xbounds);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqXbounds_fwrap, GRIDINQXBOUNDS, gridinqxbounds, INT, DOUBLEV)
 FCALLSCSUB2 (gridDefYbounds, GRIDDEFYBOUNDS, griddefybounds, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqYbounds, GRIDINQYBOUNDS, gridinqybounds, INT, DOUBLEV)
+static int gridInqYbounds_fwrap(int gridID, double ybounds[])
+{
+  size_t v;
+  v = gridInqYbounds(gridID, ybounds);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqYbounds_fwrap, GRIDINQYBOUNDS, gridinqybounds, INT, DOUBLEV)
 FCALLSCSUB3 (gridDefRowlon, GRIDDEFROWLON, griddefrowlon, INT, INT, INTV)
 FCALLSCSUB2 (gridInqRowlon, GRIDINQROWLON, gridinqrowlon, INT, INTV)
 FCALLSCSUB2 (gridChangeType, GRIDCHANGETYPE, gridchangetype, INT, INT)
diff --git a/libcdi/src/cdi_int.h b/libcdi/src/cdi_int.h
index 7a0fd20..76fe7f5 100644
--- a/libcdi/src/cdi_int.h
+++ b/libcdi/src/cdi_int.h
@@ -10,6 +10,7 @@
 #include <stdbool.h>
 #include <string.h>
 #include <errno.h>
+#include <limits.h>
 #include <math.h>
 #include <sys/types.h>
 
@@ -242,7 +243,7 @@ typedef struct {
   int         fileID;
   int         filemode;
   int         nrecs;        /* number of records                  */
-  off_t       numvals;
+  size_t      numvals;
   char       *filename;
   Record     *record;
   svarinfo_t *vars;
@@ -443,11 +444,11 @@ void
 cdiStreamDefVlist_(int streamID, int vlistID);
 
 int
-cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss);
+cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss);
 
 void
 cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss);
+                        const int rect[][2], const void *data, size_t nmiss);
 void
 cdiStreamCloseDefaultDelegate(stream_t *streamptr,
                               int recordBufIsToBeDeleted);
@@ -481,6 +482,13 @@ void cdiDefTableID(int tableID);
 void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
 void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
 
+static inline
+void cdi_check_gridsize_int_limit(const char *format, size_t gridsize)
+{
+  if ( gridsize > INT_MAX ) Error("%s format grid size (%zu) limit exceeded (%zu)!", format, gridsize, INT_MAX);
+}
+
+
 #if defined (__cplusplus)
 }
 #endif
diff --git a/libcdi/src/cdilib.c b/libcdi/src/cdilib.c
index 9295e75..5553192 100644
--- a/libcdi/src/cdilib.c
+++ b/libcdi/src/cdilib.c
@@ -1,7 +1,7 @@
 
-/* Automatically generated by m214003 at 2016-06-07, do not edit */
+/* Automatically generated by ram at 2017-11-06, do not edit */
 
-/* CDILIB_VERSION="1.7.2" */
+/* CDILIB_VERSION="1.9.2" */
 
 #ifdef _ARCH_PWR6
 #pragma options nostrict
@@ -58,8 +58,8 @@
 #  define  HAVE_LIBIEG       1
 #endif
 
-#ifndef _ERROR_H
-#define _ERROR_H
+#ifndef ERROR_H
+#define ERROR_H
 
 #include <stdarg.h>
 #include <stdlib.h>
@@ -130,7 +130,7 @@ cdiAbortC_serial(const char *caller, const char *filename,
 }
 #endif
 
-#endif  /* _ERROR_H */
+#endif  /* ERROR_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -157,102 +157,130 @@ extern "C" {
 #endif
 
 
-#define  CDI_MAX_NAME           256   /* max length of a name                 */
+#define  CDI_MAX_NAME             256   // max length of a name
 
-#define  CDI_UNDEFID             -1
-#define  CDI_GLOBAL              -1   /* Global var ID for vlist              */
+#define  CDI_UNDEFID               -1
+#define  CDI_GLOBAL                -1   // Global var ID for vlist
 
 /* Byte order */
 
-#define  CDI_BIGENDIAN            0   /* Byte order BIGENDIAN                 */
-#define  CDI_LITTLEENDIAN         1   /* Byte order LITTLEENDIAN              */
-#define  CDI_PDPENDIAN            2
+#define  CDI_BIGENDIAN              0   // Byte order BIGENDIAN
+#define  CDI_LITTLEENDIAN           1   // Byte order LITTLEENDIAN
+#define  CDI_PDPENDIAN              2
 
-#define  CDI_REAL                 1   /* Real numbers                         */
-#define  CDI_COMP                 2   /* Complex numbers                      */
-#define  CDI_BOTH                 3   /* Both numbers                         */
+#define  CDI_REAL                   1   // Real numbers
+#define  CDI_COMP                   2   // Complex numbers
+#define  CDI_BOTH                   3   // Both numbers
 
 /* Error identifier */
 
-#define	 CDI_NOERR        	  0   /* No Error                             */
-#define  CDI_EEOF                -1   /* The end of file was encountered      */
-#define  CDI_ESYSTEM            -10   /* Operating system error               */
-#define  CDI_EINVAL             -20   /* Invalid argument                     */
-#define  CDI_EUFTYPE            -21   /* Unsupported file type                */
-#define  CDI_ELIBNAVAIL         -22   /* xxx library not available            */
-#define  CDI_EUFSTRUCT          -23   /* Unsupported file structure           */
-#define  CDI_EUNC4              -24   /* Unsupported NetCDF4 structure        */
-#define  CDI_ELIMIT             -99   /* Internal limits exceeded             */
+#define	 CDI_NOERR        	    0   // No Error
+#define  CDI_EEOF                  -1   // The end of file was encountered
+#define  CDI_ESYSTEM              -10   // Operating system error
+#define  CDI_EINVAL               -20   // Invalid argument
+#define  CDI_EISDIR               -21   // Is a directory
+#define  CDI_EISEMPTY             -22   // Is empty
+#define  CDI_EUFTYPE              -23   // Unsupported file type
+#define  CDI_ELIBNAVAIL           -24   // xxx library not available
+#define  CDI_EUFSTRUCT            -25   // Unsupported file structure
+#define  CDI_EUNC4                -26   // Unsupported NetCDF4 structure
+#define  CDI_EDIMSIZE             -27   // Invalid dimension size
+#define  CDI_ELIMIT               -99   // Internal limits exceeded
 
 /* File types */
 
-#define  FILETYPE_UNDEF          -1   /* Unknown/not yet defined file type */
-#define  FILETYPE_GRB             1   /* File type GRIB                       */
-#define  FILETYPE_GRB2            2   /* File type GRIB version 2             */
-#define  FILETYPE_NC              3   /* File type NetCDF                     */
-#define  FILETYPE_NC2             4   /* File type NetCDF version 2 (64-bit)  */
-#define  FILETYPE_NC4             5   /* File type NetCDF version 4           */
-#define  FILETYPE_NC4C            6   /* File type NetCDF version 4 (classic) */
-#define  FILETYPE_SRV             7   /* File type SERVICE                    */
-#define  FILETYPE_EXT             8   /* File type EXTRA                      */
-#define  FILETYPE_IEG             9   /* File type IEG                        */
+#define  CDI_FILETYPE_GRB           1   // File type GRIB
+#define  CDI_FILETYPE_GRB2          2   // File type GRIB version 2
+#define  CDI_FILETYPE_NC            3   // File type NetCDF
+#define  CDI_FILETYPE_NC2           4   // File type NetCDF version 2 (64-bit offset)
+#define  CDI_FILETYPE_NC4           5   // File type NetCDF version 4
+#define  CDI_FILETYPE_NC4C          6   // File type NetCDF version 4 (classic)
+#define  CDI_FILETYPE_NC5           7   // File type NetCDF version 5 (64-bit data)
+#define  CDI_FILETYPE_SRV           8   // File type SERVICE
+#define  CDI_FILETYPE_EXT           9   // File type EXTRA
+#define  CDI_FILETYPE_IEG          10   // File type IEG
+
+#define  FILETYPE_GRB           1
+#define  FILETYPE_GRB2          2
+#define  FILETYPE_NC            3
+#define  FILETYPE_NC2           4
+#define  FILETYPE_NC4           5
+#define  FILETYPE_NC4C          6
+#define  FILETYPE_SRV           7
+#define  FILETYPE_EXT           8
+#define  FILETYPE_IEG           9
 
 /* Compress types */
 
-#define  COMPRESS_NONE            0
-#define  COMPRESS_SZIP            1
-#define  COMPRESS_GZIP            2
-#define  COMPRESS_BZIP2           3
-#define  COMPRESS_ZIP             4
-#define  COMPRESS_JPEG            5
+#define  CDI_COMPRESS_NONE          0
+#define  CDI_COMPRESS_SZIP          1
+#define  CDI_COMPRESS_GZIP          2
+#define  CDI_COMPRESS_BZIP2         3
+#define  CDI_COMPRESS_ZIP           4
+#define  CDI_COMPRESS_JPEG          5
 
 /* external data types */
 
+#define  CDI_DATATYPE_PACK          0
+#define  CDI_DATATYPE_PACK1         1
+#define  CDI_DATATYPE_PACK2         2
+#define  CDI_DATATYPE_PACK3         3
+#define  CDI_DATATYPE_PACK4         4
+#define  CDI_DATATYPE_PACK5         5
+#define  CDI_DATATYPE_PACK6         6
+#define  CDI_DATATYPE_PACK7         7
+#define  CDI_DATATYPE_PACK8         8
+#define  CDI_DATATYPE_PACK9         9
+#define  CDI_DATATYPE_PACK10       10
+#define  CDI_DATATYPE_PACK11       11
+#define  CDI_DATATYPE_PACK12       12
+#define  CDI_DATATYPE_PACK13       13
+#define  CDI_DATATYPE_PACK14       14
+#define  CDI_DATATYPE_PACK15       15
+#define  CDI_DATATYPE_PACK16       16
+#define  CDI_DATATYPE_PACK17       17
+#define  CDI_DATATYPE_PACK18       18
+#define  CDI_DATATYPE_PACK19       19
+#define  CDI_DATATYPE_PACK20       20
+#define  CDI_DATATYPE_PACK21       21
+#define  CDI_DATATYPE_PACK22       22
+#define  CDI_DATATYPE_PACK23       23
+#define  CDI_DATATYPE_PACK24       24
+#define  CDI_DATATYPE_PACK25       25
+#define  CDI_DATATYPE_PACK26       26
+#define  CDI_DATATYPE_PACK27       27
+#define  CDI_DATATYPE_PACK28       28
+#define  CDI_DATATYPE_PACK29       29
+#define  CDI_DATATYPE_PACK30       30
+#define  CDI_DATATYPE_PACK31       31
+#define  CDI_DATATYPE_PACK32       32
+#define  CDI_DATATYPE_CPX32        64
+#define  CDI_DATATYPE_CPX64       128
+#define  CDI_DATATYPE_FLT32       132
+#define  CDI_DATATYPE_FLT64       164
+#define  CDI_DATATYPE_INT8        208
+#define  CDI_DATATYPE_INT16       216
+#define  CDI_DATATYPE_INT32       232
+#define  CDI_DATATYPE_UINT8       308
+#define  CDI_DATATYPE_UINT16      316
+#define  CDI_DATATYPE_UINT32      332
+
 #define  DATATYPE_PACK            0
-#define  DATATYPE_PACK1           1
-#define  DATATYPE_PACK2           2
-#define  DATATYPE_PACK3           3
-#define  DATATYPE_PACK4           4
-#define  DATATYPE_PACK5           5
-#define  DATATYPE_PACK6           6
-#define  DATATYPE_PACK7           7
 #define  DATATYPE_PACK8           8
-#define  DATATYPE_PACK9           9
-#define  DATATYPE_PACK10         10
-#define  DATATYPE_PACK11         11
-#define  DATATYPE_PACK12         12
-#define  DATATYPE_PACK13         13
-#define  DATATYPE_PACK14         14
-#define  DATATYPE_PACK15         15
 #define  DATATYPE_PACK16         16
-#define  DATATYPE_PACK17         17
-#define  DATATYPE_PACK18         18
-#define  DATATYPE_PACK19         19
-#define  DATATYPE_PACK20         20
-#define  DATATYPE_PACK21         21
-#define  DATATYPE_PACK22         22
-#define  DATATYPE_PACK23         23
 #define  DATATYPE_PACK24         24
-#define  DATATYPE_PACK25         25
-#define  DATATYPE_PACK26         26
-#define  DATATYPE_PACK27         27
-#define  DATATYPE_PACK28         28
-#define  DATATYPE_PACK29         29
-#define  DATATYPE_PACK30         30
-#define  DATATYPE_PACK31         31
-#define  DATATYPE_PACK32         32
-#define  DATATYPE_CPX32          64
-#define  DATATYPE_CPX64         128
 #define  DATATYPE_FLT32         132
 #define  DATATYPE_FLT64         164
-#define  DATATYPE_INT8          208
-#define  DATATYPE_INT16         216
 #define  DATATYPE_INT32         232
-#define  DATATYPE_UINT8         308
-#define  DATATYPE_UINT16        316
-#define  DATATYPE_UINT32        332
 
 /* internal data types */
+#define  CDI_DATATYPE_INT         251
+#define  CDI_DATATYPE_FLT         252
+#define  CDI_DATATYPE_TXT         253
+#define  CDI_DATATYPE_CPX         254
+#define  CDI_DATATYPE_UCHAR       255
+#define  CDI_DATATYPE_LONG        256
+
 #define  DATATYPE_INT           251
 #define  DATATYPE_FLT           252
 #define  DATATYPE_TXT           253
@@ -262,9 +290,9 @@ extern "C" {
 
 /* Chunks */
 
-#define  CHUNK_AUTO                 1  /* use default chunk size                                */
-#define  CHUNK_GRID                 2
-#define  CHUNK_LINES                3
+#define  CDI_CHUNK_AUTO             1  /* use default chunk size                                */
+#define  CDI_CHUNK_GRID             2
+#define  CDI_CHUNK_LINES            3
 
 /* GRID types */
 
@@ -279,10 +307,13 @@ extern "C" {
 #define  GRID_UNSTRUCTURED          9  /* General unstructured grid                             */
 #define  GRID_CURVILINEAR          10  /* Curvilinear grid                                      */
 #define  GRID_LCC                  11  /* Lambert Conformal Conic (GRIB)                        */
-#define  GRID_LCC2                 12  /* Lambert Conformal Conic (PROJ)                        */
-#define  GRID_LAEA                 13  /* Lambert Azimuthal Equal Area                          */
-#define  GRID_SINUSOIDAL           14  /* Sinusoidal                                            */
-#define  GRID_PROJECTION           15  /* Projected coordiantes                                 */
+#define  GRID_PROJECTION           12  /* Projected coordinates                                 */
+#define  GRID_CHARXY               13  /* One horizontal character dimension                    */
+
+#define  CDI_PROJ_RLL              21  /* Rotated Latitude Longitude                            */
+#define  CDI_PROJ_LCC              22  /* Lambert Conformal Conic                               */
+#define  CDI_PROJ_LAEA             23  /* Lambert Azimuthal Equal Area                          */
+#define  CDI_PROJ_SINU             24  /* Sinusoidal                                            */
 
 /* ZAXIS types */
 
@@ -312,6 +343,7 @@ extern "C" {
 #define  ZAXIS_SEDIMENT_BOTTOM_TW  23  /* Bottom Of Sediment Layer Penetrated By Thermal Wave   */
 #define  ZAXIS_MIX_LAYER           24  /* Mixing Layer                                          */
 #define  ZAXIS_REFERENCE           25  /* zaxis reference number                                */
+#define  ZAXIS_CHAR                26  /* Area types                                            */
 
 /* SUBTYPE types */
 
@@ -335,12 +367,12 @@ typedef struct  {
 
 /* TIME types */
 
-#define  TIME_CONSTANT              0  /* obsolate, use TSTEP_CONSTANT                          */
-#define  TIME_VARIABLE              1  /* obsolate, use TSTEP_INSTANT                           */
+#define  TIME_CONSTANT              0  /* Time constant              */
+#define  TIME_VARYING               1  /* Time varying               */
+#define  TIME_VARIABLE              1  /* obsolate, use TIME_VARYING */
 
 /* TSTEP types */
 
-#define  TSTEP_CONSTANT             0  /* Constant            */
 #define  TSTEP_INSTANT              1  /* Instant             */
 #define  TSTEP_AVG                  2  /* Average             */
 #define  TSTEP_ACCUM                3  /* Accumulation        */
@@ -378,11 +410,12 @@ typedef struct  {
 /* CALENDAR types */
 
 #define  CALENDAR_STANDARD        0  /* don't change this value (used also in cgribexlib)! */
-#define  CALENDAR_PROLEPTIC       1
-#define  CALENDAR_360DAYS         2
-#define  CALENDAR_365DAYS         3
-#define  CALENDAR_366DAYS         4
-#define  CALENDAR_NONE            5
+#define  CALENDAR_GREGORIAN       1
+#define  CALENDAR_PROLEPTIC       2
+#define  CALENDAR_360DAYS         3
+#define  CALENDAR_365DAYS         4
+#define  CALENDAR_366DAYS         5
+#define  CALENDAR_NONE            6
 
 /* number of unsigned char needed to store UUID */
 #define  CDI_UUID_SIZE           16
@@ -495,39 +528,39 @@ int     streamInqCurTimestepID(int streamID);
 const char *streamFilename(int streamID);
 const char *streamFilesuffix(int filetype);
 
-off_t   streamNvals(int streamID);
+size_t  streamNvals(int streamID);
 
-int     streamInqNvars ( int streamID );
+int     streamInqNvars(int streamID);
 
-/* STREAM var I/O routines */
+/* STREAM var I/O routines (random access) */
 
 /*      streamWriteVar: Write a variable */
-void    streamWriteVar(int streamID, int varID, const double data[], int nmiss);
-void    streamWriteVarF(int streamID, int varID, const float data[], int nmiss);
+void    streamWriteVar(int streamID, int varID, const double data[], size_t nmiss);
+void    streamWriteVarF(int streamID, int varID, const float data[], size_t nmiss);
 
 /*      streamReadVar: Read a variable */
-void    streamReadVar(int streamID, int varID, double data[], int *nmiss);
-void    streamReadVarF(int streamID, int varID, float data[], int *nmiss);
+void    streamReadVar(int streamID, int varID, double data[], size_t *nmiss);
+void    streamReadVarF(int streamID, int varID, float data[], size_t *nmiss);
 
 /*      streamWriteVarSlice: Write a horizontal slice of a variable */
-void    streamWriteVarSlice(int streamID, int varID, int levelID, const double data[], int nmiss);
-void    streamWriteVarSliceF(int streamID, int varID, int levelID, const float data[], int nmiss);
+void    streamWriteVarSlice(int streamID, int varID, int levelID, const double data[], size_t nmiss);
+void    streamWriteVarSliceF(int streamID, int varID, int levelID, const float data[], size_t nmiss);
 
 /*      streamReadVarSlice: Read a horizontal slice of a variable */
-void    streamReadVarSlice(int streamID, int varID, int levelID, double data[], int *nmiss);
-void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[], int *nmiss);
+void    streamReadVarSlice(int streamID, int varID, int levelID, double data[], size_t *nmiss);
+void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[], size_t *nmiss);
 
-void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], int nmiss);
+void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], size_t nmiss);
 
 
-/* STREAM record I/O routines */
+/* STREAM record I/O routines (sequential access) */
 
 void    streamDefRecord(int streamID, int  varID, int  levelID);
 void    streamInqRecord(int streamID, int *varID, int *levelID);
-void    streamWriteRecord(int streamID, const double data[], int nmiss);
-void    streamWriteRecordF(int streamID, const float data[], int nmiss);
-void    streamReadRecord(int streamID, double data[], int *nmiss);
-void    streamReadRecordF(int streamID, float data[], int *nmiss);
+void    streamWriteRecord(int streamID, const double data[], size_t nmiss);
+void    streamWriteRecordF(int streamID, const float data[], size_t nmiss);
+void    streamReadRecord(int streamID, double data[], size_t *nmiss);
+void    streamReadRecordF(int streamID, float data[], size_t *nmiss);
 void    streamCopyRecord(int streamIDdest, int streamIDsrc);
 
 void    streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum);
@@ -635,7 +668,7 @@ int     vlistNsubtypes(int vlistID);
 
 void    vlistDefNtsteps(int vlistID, int nts);
 int     vlistNtsteps(int vlistID);
-int     vlistGridsizeMax(int vlistID);
+size_t  vlistGridsizeMax(int vlistID);
 int     vlistGrid(int vlistID, int index);
 int     vlistGridIndex(int vlistID, int gridID);
 void    vlistChangeGridIndex(int vlistID, int index, int gridID);
@@ -665,21 +698,24 @@ int     vlistInqModel(int vlistID);
 /* VLIST VAR routines */
 
 /*      vlistDefVarTiles: Create a new tile-based variable */
-int     vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int tsteptype, int tilesetID);
+int     vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int timetype, int tilesetID);
 
 /*      vlistDefVar: Create a new variable */
-int     vlistDefVar(int vlistID, int gridID, int zaxisID, int tsteptype);
+int     vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype);
 
 void    vlistChangeVarGrid(int vlistID, int varID, int gridID);
 void    vlistChangeVarZaxis(int vlistID, int varID, int zaxisID);
 
-void    vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *tsteptype);
+void    vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *timetype);
 int     vlistInqVarGrid(int vlistID, int varID);
 int     vlistInqVarZaxis(int vlistID, int varID);
 
 /* used in MPIOM */
 int     vlistInqVarID(int vlistID, int code);
 
+void    vlistDefVarTimetype(int vlistID, int varID, int timetype);
+int     vlistInqVarTimetype(int vlistID, int varID);
+
 void    vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
 
 /*      vlistInqVarTsteptype: Get the timestep type of a Variable */
@@ -778,7 +814,7 @@ int     vlistInqVarTypeOfGeneratingProcess(int vlistID, int varID);
 void    vlistDefVarProductDefinitionTemplate(int vlistID, int varID, int productDefinitionTemplate);
 int     vlistInqVarProductDefinitionTemplate(int vlistID, int varID);
 
-int     vlistInqVarSize(int vlistID, int varID);
+size_t  vlistInqVarSize(int vlistID, int varID);
 
 void    vlistDefIndex(int vlistID, int varID, int levID, int index);
 int     vlistInqIndex(int vlistID, int varID, int levID);
@@ -810,32 +846,29 @@ double  vlistInqVarDblKey(int vlistID, int varID, const char *name);
 /* vlistInqVarIntKey: raw access to GRIB meta-data */
 int     vlistInqVarIntKey(int vlistID, int varID, const char *name);
 
-/* needed only for CDO operator after */
-const char *vlistInqVarNamePtr(int vlistID, int varID);
-const char *vlistInqVarLongnamePtr(int vlistID, int varID);
-const char *vlistInqVarUnitsPtr(int vlistID, int varID);
+/* CDI attributes */
 
-/* VLIST attributes */
+/*      cdiInqNatts: Get number of attributes assigned to this variable */
+int     cdiInqNatts(int cdiID, int varID, int *nattsp);
+/*      cdiInqAtt: Get information about an attribute */
+int     cdiInqAtt(int cdiID, int varID, int attrnum, char *name, int *typep, int *lenp);
+int     cdiDelAtt(int cdiID, int varID, const char *name);
 
-/*      vlistInqNatts: Get number of variable attributes assigned to this variable */
-int     vlistInqNatts(int vlistID, int varID, int *nattsp);
-/*      vlistInqAtt: Get information about an attribute */
-int     vlistInqAtt(int vlistID, int varID, int attrnum, char *name, int *typep, int *lenp);
-int     vlistDelAtt(int vlistID, int varID, const char *name);
+int     cdiCopyAtts(int cdiID1, int varID1, int cdiID2, int varID2);
 
-/*      vlistDefAttInt: Define an integer attribute */
-int     vlistDefAttInt(int vlistID, int varID, const char *name, int type, int len, const int ip[]);
-/*      vlistDefAttFlt: Define a floating point attribute */
-int     vlistDefAttFlt(int vlistID, int varID, const char *name, int type, int len, const double dp[]);
-/*      vlistDefAttTxt: Define a text attribute */
-int     vlistDefAttTxt(int vlistID, int varID, const char *name, int len, const char *tp_cbuf);
+/*      cdiDefAttInt: Define an integer attribute */
+int     cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int ip[]);
+/*      cdiDefAttFlt: Define a floating point attribute */
+int     cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double dp[]);
+/*      cdiDefAttTxt: Define a text attribute */
+int     cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp_cbuf);
 
-/*      vlistInqAttInt: Get the value(s) of an integer attribute */
-int     vlistInqAttInt(int vlistID, int varID, const char *name, int mlen, int ip[]);
-/*      vlistInqAttFlt: Get the value(s) of a floating point attribute */
-int     vlistInqAttFlt(int vlistID, int varID, const char *name, int mlen, double dp[]);
-/*      vlistInqAttTxt: Get the value(s) of a text attribute */
-int     vlistInqAttTxt(int vlistID, int varID, const char *name, int mlen, char *tp_cbuf);
+/*      cdiInqAttInt: Get the value(s) of an integer attribute */
+int     cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int ip[]);
+/*      cdiInqAttFlt: Get the value(s) of a floating point attribute */
+int     cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double dp[]);
+/*      cdiInqAttTxt: Get the value(s) of a text attribute */
+int     cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp_cbuf);
 
 
 /* GRID routines */
@@ -851,10 +884,10 @@ int     gridInqMaskGME(int gridID, int mask[]);
 void    gridDefMask(int gridID, const int mask[]);
 int     gridInqMask(int gridID, int mask[]);
 
-void    gridPrint(int gridID, int index, int opt);
+void    gridPrint(int gridID, int opt);
 
 /*      gridCreate: Create a horizontal Grid */
-int     gridCreate(int gridtype, int size);
+int     gridCreate(int gridtype, size_t size);
 
 /*      gridDestroy: Destroy a horizontal Grid */
 void    gridDestroy(int gridID);
@@ -862,23 +895,32 @@ void    gridDestroy(int gridID);
 /*      gridDuplicate: Duplicate a Grid */
 int     gridDuplicate(int gridID);
 
+/*      gridDefProj: Define the projection ID of a Grid */
+void    gridDefProj(int gridID, int projID);
+
+/*      gridInqProj: Get the projection ID of a Grid */
+int     gridInqProj(int gridID);
+
+/*      gridInqProjType: Get the projection type */
+int     gridInqProjType(int gridID);
+
 /*      gridInqType: Get the type of a Grid */
 int     gridInqType(int gridID);
 
 /*      gridInqSize: Get the size of a Grid */
-int     gridInqSize(int gridID);
+size_t  gridInqSize(int gridID);
 
 /*      gridDefXsize: Define the size of a X-axis */
-void    gridDefXsize(int gridID, int xsize);
+void    gridDefXsize(int gridID, size_t xsize);
 
 /*      gridInqXsize: Get the size of a X-axis */
-int     gridInqXsize(int gridID);
+size_t  gridInqXsize(int gridID);
 
 /*      gridDefYsize: Define the size of a Y-axis */
-void    gridDefYsize(int gridID, int ysize);
+void    gridDefYsize(int gridID, size_t ysize);
 
 /*      gridInqYsize: Get the size of a Y-axis */
-int     gridInqYsize(int gridID);
+size_t  gridInqYsize(int gridID);
 
 /*      gridDefNP: Define the number of parallels between a pole and the equator */
 void    gridDefNP(int gridID, int np);
@@ -890,30 +932,59 @@ int     gridInqNP(int gridID);
 void    gridDefXvals(int gridID, const double xvals[]);
 
 /*      gridInqXvals: Get all values of a X-axis */
-int     gridInqXvals(int gridID, double xvals[]);
+size_t  gridInqXvals(int gridID, double xvals[]);
+
+/*      gridInqXIsc: Find out whether X-coordinate is of type CHAR */
+int     gridInqXIsc(int gridID);
+
+/*      gridInqXCvals: Get strings from X-axis in case grid is of type GRID_CHARXY */
+size_t  gridInqXCvals(int gridID, char *xcvals[]);
 
 /*      gridDefYvals: Define the values of a Y-axis */
 void    gridDefYvals(int gridID, const double yvals[]);
 
 /*      gridInqYvals: Get all values of a Y-axis */
-int     gridInqYvals(int gridID, double yvals[]);
+size_t  gridInqYvals(int gridID, double yvals[]);
+
+/*      gridInqYIsc: Find out whether Y-coordinate is of type CHAR */
+int     gridInqYIsc(int gridID);
+
+/*      gridInqYCvals: Get strings from Y-axis in case grid is of type GRID_CHARXY */
+size_t  gridInqYCvals(int gridID, char *ycvals[]);
 
 /* CDI grid string key values */
-#define  CDI_GRID_XNAME      901  // X-axis name
-#define  CDI_GRID_YNAME      902  // Y-axis name
-#define  CDI_GRID_XDIMNAME   903  // X-axis dimension name
-#define  CDI_GRID_YDIMNAME   904  // Y-axis dimension name
-#define  CDI_GRID_VDIMNAME   905  // Vertex dimension name
-#define  CDI_GRID_XLONGNAME  906  // X-axis longname
-#define  CDI_GRID_YLONGNAME  907  // Y-axis longname
-#define  CDI_GRID_XUNITS     908  // X-axis units
-#define  CDI_GRID_YUNITS     909  // Y-axis units
-
-//      cdiGridDefString: Define a CDI grid string value from a key
-int     cdiGridDefString(int gridID, int key, int size, const char *mesg);
-
-//      cdiGridInqString: Get a CDI grid string value from a key
-int     cdiGridInqString(int gridID, int key, int size, char *mesg);
+#define  CDI_KEY_XNAME       901  // X-axis name
+#define  CDI_KEY_XDIMNAME    902  // X-axis dimension name
+#define  CDI_KEY_XLONGNAME   903  // X-axis longname
+#define  CDI_KEY_XUNITS      904  // X-axis units
+#define  CDI_KEY_YNAME       911  // Y-axis name
+#define  CDI_KEY_YDIMNAME    912  // Y-axis dimension name
+#define  CDI_KEY_YLONGNAME   913  // Y-axis longname
+#define  CDI_KEY_YUNITS      914  // Y-axis units
+#define  CDI_KEY_VDIMNAME    920  // Vertex dimension name
+#define  CDI_KEY_MAPPING     921  // Grid mapping var name
+#define  CDI_KEY_MAPNAME     922  // Grid mapping name
+
+/* CDI zaxis string key values */
+#define  CDI_KEY_NAME        941  // Z-axis name
+#define  CDI_KEY_DIMNAME     942  // Z-axis dimension name
+#define  CDI_KEY_LONGNAME    943  // Z-axis longname
+#define  CDI_KEY_UNITS       944  // Z-axis units
+#define  CDI_KEY_PSNAME      950  // Z-axis surface pressure name
+#define  CDI_KEY_P0NAME      951  // Z-axis reference pressure name
+#define  CDI_KEY_P0VALUE     952  // Z-axis reference pressure in Pa
+
+//      cdiGridDefKeyStr: Define a CDI grid string value from a key
+int     cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg);
+
+//      cdiGridInqKeyStr: Get a CDI grid string value from a key
+int     cdiGridInqKeyStr(int gridID, int key, int size, char *mesg);
+
+//      cdiZaxisDefKeyFlt: Define a CDI Z-axis floating point value from a key
+int     cdiZaxisDefKeyFlt(int zaxisID, int key, double value);
+
+//      cdiZaxisInqKeyFlt: Get a CDI Z-axis floating point value from a key
+int     cdiZaxisInqKeyFlt(int zaxisID, int key, double *value);
 
 /*      gridDefXname: Define the name of a X-axis */
 void    gridDefXname(int gridID, const char *xname);
@@ -957,40 +1028,25 @@ void    gridInqXstdname(int gridID, char *xstdname);
 /*      gridInqYstdname: Get the standard name of a Y-axis */
 void    gridInqYstdname(int gridID, char *ystdname);
 
-/*      gridDefPrec: Define the precision of a Grid */
-void    gridDefPrec(int gridID, int prec);
+/*      gridDefDatatype: Define the data type of a Grid */
+void    gridDefDatatype(int gridID, int prec);
 
-/*      gridInqPrec: Get the precision of a Grid */
-int     gridInqPrec(int gridID);
+/*      gridInqDatatype: Get the data type of a Grid */
+int     gridInqDatatype(int gridID);
 
 /*      gridInqXval: Get one value of a X-axis */
-double  gridInqXval(int gridID, int index);
+double  gridInqXval(int gridID, size_t index);
 
 /*      gridInqYval: Get one value of a Y-axis */
-double  gridInqYval(int gridID, int index);
+double  gridInqYval(int gridID, size_t index);
 
 double  gridInqXinc(int gridID);
 double  gridInqYinc(int gridID);
 
 int     gridIsCircular(int gridID);
-int     gridIsRotated(int gridID);
-void    gridDefXpole(int gridID, double xpole);
-double  gridInqXpole(int gridID);
-void    gridDefYpole(int gridID, double ypole);
-double  gridInqYpole(int gridID);
-void    gridDefAngle(int gridID, double angle);
-double  gridInqAngle(int gridID);
+
 int     gridInqTrunc(int gridID);
 void    gridDefTrunc(int gridID, int trunc);
-/* Hexagonal GME grid */
-void    gridDefGMEnd(int gridID, int nd);
-int     gridInqGMEnd(int gridID);
-void    gridDefGMEni(int gridID, int ni);
-int     gridInqGMEni(int gridID);
-void    gridDefGMEni2(int gridID, int ni2);
-int     gridInqGMEni2(int gridID);
-void    gridDefGMEni3(int gridID, int ni3);
-int     gridInqGMEni3(int gridID);
 
 /* Reference of an unstructured grid */
 
@@ -1026,18 +1082,17 @@ void    gridInqUUID(int gridID, unsigned char *uuid);
 void    gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE]);
 #endif
 
-/* Lambert Conformal Conic grid (GRIB version) */
-void gridDefLCC(int gridID, double originLon, double originLat, double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag);
-void gridInqLCC(int gridID, double *originLon, double *originLat, double *lonParY, double *lat1, double *lat2, double *xinc, double *yinc, int *projflag, int *scanflag);
+/* Rotated Lon/Lat grid */
+void    gridDefParamRLL(int gridID, double xpole, double ypole, double angle);
+void    gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle);
 
-/* Lambert Conformal Conic 2 grid (PROJ version) */
-void gridDefLcc2(int gridID, double earth_radius, double lon_0, double lat_0, double lat_1, double lat_2);
-void gridInqLcc2(int gridID, double *earth_radius, double *lon_0, double *lat_0, double *lat_1, double *lat_2);
-
-/* Lambert Azimuthal Equal Area grid */
-void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0);
-void gridInqLaea(int gridID, double *earth_radius, double *lon_0, double *lat_0);
+/* Hexagonal GME grid */
+void    gridDefParamGME(int gridID, int nd, int ni, int ni2, int ni3);
+void    gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3);
 
+  /* Lambert Conformal Conic grid (GRIB version) */
+void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2, double a, double rf, double xval_0, double yval_0, double x_0, double y_0);
+int gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0);
 
 void    gridDefArea(int gridID, const double area[]);
 void    gridInqArea(int gridID, double area[]);
@@ -1053,13 +1108,13 @@ int     gridInqNvertex(int gridID);
 void    gridDefXbounds(int gridID, const double xbounds[]);
 
 /*      gridInqXbounds: Get the bounds of a X-axis */
-int     gridInqXbounds(int gridID, double xbounds[]);
+size_t  gridInqXbounds(int gridID, double xbounds[]);
 
 /*      gridDefYbounds: Define the bounds of a Y-axis */
 void    gridDefYbounds(int gridID, const double ybounds[]);
 
 /*      gridInqYbounds: Get the bounds of a Y-axis */
-int     gridInqYbounds(int gridID, double ybounds[]);
+size_t  gridInqYbounds(int gridID, double ybounds[]);
 
 void    gridDefRowlon(int gridID, int nrowlon, const int rowlon[]);
 void    gridInqRowlon(int gridID, int rowlon[]);
@@ -1068,9 +1123,16 @@ void    gridChangeType(int gridID, int gridtype);
 void    gridDefComplexPacking(int gridID, int lpack);
 int     gridInqComplexPacking(int gridID);
 
+void    gridDefUvRelativeToGrid(int gridID, int uvRelativeToGrid);
+int     gridInqUvRelativeToGrid(int gridID);
+
+void    gridDefScanningMode(int gridID, int mode);
+int     gridInqScanningMode(int gridID);
+
 /* ZAXIS routines */
 
 void    zaxisName(int zaxistype, char *zaxisname);
+const char *zaxisNamePtr(int leveltype);
 
 /*      zaxisCreate: Create a vertical Z-axis */
 int     zaxisCreate(int zaxistype, int size);
@@ -1087,15 +1149,22 @@ int     zaxisInqSize(int zaxisID);
 /*      zaxisDuplicate: Duplicate a Z-axis */
 int     zaxisDuplicate(int zaxisID);
 
-void    zaxisResize(int zaxisID, int size);
-
-void    zaxisPrint(int zaxisID, int index);
+void    zaxisPrint(int zaxisID);
 
 /*      zaxisDefLevels: Define the levels of a Z-axis */
 void    zaxisDefLevels(int zaxisID, const double levels[]);
 
+/*      zaxisDefCvals: Define area types of a Z-axis */
+void    zaxisDefCvals(int zaxisID, const char *cvals[], int clength);
+
 /*      zaxisInqLevels: Get all levels of a Z-axis */
-void    zaxisInqLevels(int zaxisID, double levels[]);
+int     zaxisInqLevels(int zaxisID, double levels[]);
+
+/*      zaxisInqCLen: Get maximal string length of character Z-axis */
+int     zaxisInqCLen(int zaxisID);
+
+/*      zaxisInqCVals: Get all string values of a character Z-axis */
+int     zaxisInqCVals(int zaxisID, char ***clevels);
 
 /*      zaxisDefLevel: Define one level of a Z-axis */
 void    zaxisDefLevel(int zaxisID, int levelID, double levels);
@@ -1121,18 +1190,11 @@ void    zaxisDefUUID(int zaxisID, const unsigned char uuid[CDI_UUID_SIZE]);
 /*      zaxisInqUUID: Get the UUID of a generalized Z-axis */
 void    zaxisInqUUID(int zaxisID, unsigned char uuid[CDI_UUID_SIZE]);
 
-/* CDI zaxis string key values */
-#define  CDI_ZAXIS_NAME      801  // Z-axis name
-#define  CDI_ZAXIS_DIMNAME   802  // Z-axis dimension name
-#define  CDI_ZAXIS_VDIMNAME  803  // Vertex dimension name
-#define  CDI_ZAXIS_LONGNAME  804  // Z-axis longname
-#define  CDI_ZAXIS_UNITS     805  // Z-axis units
-
-//      cdiZaxisDefString: Define a CDI Z-axis string value from a key
-int     cdiZaxisDefString(int zaxisID, int key, int size, const char *mesg);
+//      cdiZaxisDefKeyStr: Define a CDI Z-axis string value from a key
+int     cdiZaxisDefKeyStr(int zaxisID, int key, int size, const char *mesg);
 
-//      cdiZaxisInqString: Get a CDI Z-axis string value from a key
-int     cdiZaxisInqString(int zaxisID, int key, int size, char *mesg);
+//      cdiZaxisInqKeyStr: Get a CDI Z-axis string value from a key
+int     cdiZaxisInqKeyStr(int zaxisID, int key, int size, char *mesg);
 
 /*      zaxisDefName: Define the name of a Z-axis */
 void    zaxisDefName(int zaxisID, const char *name_optional);
@@ -1155,14 +1217,8 @@ void    zaxisInqUnits(int zaxisID, char *units);
 /*      zaxisInqStdname: Get the standard name of a Z-axis */
 void    zaxisInqStdname(int zaxisID, char *stdname);
 
-/*      zaxisDefPsName: Define the name of the surface pressure variable of a hybrid sigma pressure Z-axis */
-void    zaxisDefPsName(int zaxisID, const char *psname_optional);
-
-/*      zaxisInqPsName: Get the name of the surface pressure variable of a hybrid sigma pressure Z-axis */
-void    zaxisInqPsName(int zaxisID, char *psname);
-
-void    zaxisDefPrec(int zaxisID, int prec);
-int     zaxisInqPrec(int zaxisID);
+void    zaxisDefDatatype(int zaxisID, int prec);
+int     zaxisInqDatatype(int zaxisID);
 
 void    zaxisDefPositive(int zaxisID, int positive);
 int     zaxisInqPositive(int zaxisID);
@@ -1173,7 +1229,6 @@ int     zaxisInqScalar(int zaxisID);
 void    zaxisDefLtype(int zaxisID, int ltype);
 int     zaxisInqLtype(int zaxisID);
 
-const double *zaxisInqLevelsPtr(int zaxisID);
 void    zaxisDefVct(int zaxisID, int size, const double vct[]);
 void    zaxisInqVct(int zaxisID, double vct[]);
 int     zaxisInqVctSize(int zaxisID);
@@ -1239,6 +1294,7 @@ int     taxisInqFdate(int taxisID);
 int     taxisInqFtime(int taxisID);
 
 int     taxisHasBounds(int taxisID);
+void    taxisWithBounds(int taxisID);
 
 void    taxisDeleteBounds(int taxisID);
 
@@ -1294,8 +1350,6 @@ const char *modelInqNamePtr(int modelID);
 
 /* Table routines */
 
-/*      tableWriteC: write table of parameters to file in C language format */
-void    tableWriteC(const char *filename, int tableID);
 /*      tableFWriteC: write table of parameters to FILE* in C language format */
 void    tableFWriteC(FILE *ptfp, int tableID);
 /*      tableWrite: write table of parameters to file in tabular format */
@@ -1305,7 +1359,6 @@ int     tableRead(const char *tablefile);
 int     tableDef(int modelID, int tablenum, const char *tablename);
 
 const char *tableInqNamePtr(int tableID);
-void    tableDefEntry(int tableID, int code, const char *name, const char *longname, const char *units);
 
 int     tableInq(int modelID, int tablenum, const char *tablename);
 int     tableInqNumber(void);
@@ -1313,17 +1366,7 @@ int     tableInqNumber(void);
 int     tableInqNum(int tableID);
 int     tableInqModel(int tableID);
 
-void    tableInqPar(int tableID, int code, char *name, char *longname, char *units);
-
-int     tableInqParCode(int tableID, char *name, int *code);
-int     tableInqParName(int tableID, int code, char *name);
-int     tableInqParLongname(int tableID, int code, char *longname);
-int     tableInqParUnits(int tableID, int code, char *units);
-
-/* needed only for CDO operator after */
-const char *tableInqParNamePtr(int tableID, int parID);
-const char *tableInqParLongnamePtr(int tableID, int parID);
-const char *tableInqParUnitsPtr(int tableID, int parID);
+void    tableInqEntry(int tableID, int id, int ltype, char *name, char *longname, char *units);
 
 /* History routines */
 
@@ -1390,6 +1433,8 @@ void gribapiLibraryVersion(int *major_version, int *minor_version, int *revision
 #ifndef _BASETIME_H
 #define _BASETIME_H
 
+#include <stdbool.h>
+
 //#define USE_TIMECACHE 1
 #define MAX_TIMECACHE_SIZE 1024
 
@@ -1406,7 +1451,7 @@ typedef struct {
   int   ncdimid;
   int   ncvarboundsid;
   int   leadtimeid;
-  int   lwrf;     /* TRUE for time axis in WRF format */
+  bool  lwrf;     /* true for time axis in WRF format */
   timecache_t *timevar_cache;
 }
 basetime_t;
@@ -1427,21 +1472,20 @@ void basetimeInit(basetime_t *basetime);
 #endif
 
 #include <stdio.h>
+#include <stdbool.h>
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
 
 void basetimeInit(basetime_t *basetime)
 {
   if ( basetime == NULL )
     Error("Internal problem! Basetime not allocated.");
 
-  basetime->ncvarid       = UNDEFID;
-  basetime->ncdimid       = UNDEFID;
-  basetime->ncvarboundsid = UNDEFID;
-  basetime->leadtimeid    = UNDEFID;
-  basetime->lwrf          = 0;
+  basetime->ncvarid       = CDI_UNDEFID;
+  basetime->ncdimid       = CDI_UNDEFID;
+  basetime->ncvarboundsid = CDI_UNDEFID;
+  basetime->leadtimeid    = CDI_UNDEFID;
+  basetime->lwrf          = false;
   basetime->timevar_cache = NULL;
 }
 /*
@@ -1582,8 +1626,8 @@ void swap8byte(void *ptr, size_t size);
  * require-trailing-newline: t
  * End:
  */
-#ifndef _BINARY_H
-#define _BINARY_H
+#ifndef BINARY_H
+#define BINARY_H
 
 #ifdef HAVE_CONFIG_H
 #endif
@@ -1623,7 +1667,7 @@ int binReadFlt64(int fileID, int byteswap, size_t size, FLT64 *ptr);
 int binWriteFlt32(int fileID, int byteswap, size_t size, FLT32 *ptr);
 int binWriteFlt64(int fileID, int byteswap, size_t size, FLT64 *ptr);
 
-#endif  /* _BINARY_H */
+#endif  /* BINARY_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -1981,9 +2025,9 @@ void decode_juldaysec(int calendar, int julday, int secofday, int *year, int *mo
 
 
 
-static int month_360[12] = {30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
-static int month_365[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static const int month_360[12] = {30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30};
+static const int month_365[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static const int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 
 int calendar_dpy(int calendar)
@@ -2000,9 +2044,9 @@ int calendar_dpy(int calendar)
 
 int days_per_month(int calendar, int year, int month)
 {
-  int *dpm = NULL;
   int daysperyear = calendar_dpy(calendar);
 
+  const int *dpm;
   if      ( daysperyear == 360 ) dpm = month_360;
   else if ( daysperyear == 365 ) dpm = month_365;
   else                           dpm = month_366;
@@ -2032,7 +2076,7 @@ int days_per_year(int calendar, int year)
 
   if ( daysperyear == 0 )
     {
-      if ( year == 1582 && calendar == CALENDAR_STANDARD )
+      if ( year == 1582 && (calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN) )
         daysperyear = 355;
       else if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
         daysperyear = 366;
@@ -2047,11 +2091,11 @@ int days_per_year(int calendar, int year)
 static void decode_day(int dpy, int days, int *year, int *month, int *day)
 {
   int i = 0;
-  int *dpm = NULL;
 
   *year = (days-1) / dpy;
   days -= (*year*dpy);
 
+  const int *dpm = NULL;
   if      ( dpy == 360 ) dpm = month_360;
   else if ( dpy == 365 ) dpm = month_365;
   else if ( dpy == 366 ) dpm = month_366;
@@ -2070,9 +2114,9 @@ static void decode_day(int dpy, int days, int *year, int *month, int *day)
 
 static int encode_day(int dpy, int year, int month, int day)
 {
-  int *dpm = NULL;
   long rval = (long)dpy * year + day;
 
+  const int *dpm = NULL;
   if      ( dpy == 360 ) dpm = month_360;
   else if ( dpy == 365 ) dpm = month_365;
   else if ( dpy == 366 ) dpm = month_366;
@@ -2285,8 +2329,8 @@ int main(void)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _CDF_H
-#define _CDF_H
+#ifndef  CDF_H
+#define  CDF_H
 
 void cdfDebug(int debug);
 
@@ -2295,12 +2339,11 @@ extern int CDF_Debug;
 const char *cdfLibraryVersion(void);
 const char *hdfLibraryVersion(void);
 
-int  cdfOpen(const char *filename, const char *mode);
-int  cdfOpen64(const char *filename, const char *mode);
+int  cdfOpen(const char *filename, const char *mode, int filetype);
 int  cdf4Open(const char *filename, const char *mode, int *filetype);
 void cdfClose(int fileID);
 
-#endif  /* _CDF_H */
+#endif  /* CDF_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -2310,6 +2353,23 @@ void cdfClose(int fileID);
  * require-trailing-newline: t
  * End:
  */
+#ifndef  CDF_CONFIG_H_
+#define  CDF_CONFIG_H_
+
+#ifdef  HAVE_CONFIG_H
+#endif
+
+#ifdef  HAVE_LIBNETCDF
+
+#include  <netcdf.h>
+
+#ifdef  NC_FORMAT_64BIT_DATA
+#define  HAVE_NETCDF5  1
+#endif
+
+#endif
+
+#endif
 #ifndef RESOURCE_HANDLE_H
 #define RESOURCE_HANDLE_H
 
@@ -2410,6 +2470,7 @@ enum reshListMismatch {
 
 int reshListCompare(int nsp0, int nsp1);
 void reshListPrint(FILE *fp);
+int reshGetTxCode(cdiResH resH);
 
 #endif
 /*
@@ -2424,6 +2485,8 @@ void reshListPrint(FILE *fp);
 #ifndef _TAXIS_H
 #define _TAXIS_H
 
+#include <stdbool.h>
+
 #ifndef RESOURCE_HANDLE_H
 #endif
 
@@ -2431,8 +2494,9 @@ typedef struct {
   /* Date format  YYYYMMDD */
   /* Time format    hhmmss */
   int     self;
-  short   used;
+  bool    used;
   short   has_bounds;
+  int     datatype;       // datatype
   int     type;           // time type
   int     vdate;          // verification date
   int     vtime;          // verification time
@@ -2443,15 +2507,16 @@ typedef struct {
   int     calendar;
   int     unit;           // time unit
   int     numavg;
-  int     climatology;
+  bool    climatology;
   int     vdate_lb;       // lower bounds of vdate
   int     vtime_lb;       // lower bounds of vtime
   int     vdate_ub;       // upper bounds of vdate
   int     vtime_ub;       // upper bounds of vtime
   int     fc_unit;        // forecast time unit
   double  fc_period;      // forecast time period
-  char*   name;
-  char*   longname;
+  char   *name;
+  char   *longname;
+  char   *units;
 }
 taxis_t;
 
@@ -2464,8 +2529,10 @@ double   cdiEncodeTimeval(int date, int time, taxis_t* taxis);
 void     timeval2vtime(double timevalue, taxis_t* taxis, int* vdate, int* vtime);
 double   vtime2timeval(int vdate, int vtime, taxis_t *taxis);
 
+void    ptaxisDefDatatype(taxis_t *taxisptr, int datatype);
 void    ptaxisDefName(taxis_t *taxisptr, const char *name);
-void    ptaxisDefLongname(taxis_t *taxisptr, const char *name);
+void    ptaxisDefLongname(taxis_t *taxisptr, const char *longname);
+void    ptaxisDefUnits(taxis_t *taxisptr, const char *units);
 void    taxisDestroyKernel(taxis_t *taxisptr);
 #if !defined (SX)
 extern const resOps taxisOps;
@@ -2617,7 +2684,6 @@ int  extDefDataDP(void *ext, const double *data);
 #define  IEG_LTYPE_LANDDEPTH           111
 #define  IEG_LTYPE_LANDDEPTH_LAYER     112
 #define  IEG_LTYPE_SEADEPTH            160
-#define  IEG_LTYPE_99_MARGIN          1000
 
 /*
  *  Data representation type (Grid Type) [Table 6]
@@ -2703,8 +2769,8 @@ int  iegDefDataDP(void *ieg, const double *data);
  * require-trailing-newline: t
  * End:
  */
-#ifndef _CDI_INT_H
-#define _CDI_INT_H
+#ifndef  CDI_INT_H
+#define  CDI_INT_H
 
 #if defined (HAVE_CONFIG_H)
 #endif
@@ -2714,6 +2780,7 @@ int  iegDefDataDP(void *ieg, const double *data);
 #include <stdbool.h>
 #include <string.h>
 #include <errno.h>
+#include <limits.h>
 #include <math.h>
 #include <sys/types.h>
 
@@ -2744,7 +2811,7 @@ char *strdup(const char *s);
 #endif
 
 
-#ifndef  _ERROR_H
+#ifndef  ERROR_H
 #endif
 #ifndef _BASETIME_H
 #endif
@@ -2846,9 +2913,17 @@ typedef struct
   int       ilevel2;
   int       ltype;
   short     tsteptype;
-  short     used;
+#ifdef HIRLAM_EXTENSIONS
+    // NOTE: tsteptype MUST be part of attributes used to compare variables!
+    // Modern NWP models (HARMONIE, HIRLAM) use timeRangeIndicator to specify
+    // if the field is instantanous or accumulated.
+    // Both types are typically in the same GRIB-file.
+    // (181; 105, 0, timeRangeIndicator=0) .. instantanous rain
+    // (181; 105, 0, timeRangeIndicator=4) .. accumulated rain  .. both can be in the same grib file
+#endif // HIRLAM_EXTENSIONS
   short     varID;
   short     levelID;
+  short     used;
   char      varname[32]; /* needed for grib decoding with GRIB_API */
   var_tile_t tiles;      /* tile-related meta-data, currently for GRIB-API only. */
 }
@@ -2864,7 +2939,7 @@ typedef struct {
                          /* tsID>0 number of non constant records */
   int       nallrecs;    /* number of all records                 */
   int       curRecID;    /* current record ID                     */
-  long      next;
+  bool      next;
   off_t     position;    /* timestep file position                */
   taxis_t   taxis;
 }
@@ -2882,14 +2957,14 @@ typedef struct {
 typedef struct {
   int            ncvarid;
   int            subtypeSize;
-  sleveltable_t *recordTable; /* record IDs for each subtype */
-  int            defmiss;     /* TRUE if missval is defined in file */
+  sleveltable_t *recordTable; // record IDs for each subtype
+  bool           defmiss;     // true: if missval is defined in file
+  bool           isUsed;
 
-  int            isUsed;
   int            gridID;
   int            zaxisID;
-  int            tsteptype;   /* TSTEP_* */
-  int            subtypeID;   /* subtype ID, e.g. for tile-related meta-data (currently for GRIB-API only). */
+  int            tsteptype;   // TSTEP_*
+  int            subtypeID;   // subtype ID, e.g. for tile-related meta-data (currently for GRIB-API only).
 }
 svarinfo_t;
 
@@ -2902,6 +2977,21 @@ typedef struct {
 }
 VCT;
 
+#ifdef HAVE_LIBNETCDF
+enum {
+  CDF_DIMID_X,
+  CDF_DIMID_Y,
+  CDF_VARID_X,
+  CDF_VARID_Y,
+  CDF_VARID_A,
+  CDF_SIZE_ncIDs,
+};
+typedef struct {
+  int gridID;
+  int ncIDs[CDF_SIZE_ncIDs];
+}
+ncgrid_t;
+#endif
 
 typedef struct {
   int         self;
@@ -2912,7 +3002,7 @@ typedef struct {
   int         fileID;
   int         filemode;
   int         nrecs;        /* number of records                  */
-  off_t       numvals;
+  size_t      numvals;
   char       *filename;
   Record     *record;
   svarinfo_t *vars;
@@ -2927,22 +3017,21 @@ typedef struct {
   basetime_t  basetime;
   int         ncmode;
   int         vlistID;
-  int         xdimID[MAX_GRIDS_PS];	//Warning: synchronous array to vlist_to_pointer(vlistID)->gridIDs
-  int         ydimID[MAX_GRIDS_PS];	//Warning: synchronous array to vlist_to_pointer(vlistID)->gridIDs
+#ifdef HAVE_LIBNETCDF
+  ncgrid_t    ncgrid[MAX_GRIDS_PS];
   int         zaxisID[MAX_ZAXES_PS];	//Warning: synchronous array to vlist_to_pointer(vlistID)->zaxisIDs
   int         nczvarID[MAX_ZAXES_PS];
-  int         ncxvarID[MAX_GRIDS_PS];
-  int         ncyvarID[MAX_GRIDS_PS];
-  int         ncavarID[MAX_GRIDS_PS];
+  VCT         vct;
+#endif
   int         historyID;
   int         globalatts;
   int         localatts;
-  VCT         vct;
   int         unreduced;
-  int         sortname;
   int         have_missval;
   int         comptype;      // compression type
   int         complevel;     // compression level
+  bool        sortname;
+  bool        sortparam;
 #if defined (GRIBCONTAINER2D)
   void      **gribContainers;
 #else
@@ -2969,7 +3058,7 @@ typedef enum {
 typedef struct
 {
   char*                  keyword;        /* keyword string */
-  int                    update;
+  bool                   update;
   key_val_pair_datatype  data_type;      /* data type of this key/value pair */
   double                 dbl_val;        /* double value (data_type == t_double) */
   int                    int_val;        /* integer value (data_type == t_int) */
@@ -2984,8 +3073,10 @@ typedef enum {
 } CdiTimeType;
 
 
+#define  CDI_FILETYPE_UNDEF          -1   /* Unknown/not yet defined file type */
 
 
+extern int cdiDebugExt;
 extern int CDI_Debug;      /* If set to 1, debuggig (default 0)            */
 extern int CDI_Recopt;
 extern int cdiGribApiDebug;
@@ -3001,14 +3092,17 @@ extern int cdiChunkType;
 extern int cdiSplitLtype105;
 extern int cdiDataUnreduced;
 extern int cdiSortName;
+extern int cdiSortParam;
 extern int cdiHaveMissval;
-extern int cdiIgnoreAttCoordinates;
-extern int cdiIgnoreValidRange;
+extern bool cdiIgnoreAttCoordinates;
+extern bool cdiCoordinatesLonLat;
+extern bool cdiIgnoreValidRange;
 extern int cdiSkipRecords;
 extern int cdiConvention;
 extern int cdiInventoryMode;
 extern int CDI_Version_Info;
 extern int CDI_cmor_mode;
+extern int CDI_reduce_dim;
 extern size_t CDI_netcdf_hdr_pad;
 extern bool CDI_netcdf_lazy_grid_load;
 extern int STREAM_Debug;
@@ -3035,8 +3129,6 @@ int     streamInqFileID(int streamID);
 
 void    gridDefHasDims(int gridID, int hasdims);
 int     gridInqHasDims(int gridID);
-const char *gridNamePtr(int gridtype);
-const char   *zaxisNamePtr(int leveltype);
 int     zaxisInqLevelID(int zaxisID, double level);
 
 void    streamCheckID(const char *caller, int streamID);
@@ -3060,6 +3152,8 @@ void    vlist_check_contents(int vlistID);
 
 void    cdi_create_records(stream_t *streamptr, int tsID);
 
+void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name);
+
 int     recordNewEntry(stream_t *streamptr, int tsID);
 
 void    cdiCreateTimesteps(stream_t *streamptr);
@@ -3068,8 +3162,6 @@ void    recordInitEntry(record_t *record);
 
 void    cdiCheckZaxis(int zaxisID);
 
-void    cdiPrintDatatypes(void);
-
 void    cdiDefAccesstype(int streamID, int type);
 int     cdiInqAccesstype(int streamID);
 
@@ -3111,11 +3203,11 @@ void
 cdiStreamDefVlist_(int streamID, int vlistID);
 
 int
-cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss);
+cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss);
 
 void
 cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss);
+                        const int rect[][2], const void *data, size_t nmiss);
 void
 cdiStreamCloseDefaultDelegate(stream_t *streamptr,
                               int recordBufIsToBeDeleted);
@@ -3149,11 +3241,18 @@ void cdiDefTableID(int tableID);
 void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *xvals);
 void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *yvals);
 
+static inline
+void cdi_check_gridsize_int_limit(const char *format, size_t gridsize)
+{
+  if ( gridsize > INT_MAX ) Error("%s format grid size (%zu) limit exceeded (%zu)!", format, gridsize, INT_MAX);
+}
+
+
 #if defined (__cplusplus)
 }
 #endif
 
-#endif  /* _CDI_INT_H */
+#endif  /* CDI_INT_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -3163,8 +3262,8 @@ void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double y
  * require-trailing-newline: t
  * End:
  */
-#ifndef _CDF_INT_H
-#define _CDF_INT_H
+#ifndef  CDF_INT_H
+#define  CDF_INT_H
 
 #if  defined  (HAVE_LIBNETCDF)
 
@@ -3241,6 +3340,7 @@ void cdf_put_att_double(int ncid, int varid, const char *name, nc_type xtype, si
 void cdf_get_att_string(int ncid, int varid, const char *name, char **tp);
 void cdf_get_att_text  (int ncid, int varid, const char *name, char *tp);
 void cdf_get_att_int   (int ncid, int varid, const char *name, int *ip);
+void cdf_get_att_long  (int ncid, int varid, const char *name, long *ip);
 void cdf_get_att_double(int ncid, int varid, const char *name, double *dp);
 
 void cdf_inq_att    (int ncid, int varid, const char *name, nc_type * xtypep, size_t * lenp);
@@ -3249,6 +3349,8 @@ void cdf_inq_attlen (int ncid, int varid, const char *name, size_t *lenp);
 void cdf_inq_attname(int ncid, int varid, int attnum, char *name);
 void cdf_inq_attid  (int ncid, int varid, const char *name, int *attnump);
 
+void cdf_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp);
+
 typedef int (*cdi_nc__create_funcp)(const char *path, int cmode,
                                     size_t initialsz, size_t *chunksizehintp,
                                     int *ncidp);
@@ -3259,7 +3361,7 @@ typedef void (*cdi_cdf_def_var_funcp)(int ncid, const char *name,
 
 #endif
 
-#endif  /* _CDF_INT_H */
+#endif  /* CDF_INT_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -3269,7 +3371,7 @@ typedef void (*cdi_cdf_def_var_funcp)(int ncid, const char *name,
  * require-trailing-newline: t
  * End:
  */
-#if defined (HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #endif
 
 #include <stdio.h>
@@ -3282,32 +3384,32 @@ typedef void (*cdi_cdf_def_var_funcp)(int ncid, const char *name,
 
 const char *cdfLibraryVersion(void)
 {
-#if  defined  (HAVE_LIBNETCDF)
+#ifdef  HAVE_LIBNETCDF
   return nc_inq_libvers();
 #else
   return "library undefined";
 #endif
 }
 
-#if  defined(HAVE_H5GET_LIBVERSION)
-#if  defined(__cplusplus)
+#ifdef  HAVE_H5GET_LIBVERSION
+#ifdef  __cplusplus
 extern "C" {
 #endif
   int H5get_libversion(unsigned *, unsigned *, unsigned *);
-#if defined(__cplusplus)
+#ifdef  __cplusplus
 }
 #endif
 #endif
 
 const char *hdfLibraryVersion(void)
 {
-#if  defined(HAVE_H5GET_LIBVERSION)
+#ifdef  HAVE_H5GET_LIBVERSION
   static char hdf_libvers[256];
   unsigned majnum, minnum, relnum;
 
   H5get_libversion(&majnum, &minnum, &relnum);
 
-#if  defined(HAVE_NC4HDF5_THREADSAFE)
+#ifdef  HAVE_NC4HDF5_THREADSAFE
   sprintf(hdf_libvers, "%u.%u.%u threadsafe", majnum, minnum, relnum);
 #else
   sprintf(hdf_libvers, "%u.%u.%u", majnum, minnum, relnum);
@@ -3330,7 +3432,7 @@ void cdfDebug(int debug)
     Message("debug level %d", debug);
 }
 
-#if  defined  (HAVE_LIBNETCDF)
+#ifdef  HAVE_LIBNETCDF
 static
 void cdfComment(int ncid)
 {
@@ -3358,11 +3460,10 @@ void cdfComment(int ncid)
 static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
 {
   int ncid = -1;
-#if  defined  (HAVE_LIBNETCDF)
+#ifdef  HAVE_LIBNETCDF
   int fmode = tolower(*mode);
   int writemode = NC_CLOBBER;
   int readmode = NC_NOWRITE;
-  int status;
 
   if ( filename == NULL )
     ncid = CDI_EINVAL;
@@ -3371,31 +3472,34 @@ static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
       switch (fmode)
 	{
 	case 'r':
-	  status = cdf_open(filename, readmode, &ncid);
-	  if ( status > 0 && ncid < 0 ) ncid = CDI_ESYSTEM;
-#if  defined  (HAVE_NETCDF4)
-	  else
-	    {
-	      int format;
-	      (void) nc_inq_format(ncid, &format);
-	      if ( format == NC_FORMAT_NETCDF4_CLASSIC )
-		{
-		  *filetype = FILETYPE_NC4C;
-		}
-	    }
+          {
+            int status = cdf_open(filename, readmode, &ncid);
+            if ( status > 0 && ncid < 0 ) ncid = CDI_ESYSTEM;
+#ifdef  HAVE_NETCDF4
+            else
+              {
+                int format;
+                (void) nc_inq_format(ncid, &format);
+                if ( format == NC_FORMAT_NETCDF4_CLASSIC )
+                  *filetype = CDI_FILETYPE_NC4C;
+              }
 #endif
+          }
 	  break;
 	case 'w':
-#if  defined  (NC_64BIT_OFFSET)
-	  if      ( *filetype == FILETYPE_NC2  ) writemode |= NC_64BIT_OFFSET;
+#ifdef  NC_64BIT_OFFSET
+	  if      ( *filetype == CDI_FILETYPE_NC2  ) writemode |= NC_64BIT_OFFSET;
 #endif
-#if  defined  (HAVE_NETCDF4)
-	  if      ( *filetype == FILETYPE_NC4  ) writemode |= NC_NETCDF4;
-	  else if ( *filetype == FILETYPE_NC4C ) writemode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
+#ifdef  NC_64BIT_DATA
+	  if      ( *filetype == CDI_FILETYPE_NC5  ) writemode |= NC_64BIT_DATA;
+#endif
+#ifdef  HAVE_NETCDF4
+	  if      ( *filetype == CDI_FILETYPE_NC4  ) writemode |= NC_NETCDF4;
+	  else if ( *filetype == CDI_FILETYPE_NC4C ) writemode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
 #endif
 	  cdf_create(filename, writemode, &ncid);
 	  if ( CDI_Version_Info ) cdfComment(ncid);
-          cdf_put_att_text(ncid, NC_GLOBAL, "Conventions", 6, "CF-1.4");
+          cdf_put_att_text(ncid, NC_GLOBAL, "Conventions", 6, "CF-1.6");
 	  break;
 	case 'a':
 	  cdf_open(filename, NC_WRITE, &ncid);
@@ -3410,34 +3514,20 @@ static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
 }
 
 
-int cdfOpen(const char *filename, const char *mode)
-{
-  int filetype = FILETYPE_NC;
-
-  if ( CDF_Debug )
-    Message("Open %s with mode %c", filename, *mode);
-
-  int fileID = cdfOpenFile(filename, mode, &filetype);
-
-  if ( CDF_Debug )
-    Message("File %s opened with id %d", filename, fileID);
-
-  return fileID;
-}
-
-
-int cdfOpen64(const char *filename, const char *mode)
+int cdfOpen(const char *filename, const char *mode, int filetype)
 {
   int fileID = -1;
-  int open_file = TRUE;
-  int filetype = FILETYPE_NC2;
+  bool open_file = true;
 
   if ( CDF_Debug )
     Message("Open %s with mode %c", filename, *mode);
 
-#if  defined  (HAVE_LIBNETCDF)
-#if  ! defined  (NC_64BIT_OFFSET)
-  open_file = FALSE;
+#ifdef  HAVE_LIBNETCDF
+#ifndef  NC_64BIT_OFFSET
+  if ( filetype == CDI_FILETYPE_NC2 ) open_file = false;
+#endif
+#ifndef  NC_64BIT_DATA
+  if ( filetype == CDI_FILETYPE_NC5 ) open_file = false;
 #endif
 #endif
 
@@ -3446,7 +3536,7 @@ int cdfOpen64(const char *filename, const char *mode)
       fileID = cdfOpenFile(filename, mode, &filetype);
 
       if ( CDF_Debug )
-	Message("File %s opened with id %d", filename, fileID);
+        Message("File %s opened with id %d", filename, fileID);
     }
   else
     {
@@ -3460,13 +3550,13 @@ int cdfOpen64(const char *filename, const char *mode)
 int cdf4Open(const char *filename, const char *mode, int *filetype)
 {
   int fileID = -1;
-  int open_file = FALSE;
+  bool open_file = false;
 
   if ( CDF_Debug )
     Message("Open %s with mode %c", filename, *mode);
 
-#if  defined  (HAVE_NETCDF4)
-  open_file = TRUE;
+#ifdef  HAVE_NETCDF4
+  open_file = true;
 #endif
 
   if ( open_file )
@@ -3487,7 +3577,7 @@ int cdf4Open(const char *filename, const char *mode, int *filetype)
 
 static void cdfCloseFile(int fileID)
 {
-#if  defined  (HAVE_LIBNETCDF)
+#ifdef  HAVE_LIBNETCDF
   cdf_close(fileID);
 #endif
 }
@@ -3654,12 +3744,12 @@ void cdf_create(const char *path, int cmode, int *ncidp)
 int cdf_open(const char *path, int omode, int *ncidp)
 {
   int status = 0;
-  int dapfile = FALSE;
+  bool dapfile = false;
   struct stat filestat;
   size_t chunksizehint = 0;
 
 #if  defined  (HAVE_LIBNC_DAP)
-  if ( strncmp(path, "http:", 5) == 0 || strncmp(path, "https:", 6) == 0 ) dapfile = TRUE;
+  if ( strncmp(path, "http:", 5) == 0 || strncmp(path, "https:", 6) == 0 ) dapfile = true;
 #endif
 
   if ( dapfile )
@@ -3973,6 +4063,52 @@ void cdf_put_var_float(int ncid, int varid, const float *fp)
   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
 }
 
+static
+const char *cdf_var_type(nc_type xtype)
+{
+  const char *ctype = "unknown";
+
+  if      ( xtype == NC_BYTE   )  ctype = "NC_BYTE";
+  else if ( xtype == NC_CHAR   )  ctype = "NC_CHAR";
+  else if ( xtype == NC_SHORT  )  ctype = "NC_SHORT";
+  else if ( xtype == NC_INT    )  ctype = "NC_INT";
+  else if ( xtype == NC_FLOAT  )  ctype = "NC_FLOAT";
+  else if ( xtype == NC_DOUBLE )  ctype = "NC_DOUBLE";
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_UBYTE  )  ctype = "NC_UBYTE";
+  else if ( xtype == NC_LONG   )  ctype = "NC_LONG";
+  else if ( xtype == NC_USHORT )  ctype = "NC_USHORT";
+  else if ( xtype == NC_UINT   )  ctype = "NC_UINT";
+  else if ( xtype == NC_INT64  )  ctype = "NC_INT64";
+  else if ( xtype == NC_UINT64 )  ctype = "NC_UINT64";
+#endif
+
+  return ctype;
+}
+
+static
+void minmaxval(size_t nvals, const double *array, double *minval, double *maxval)
+{
+  *minval = array[0];
+  *maxval = array[0];
+  for ( size_t i = 1; i < nvals; ++i )
+    {
+      if      ( array[i] > *maxval ) *maxval = array[i];
+      else if ( array[i] < *minval ) *minval = array[i];
+    }
+}
+
+static
+void minmaxvalf(size_t nvals, const float *array, double *minval, double *maxval)
+{
+  *minval = array[0];
+  *maxval = array[0];
+  for ( size_t i = 1; i < nvals; ++i )
+    {
+      if      ( array[i] > *maxval ) *maxval = array[i];
+      else if ( array[i] < *minval ) *minval = array[i];
+    }
+}
 
 void cdf_put_vara_double(int ncid, int varid, const size_t start[],
                          const size_t count[], const double *dp)
@@ -3980,13 +4116,19 @@ void cdf_put_vara_double(int ncid, int varid, const size_t start[],
   int status = nc_put_vara_double(ncid, varid, start, count, dp);
 
   if ( CDF_Debug || status != NC_NOERR )
-    Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
-
-  if ( status != NC_NOERR )
     {
       char name[256];
       nc_inq_varname(ncid, varid, name);
-      Message("varname = %s", name);
+      nc_type xtype;
+      nc_inq_vartype(ncid, varid, &xtype);
+      int ndims;
+      nc_inq_varndims(ncid, varid, &ndims);
+      double minval = 0, maxval = 0;
+      size_t nvals = 1;
+      for ( int i = 0; i < ndims; ++i ) nvals *= count[i];
+      minmaxval(nvals, dp, &minval, &maxval);
+      // Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
+      Message("name=%s  type=%s  minval=%f  maxval=%f", name, cdf_var_type(xtype), minval, maxval);
     }
 
   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
@@ -3999,7 +4141,20 @@ void  cdf_put_vara_float(int ncid, int varid, const size_t start[],
   int status = nc_put_vara_float(ncid, varid, start, count, fp);
 
   if ( CDF_Debug || status != NC_NOERR )
-    Message("ncid = %d varid = %d val0 = %f", ncid, varid, *fp);
+    {
+      char name[256];
+      nc_inq_varname(ncid, varid, name);
+      nc_type xtype;
+      nc_inq_vartype(ncid, varid, &xtype);
+      int ndims;
+      nc_inq_varndims(ncid, varid, &ndims);
+      double minval = 0, maxval = 0;
+      size_t nvals = 1;
+      for ( int i = 0; i < ndims; ++i ) nvals *= count[i];
+      minmaxvalf(nvals, fp, &minval, &maxval);
+      // Message("ncid = %d varid = %d val0 = %f", ncid, varid, *dp);
+      Message("name=%s  type=%s  minval=%f  maxval=%f", name, cdf_var_type(xtype), minval, maxval);
+    }
 
   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
 }
@@ -4268,6 +4423,19 @@ void cdf_get_att_int(int ncid, int varid, const char *name, int *ip)
 }
 
 
+void cdf_get_att_long(int ncid, int varid, const char *name, long *ip)
+{
+#if  defined  (HAVE_NETCDF4)
+  int status = nc_get_att_long(ncid, varid, name, ip);
+
+  if ( CDF_Debug || status != NC_NOERR )
+    Message("ncid = %d varid = %d att = %s val = %ld", ncid, varid, name, *ip);
+
+  if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
+#endif
+}
+
+
 void cdf_get_att_double(int ncid, int varid, const char *name, double *dp)
 {
   int status;
@@ -4336,224 +4504,16 @@ void cdf_inq_attid(int ncid, int varid, const char *name, int *attnump)
   if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
 }
 
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef CDI_CKSUM_H_
-#define CDI_CKSUM_H_
-
-#include <inttypes.h>
-
-uint32_t cdiCheckSum(int type, int count, const void *data);
-
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifdef HAVE_CONFIG_H
-#endif
-
-#include <inttypes.h>
-#include <sys/types.h>
-
-void
-memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len);
-
-void
-memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
-               size_t elem_size);
-
-uint32_t
-memcrc_finish(uint32_t *state, off_t total_size);
-
-uint32_t
-memcrc(const unsigned char *b, size_t n);
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifdef HAVE_CONFIG_H
-#endif
-
-#ifndef SERIALIZE_H
-#define SERIALIZE_H
-
-#include <string.h>
-
-#ifndef  CDI_CKSUM_H_
-#endif
-#ifndef  _ERROR_H
-#endif
-
-/*
- * Generic interfaces for (de-)marshalling
- */
-int serializeGetSize(int count, int datatype, void *context);
-void serializePack(const void *data, int count, int datatype,
-                   void *buf, int buf_size, int *position, void *context);
-void serializeUnpack(const void *buf, int buf_size, int *position,
-                     void *data, int count, int datatype, void *context);
-
-/*
- * (de-)marshalling function for common data structures
- */
-static inline int
-serializeStrTabGetPackSize(const char **strTab, int numStr,
-                           void *context)
-{
-  xassert(numStr >= 0);
-  int packBuffSize = 0;
-  for (size_t i = 0; i < (size_t)numStr; ++i)
-  {
-    size_t len = strlen(strTab[i]);
-    packBuffSize +=
-      serializeGetSize(1, DATATYPE_INT, context)
-      + serializeGetSize((int)len, DATATYPE_TXT, context);
-  }
-  packBuffSize +=
-    serializeGetSize(1, DATATYPE_UINT32, context);
-  return packBuffSize;
-}
-
-static inline void
-serializeStrTabPack(const char **strTab, int numStr,
-                    void *buf, int buf_size, int *position, void *context)
-{
-  uint32_t d = 0;
-  xassert(numStr >= 0);
-  for (size_t i = 0; i < (size_t)numStr; ++i)
-  {
-    int len = (int)strlen(strTab[i]);
-    serializePack(&len, 1, DATATYPE_INT,
-                  buf, buf_size, position, context);
-    serializePack(strTab[i], len, DATATYPE_TXT,
-                  buf, buf_size, position, context);
-    d ^= cdiCheckSum(DATATYPE_TXT, len, strTab[i]);
-  }
-  serializePack(&d, 1, DATATYPE_UINT32,
-                buf, buf_size, position, context);
-}
 
-static inline void
-serializeStrTabUnpack(const void *buf, int buf_size, int *position,
-                      char **strTab, int numStr, void *context)
+#if  defined  (HAVE_NETCDF4)
+void cdf_def_var_chunking(int ncid, int varid, int storage, const size_t *chunksizesp)
 {
-  uint32_t d, d2 = 0;
-  xassert(numStr >= 0);
-  for (size_t i = 0; i < (size_t)numStr; ++i)
-    {
-      int len;
-      serializeUnpack(buf, buf_size, position,
-                      &len, 1, DATATYPE_INT, context);
-      serializeUnpack(buf, buf_size, position,
-                      strTab[i], len, DATATYPE_TXT, context);
-      strTab[i][len] = '\0';
-      d2 ^= cdiCheckSum(DATATYPE_TXT, len, strTab[i]);
-    }
-  serializeUnpack(buf, buf_size, position,
-                  &d, 1, DATATYPE_UINT32, context);
-  xassert(d == d2);
+  int status = nc_def_var_chunking(ncid, varid, storage, chunksizesp);
+  if ( status != NC_NOERR ) Error("%s", nc_strerror(status));
 }
-
-/*
- * Interfaces for marshalling within a single memory domain
- */
-int serializeGetSizeInCore(int count, int datatype, void *context);
-void serializePackInCore(const void *data, int count, int datatype,
-                          void *buf, int buf_size, int *position, void *context);
-void serializeUnpackInCore(const void *buf, int buf_size, int *position,
-                           void *data, int count, int datatype, void *context);
-
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifdef HAVE_CONFIG_H
 #endif
 
-#include <inttypes.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-
-uint32_t cdiCheckSum(int type, int count, const void *buffer)
-{
-  uint32_t s = 0U;
-  xassert(count >= 0);
-  size_t elemSize = (size_t)serializeGetSizeInCore(1, type, NULL);
-  memcrc_r_eswap(&s, (const unsigned char *)buffer, (size_t)count, elemSize);
-  s = memcrc_finish(&s, (off_t)(elemSize * (size_t)count));
-  return s;
-}
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
 #endif
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-const char *cdiStringError(int cdiErrno)
-{
-  static const char UnknownError[] = "Unknown Error";
-  static const char _EUFTYPE[]     = "Unsupported file type";
-  static const char _ELIBNAVAIL[]  = "Unsupported file type (library support not compiled in)";
-  static const char _EUFSTRUCT[]   = "Unsupported file structure";
-  static const char _EUNC4[]       = "Unsupported NetCDF4 structure";
-  static const char _ELIMIT[]      = "Internal limits exceeded";
-
-  switch (cdiErrno) {
-  case CDI_ESYSTEM:
-    {
-      const char *cp = strerror(errno);
-      if ( cp == NULL ) break;
-      return cp;
-    }
-  case CDI_EUFTYPE:    return _EUFTYPE;
-  case CDI_ELIBNAVAIL: return _ELIBNAVAIL;
-  case CDI_EUFSTRUCT:  return _EUFSTRUCT;
-  case CDI_EUNC4:      return _EUNC4;
-  case CDI_ELIMIT:     return _ELIMIT;
-  }
-
-  return UnknownError;
-}
-
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -4618,134 +4578,373 @@ extern void    memFree   (void *ptr, const char *file, const char *functionname,
  * require-trailing-newline: t
  * End:
  */
-#ifndef _GRIBAPI_H
-#define _GRIBAPI_H
+#ifndef  CDF_UTIL_H_
+#define  CDF_UTIL_H_
 
-#ifdef HAVE_LIBGRIB_API
-#include <grib_api.h>
-#ifndef  _ERROR_H
-#endif
-#endif
+#include <stdbool.h>
+
+void str_tolower(char *str);
+bool str_is_equal(const char *vstr, const char *cstr);
+
+int get_timeunit(size_t len, const char *ptu);
+
+bool is_time_units(const char *timeunits);
+bool is_timeaxis_units(const char *timeunits);
+
+bool is_height_units(const char *units);
+bool is_pressure_units(const char *units);
+bool is_DBL_axis(/*const char *units,*/ const char *longname);
+bool is_depth_axis(const char *stdname, const char *longname);
+bool is_height_axis(const char *stdname, const char *longname);
+
+bool is_lon_axis(const char *units, const char *stdname);
+bool is_lat_axis(const char *units, const char *stdname);
+
+bool is_x_axis(const char *units, const char *stdname);
+bool is_y_axis(const char *units, const char *stdname);
+
+void set_gridtype(const char *attstring, int *gridtype);
+void set_zaxistype(const char *attstring, int *zaxistype);
+void set_calendar(const char *attstring, int *calendar);
 
-#ifndef  _CDI_INT_H
 #endif
+#include <string.h>
+#include <ctype.h>
 
-#define  GRIBAPI_MISSVAL  -9.E33
 
-/* GRIB2 Level Types */
-#define  GRIB2_LTYPE_SURFACE               1
-#define  GRIB2_LTYPE_CLOUD_BASE            2
-#define  GRIB2_LTYPE_CLOUD_TOP             3
-#define  GRIB2_LTYPE_ISOTHERM0             4
-#define  GRIB2_LTYPE_TOA                   8
-#define  GRIB2_LTYPE_SEA_BOTTOM            9
-#define  GRIB2_LTYPE_ATMOSPHERE           10
-#define  GRIB2_LTYPE_ISOBARIC            100
-#define  GRIB2_LTYPE_MEANSEA             101
-#define  GRIB2_LTYPE_ALTITUDE            102
-#define  GRIB2_LTYPE_HEIGHT              103
-#define  GRIB2_LTYPE_SIGMA               104
-#define  GRIB2_LTYPE_HYBRID              105
-#define  GRIB2_LTYPE_LANDDEPTH           106
-#define  GRIB2_LTYPE_ISENTROPIC          107
-#define  GRIB2_LTYPE_SNOW                114
-#define  GRIB2_LTYPE_REFERENCE           150
-#define  GRIB2_LTYPE_SEADEPTH            160  /* Depth Below Sea Level                                 */
-#define  GRIB2_LTYPE_LAKE_BOTTOM         162  /* Lake or River Bottom                                  */
-#define  GRIB2_LTYPE_SEDIMENT_BOTTOM     163  /* Bottom Of Sediment Layer                              */
-#define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TA  164  /* Bottom Of Thermally Active Sediment Layer             */
-#define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TW  165  /* Bottom Of Sediment Layer Penetrated By Thermal Wave   */
-#define  GRIB2_LTYPE_MIX_LAYER           166  /* Mixing Layer                                          */
+void str_tolower(char *str)
+{
+  if ( str )
+    for ( size_t i = 0; str[i]; ++i )
+      str[i] = (char)tolower((int)str[i]);
+}
 
-/* GRIB2 Data representation type (Grid Type) */
-#define  GRIB2_GTYPE_LATLON                0  /*  latitude/longitude                                   */
-#define  GRIB2_GTYPE_LATLON_ROT            1  /*  rotated latitude/longitude                           */
-#define  GRIB2_GTYPE_LATLON_STR            2  /*  stretched latitude/longitude                         */
-#define  GRIB2_GTYPE_LATLON_ROTSTR         3  /*  rotated and stretched latitude/longitude             */
-#define  GRIB2_GTYPE_GAUSSIAN             40  /*  gaussian grid                                        */
-#define  GRIB2_GTYPE_GAUSSIAN_ROT         41  /*  rotated gaussian grid                                */
-#define  GRIB2_GTYPE_GAUSSIAN_STR         42  /*  stretched gaussian grid                              */
-#define  GRIB2_GTYPE_GAUSSIAN_ROTSTR      43  /*  rotated and stretched gaussian grid                  */
-#define  GRIB2_GTYPE_LCC                  30  /*  Lambert conformal                                    */
-#define  GRIB2_GTYPE_SPECTRAL             50  /*  spherical harmonics                                  */
-#define  GRIB2_GTYPE_GME                 100  /*  hexagonal GME grid                                   */
-#define  GRIB2_GTYPE_UNSTRUCTURED        101  /*  General Unstructured Grid                            */
 
-const char *gribapiLibraryVersionString(void);
-void gribContainersNew(stream_t * streamptr);
-void gribContainersDelete(stream_t * streamptr);
+bool str_is_equal(const char *vstr, const char *cstr)
+{
+  bool is_equal = false;
+  size_t clen = (cstr != NULL) ? strlen(cstr) : 0;
 
-#ifdef HAVE_LIBGRIB_API
-static inline void *gribHandleNew(int editionNumber)
+  if ( vstr && *vstr ) is_equal = (memcmp(vstr, cstr, clen) == 0);
+
+  return is_equal;
+}
+
+int get_timeunit(size_t len, const char *ptu)
 {
-  void *gh = (void *)grib_handle_new_from_samples(NULL, (editionNumber == 1) ? "GRIB1" : "GRIB2");
+  int timeunit = -1;
 
-  if ( gh == NULL ) Error("grib_handle_new_from_samples failed!");
+  while ( isspace(*ptu) && len ) { ptu++; len--; }
 
-  return gh;
+  if ( len > 2 )
+    {
+      if      ( str_is_equal(ptu, "sec") )            timeunit = TUNIT_SECOND;
+      else if ( str_is_equal(ptu, "minute") )         timeunit = TUNIT_MINUTE;
+      else if ( str_is_equal(ptu, "hour") )           timeunit = TUNIT_HOUR;
+      else if ( str_is_equal(ptu, "day") )            timeunit = TUNIT_DAY;
+      else if ( str_is_equal(ptu, "month") )          timeunit = TUNIT_MONTH;
+      else if ( str_is_equal(ptu, "calendar_month") ) timeunit = TUNIT_MONTH;
+      else if ( str_is_equal(ptu, "year") )           timeunit = TUNIT_YEAR;
+    }
+  else if ( len == 1 && ptu[0] == 's' )  timeunit = TUNIT_SECOND;
+
+  return timeunit;
 }
 
-static inline int my_grib_set_double(grib_handle* h, const char* key, double val)
+
+bool is_time_units(const char *timeunits)
 {
-  if ( cdiGribApiDebug )
-    fprintf(stderr, "grib_set_double(\tgrib_handle* h, \"%s\", %f)\n", key, val);
+  while ( isspace(*timeunits) ) timeunits++; 
 
-  int ret_val = grib_set_double(h, key, val);
-  if (ret_val != 0)
-    fprintf(stderr, "!!! failed call to grib_set_double(\tgrib_handle* h, \"%s\", %f) !!!\n", key, val);
-  return ret_val;
+  bool status = str_is_equal(timeunits, "sec")
+             || str_is_equal(timeunits, "minute")
+             || str_is_equal(timeunits, "hour")
+             || str_is_equal(timeunits, "day")
+             || str_is_equal(timeunits, "month")
+             || str_is_equal(timeunits, "calendar_month")
+             || str_is_equal(timeunits, "year");
+
+  return status;
 }
 
-static inline int my_grib_set_long(grib_handle* h, const char* key, long val)
+
+bool is_timeaxis_units(const char *timeunits)
 {
-  if ( cdiGribApiDebug )
-    fprintf(stderr, "grib_set_long(  \tgrib_handle* h, \"%s\", %ld)\n", key, val);
+  bool status = false;
 
-  int ret_val = grib_set_long(h, key, val);
-  if (ret_val != 0)
-    fprintf(stderr, "!!! failed call to grib_set_long(  \tgrib_handle* h, \"%s\", %ld) !!!\n", key, val);
-  return ret_val;
+  size_t len = strlen(timeunits);
+  char *tu = (char *) Malloc((len+1)*sizeof(char));
+  memcpy(tu, timeunits, (len+1) * sizeof(char));
+  char *ptu = tu;
+
+  for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
+
+  int timeunit = get_timeunit(len, ptu);
+  if ( timeunit != -1 )
+    {
+      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+      if ( *ptu )
+        {
+          while ( isspace(*ptu) ) ptu++;
+
+          int timetype = str_is_equal(ptu, "as") ? TAXIS_ABSOLUTE :
+                         str_is_equal(ptu, "since") ? TAXIS_RELATIVE : -1;
+
+          status = timetype != -1;
+        }
+    }
+
+  Free(tu);
+
+  return status;
 }
 
-static inline int my_grib_set_string(grib_handle* h, const char* key, const char* val, size_t* length)
+
+bool is_height_units(const char *units)
 {
-  if ( cdiGribApiDebug )
-    fprintf(stderr, "grib_set_string(\tgrib_handle* h, \"%s\", \"%s\")\n", key, val);
+  int u0 = units[0];
 
-  int ret_val = grib_set_string(h, key, val, length);
-  if (ret_val != 0)
-    fprintf(stderr, "!!! grib_set_string(\tgrib_handle* h, \"%s\", \"%s\") !!!\n", key, val);
-  return ret_val;
+  bool status
+    = (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0))
+    || (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k'));
+
+  return status;
 }
 
-static inline void gribHandleDelete(void *gh)
+
+bool is_pressure_units(const char *units)
 {
-  grib_handle_delete((struct grib_handle *)gh);
+  bool status = false;
+
+  if ( strncmp(units, "millibar", 8) == 0 ||
+       strncmp(units, "mb", 2)       == 0 ||
+       strncmp(units, "hectopas", 8) == 0 ||
+       strncmp(units, "hPa", 3)      == 0 ||
+       strncmp(units, "Pa", 2)       == 0 )
+    {
+      status = true;
+    }
+
+  return status;
 }
-#else
-#define gribHandleNew(editionNumber) (NULL)
-#define gribHandleDelete(gh)
-#endif
 
-typedef struct {
-  int init;
-  void *gribHandle;
+
+bool is_DBL_axis(/*const char *units,*/ const char *longname)
+{
+  bool status = false;
+
+  if ( strcmp(longname, "depth below land")         == 0 ||
+       strcmp(longname, "depth_below_land")         == 0 ||
+       strcmp(longname, "levels below the surface") == 0 )
+    {
+      /*
+      if ( strcmp(ncvars[ncvarid].units, "cm") == 0 ||
+           strcmp(ncvars[ncvarid].units, "dm") == 0 ||
+           strcmp(ncvars[ncvarid].units, "m")  == 0 )
+      */
+        status = true;
+    }
+
+  return status;
 }
-gribContainer_t;
 
-#endif  /* _GRIBAPI_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
+
+bool is_depth_axis(const char *stdname, const char *longname)
+{
+  bool status = false;
+
+  if ( strcmp(stdname, "depth") == 0 )
+    status = true;
+  else
+    if ( strcmp(longname, "depth_below_sea") == 0 ||
+         strcmp(longname, "depth below sea") == 0 )
+      {
+        status = true;
+      }
+
+  return status;
+}
+
+
+bool is_height_axis(const char *stdname, const char *longname)
+{
+  bool status = false;
+
+  if ( strcmp(stdname, "height") == 0 )
+    status = true;
+  else
+    if ( strcmp(longname, "height") == 0 ||
+         strcmp(longname, "height above the surface") == 0 )
+      {
+        status = true;
+      }
+
+  return status;
+}
+
+
+bool is_lon_axis(const char *units, const char *stdname)
+{
+  bool status = false;
+  char lc_units[16];
+
+  memcpy(lc_units, units, 15);
+  lc_units[15] = 0;
+  str_tolower(lc_units);
+
+  if ( (str_is_equal(lc_units, "degree") || str_is_equal(lc_units, "radian")) &&
+       (str_is_equal(stdname, "grid_longitude") || str_is_equal(stdname, "longitude")) )
+    {
+      status = true;
+    }
+  else if ( str_is_equal(lc_units, "degree")
+            && !str_is_equal(stdname, "grid_latitude")
+            && !str_is_equal(stdname, "latitude") )
+    {
+      int ioff = 6;
+      if ( lc_units[ioff] == 's' ) ioff++;
+      if ( lc_units[ioff] == '_' ) ioff++;
+      if ( lc_units[ioff] == 'e' ) status = true;
+    }
+
+  return status;
+}
+
+
+bool is_lat_axis(const char *units, const char *stdname)
+{
+  bool status = false;
+  char lc_units[16];
+
+  memcpy(lc_units, units, 15);
+  lc_units[15] = 0;
+  str_tolower(lc_units);
+
+  if ( (str_is_equal(lc_units, "degree") || str_is_equal(lc_units, "radian")) &&
+        (str_is_equal(stdname, "grid_latitude") || str_is_equal(stdname, "latitude")) )
+    {
+      status = true;
+    }
+  else if ( str_is_equal(lc_units, "degree")
+            && !str_is_equal(stdname, "grid_longitude")
+            && !str_is_equal(stdname, "longitude") )
+    {
+      int ioff = 6;
+      if ( lc_units[ioff] == 's' ) ioff++;
+      if ( lc_units[ioff] == '_' ) ioff++;
+      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = true;
+    }
+
+  return status;
+}
+
+
+bool is_x_axis(const char *units, const char *stdname)
+{
+  (void)units;
+  return (strcmp(stdname, "projection_x_coordinate") == 0);
+}
+
+
+bool is_y_axis(const char *units, const char *stdname)
+{
+  (void)units;
+  return (strcmp(stdname, "projection_y_coordinate") == 0);
+}
+
+
+void set_gridtype(const char *attstring, int *gridtype)
+{
+  if      ( strcmp(attstring, "gaussian reduced") == 0 )
+    *gridtype = GRID_GAUSSIAN_REDUCED;
+  else if ( strcmp(attstring, "gaussian") == 0 )
+    *gridtype = GRID_GAUSSIAN;
+  else if ( strncmp(attstring, "spectral", 8) == 0 )
+    *gridtype = GRID_SPECTRAL;
+  else if ( strncmp(attstring, "fourier", 7) == 0 )
+    *gridtype = GRID_FOURIER;
+  else if ( strcmp(attstring, "trajectory") == 0 )
+    *gridtype = GRID_TRAJECTORY;
+  else if ( strcmp(attstring, "generic") == 0 )
+    *gridtype = GRID_GENERIC;
+  else if ( strcmp(attstring, "cell") == 0 )
+    *gridtype = GRID_UNSTRUCTURED;
+  else if ( strcmp(attstring, "unstructured") == 0 )
+    *gridtype = GRID_UNSTRUCTURED;
+  else if ( strcmp(attstring, "curvilinear") == 0 )
+    *gridtype = GRID_CURVILINEAR;
+  else if ( strcmp(attstring, "characterxy") == 0 )
+    *gridtype = GRID_CHARXY;
+  else if ( strcmp(attstring, "sinusoidal") == 0 )
+    ;
+  else if ( strcmp(attstring, "laea") == 0 )
+    ;
+  else if ( strcmp(attstring, "lcc2") == 0 )
+    ;
+  else if ( strcmp(attstring, "linear") == 0 ) // ignore grid type linear
+    ;
+  else
+    {
+      static bool warn = true;
+      if ( warn )
+        {
+          warn = false;
+          Warning("NetCDF attribute grid_type='%s' unsupported!", attstring);
+        }
+    }
+}
+
+
+void set_zaxistype(const char *attstring, int *zaxistype)
+{
+  if      ( strcmp(attstring, "toa") == 0 ) *zaxistype = ZAXIS_TOA;
+  else if ( strcmp(attstring, "cloudbase") == 0 ) *zaxistype = ZAXIS_CLOUD_BASE;
+  else if ( strcmp(attstring, "cloudtop") == 0 ) *zaxistype = ZAXIS_CLOUD_TOP;
+  else if ( strcmp(attstring, "isotherm0") == 0 ) *zaxistype = ZAXIS_ISOTHERM_ZERO;
+  else if ( strcmp(attstring, "seabottom") == 0 ) *zaxistype = ZAXIS_SEA_BOTTOM;
+  else if ( strcmp(attstring, "lakebottom") == 0 ) *zaxistype = ZAXIS_LAKE_BOTTOM;
+  else if ( strcmp(attstring, "sedimentbottom") == 0 ) *zaxistype = ZAXIS_SEDIMENT_BOTTOM;
+  else if ( strcmp(attstring, "sedimentbottomta") == 0 ) *zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;
+  else if ( strcmp(attstring, "sedimentbottomtw") == 0 ) *zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;
+  else if ( strcmp(attstring, "mixlayer") == 0 ) *zaxistype = ZAXIS_MIX_LAYER;
+  else if ( strcmp(attstring, "atmosphere") == 0 ) *zaxistype = ZAXIS_ATMOSPHERE;
+  else
+    {
+      static bool warn = true;
+      if ( warn )
+        {
+          warn = false;
+          Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
+        }
+    }  
+}
+
+
+void set_calendar(const char *attstring, int *calendar)
+{
+  if ( str_is_equal(attstring, "standard") )
+    *calendar = CALENDAR_STANDARD;
+  else if ( str_is_equal(attstring, "gregorian") )
+    *calendar = CALENDAR_GREGORIAN;
+  else if ( str_is_equal(attstring, "none") )
+    *calendar = CALENDAR_NONE;
+  else if ( str_is_equal(attstring, "proleptic") )
+    *calendar = CALENDAR_PROLEPTIC;
+  else if ( str_is_equal(attstring, "360") )
+    *calendar = CALENDAR_360DAYS;
+  else if ( str_is_equal(attstring, "365") ||
+            str_is_equal(attstring, "noleap") )
+    *calendar = CALENDAR_365DAYS;
+  else if ( str_is_equal(attstring, "366") ||
+            str_is_equal(attstring, "all_leap") )
+    *calendar = CALENDAR_366DAYS;
+  else
+    Warning("calendar >%s< unsupported!", attstring);
+}
 #ifndef _STREAM_CDF_H
 #define _STREAM_CDF_H
 
+
 void   cdfDefVars(stream_t *streamptr);
 void   cdfDefTimestep(stream_t *streamptr, int tsID);
 int    cdfInqTimestep(stream_t *streamptr, int tsID);
@@ -4759,21 +4958,27 @@ void   cdfDefRecord(stream_t * streamptr);
 
 void   cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void   cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
-void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
+void   cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID);
+
+void   cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
+void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
 
-void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
-void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
+void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
+void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
 
-void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
-void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
+void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
+void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
 
 void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                           const int rect[][2], const void *data, int nmiss);
+                           const int rect[][2], const void *data, size_t nmiss);
 
 void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
 void cdfDefTime(stream_t* streamptr);
 
+void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor);
+
+int cdfDefDatatype(int datatype, int filetype);
+
 #endif
 /*
  * Local Variables:
@@ -4784,870 +4989,810 @@ void cdfDefTime(stream_t* streamptr);
  * require-trailing-newline: t
  * End:
  */
-#ifndef _CGRIBEX_H
-#define _CGRIBEX_H
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#define  GRIB_MISSVAL  -9.E33
+#ifndef CDI_ATT_H
+#define CDI_ATT_H
 
-/* GRIB1 Level Types */
-#define  GRIB1_LTYPE_SURFACE               1
-#define  GRIB1_LTYPE_CLOUD_BASE            2
-#define  GRIB1_LTYPE_CLOUD_TOP             3
-#define  GRIB1_LTYPE_ISOTHERM0             4
-#define  GRIB1_LTYPE_TOA                   8
-#define  GRIB1_LTYPE_SEA_BOTTOM            9
-#define  GRIB1_LTYPE_ATMOSPHERE           10
-#define  GRIB1_LTYPE_99                   99
-#define  GRIB1_LTYPE_ISOBARIC            100
-#define  GRIB1_LTYPE_MEANSEA             102
-#define  GRIB1_LTYPE_ALTITUDE            103
-#define  GRIB1_LTYPE_HEIGHT              105
-#define  GRIB1_LTYPE_SIGMA               107
-#define  GRIB1_LTYPE_SIGMA_LAYER         108
-#define  GRIB1_LTYPE_HYBRID              109
-#define  GRIB1_LTYPE_HYBRID_LAYER        110
-#define  GRIB1_LTYPE_LANDDEPTH           111
-#define  GRIB1_LTYPE_LANDDEPTH_LAYER     112
-#define  GRIB1_LTYPE_ISENTROPIC          113
-#define  GRIB1_LTYPE_SEADEPTH            160  /* Depth Below Sea Level                                 */
-#define  GRIB1_LTYPE_LAKE_BOTTOM         162  /* Lake or River Bottom                                  */
-#define  GRIB1_LTYPE_SEDIMENT_BOTTOM     163  /* Bottom Of Sediment Layer                              */
-#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TA  164  /* Bottom Of Thermally Active Sediment Layer             */
-#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TW  165  /* Bottom Of Sediment Layer Penetrated By Thermal Wave   */
-#define  GRIB1_LTYPE_MIX_LAYER           166  /* Mixing Layer                                          */
-#define  GRIB1_LTYPE_99_MARGIN          1000
+#ifdef HAVE_CONFIG_H
+#endif
 
-/* GRIB1 Data representation type (Grid Type) [Table 6] */
-#define  GRIB1_GTYPE_LATLON                0  /*  latitude/longitude                                   */
-#define  GRIB1_GTYPE_LATLON_ROT           10  /*  rotated latitude/longitude                           */
-#define  GRIB1_GTYPE_LATLON_STR           20  /*  stretched latitude/longitude                         */
-#define  GRIB1_GTYPE_LATLON_ROTSTR        30  /*  rotated and stretched latitude/longitude             */
-#define  GRIB1_GTYPE_GAUSSIAN              4  /*  gaussian grid                                        */
-#define  GRIB1_GTYPE_GAUSSIAN_ROT         14  /*  rotated gaussian grid                                */
-#define  GRIB1_GTYPE_GAUSSIAN_STR         24  /*  stretched gaussian grid                              */
-#define  GRIB1_GTYPE_GAUSSIAN_ROTSTR      34  /*  rotated and stretched gaussian grid                  */
-#define  GRIB1_GTYPE_LCC                   3  /*  Lambert conformal                                    */
-#define  GRIB1_GTYPE_SPECTRAL             50  /*  spherical harmonics                                  */
-#define  GRIB1_GTYPE_GME                 192  /*  hexagonal GME grid                                   */
+#ifndef _CDI_LIMITS_H
+#endif
 
 /*
- *  Macros for the indicator section ( Section 0 )
+ * CDI attribute
  */
-#define  ISEC0_GRIB_Len             (isec0[ 0])  /*  Number of octets in the GRIB message              */
-#define  ISEC0_GRIB_Version         (isec0[ 1])  /*  GRIB edition number                               */
+typedef struct {
+  size_t    xsz;	  /* amount of space at xvalue                      */
+  size_t    namesz;       /* size of name                                   */
+  char     *name;         /* attribute name                                 */
+  int       indtype;	  /* internal data type of xvalue (INT, FLT or TXT) */
+  int       exdtype;      /* external data type                             */
+                          /* indtype    exdtype                             */
+                          /* TXT        TXT                                 */
+                          /* INT        INT16, INT32                        */
+                          /* FLT        FLT32, FLT64                        */
+  size_t    nelems;    	  /* number of elements                             */
+  void     *xvalue;       /* the actual data                                */
+} cdi_att_t;
 
 
-/*
- *  Macros for the product definition section ( Section 1 )
- */
-#define  ISEC1_TABLE4_MINUTE      0
-#define  ISEC1_TABLE4_HOUR        1
-#define  ISEC1_TABLE4_DAY         2
-#define  ISEC1_TABLE4_3HOURS     10
-#define  ISEC1_TABLE4_6HOURS     11
-#define  ISEC1_TABLE4_12HOURS    12
-#define  ISEC1_TABLE4_QUARTER    13
-#define  ISEC1_TABLE4_30MINUTES  14
+typedef struct {
+  size_t     nalloc;		/* number allocated >= nelems */
+  size_t     nelems;		/* length of the array */
+  cdi_att_t  value[MAX_ATTRIBUTES];
+} cdi_atts_t;
 
 
-#define  ISEC1_CodeTable            (isec1[ 0])  /*  Version number of code table                 */
-#define  ISEC1_CenterID             (isec1[ 1])  /*  Identification of centre                     */
-#define  ISEC1_ModelID              (isec1[ 2])  /*  Identification of model                      */
-#define  ISEC1_GridDefinition       (isec1[ 3])  /*  Grid definition                              */
-#define  ISEC1_Sec2Or3Flag          (isec1[ 4])  /*  Section 2 or 3 included                      */
-#define  ISEC1_Parameter            (isec1[ 5])  /*  Parameter indicator                          */
-#define  ISEC1_LevelType            (isec1[ 6])  /*  Type of level indicator                      */
-#define  ISEC1_Level1               (isec1[ 7])  /*  Level 1                                      */
-#define  ISEC1_Level2               (isec1[ 8])  /*  Level 2                                      */
-#define  ISEC1_Year                 (isec1[ 9])  /*  Year of century (YY)                         */
-#define  ISEC1_Month                (isec1[10])  /*  Month (MM)                                   */
-#define  ISEC1_Day                  (isec1[11])  /*  Day (DD)                                     */
-#define  ISEC1_Hour                 (isec1[12])  /*  Hour (HH)                                    */
-#define  ISEC1_Minute               (isec1[13])  /*  Minute (MM)                                  */
-#define  ISEC1_TimeUnit             (isec1[14])  /*  Time unit indicator                          */
-#define  ISEC1_TimePeriod1          (isec1[15])  /*  P1 Time period                               */
-#define  ISEC1_TimePeriod2          (isec1[16])  /*  P2 Time period                               */
-#define  ISEC1_TimeRange            (isec1[17])  /*  Time range indicator                         */
-#define  ISEC1_AvgNum               (isec1[18])  /*  Number of products included in an average    */
-#define  ISEC1_AvgMiss              (isec1[19])  /*  Number of products missing from an average   */
-#define  ISEC1_Century              (isec1[20])  /*  Century                                      */
-#define  ISEC1_SubCenterID          (isec1[21])  /*  Subcenter identifier                         */
-#define  ISEC1_DecScaleFactor       (isec1[22])  /*  Decimal scale factor                         */
-#define  ISEC1_LocalFLag            (isec1[23])  /*  Flag field to indicate local use in isec1    */
+int cdiAttsGetSize(void *p, int varID, void *context);
 
-#define  ISEC1_ECMWF_LocalExtension (isec1[36])
-#define  ISEC1_ECMWF_Class          (isec1[37])
+void cdiAttsPack(void *p, int varID, void *buf, int size, int *position, void *context);
 
+void cdiAttsUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context);
+
+#endif
 
 /*
- *  Macros for the grid definition section ( Section 2 )
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
  */
-#define  ISEC2_GridType             (isec2[ 0])  /* Data representation type */
+#ifndef _GRID_H
+#define _GRID_H
 
-/* Triangular grids */
+#include <stdbool.h>
 
-#define  ISEC2_GME_NI2              (isec2[ 1])  /*  Number of factor 2 in factorisation of Ni    */
-#define  ISEC2_GME_NI3              (isec2[ 2])  /*  Number of factor 3 in factorisation of Ni    */
-#define  ISEC2_GME_ND               (isec2[ 3])  /*  Nubmer of diamonds                           */
-#define  ISEC2_GME_NI               (isec2[ 4])  /*  Number of tri. subdiv. of the icosahedron    */
-#define  ISEC2_GME_AFlag            (isec2[ 5])  /*  Flag for orientation of diamonds (Table A)   */
-#define  ISEC2_GME_LatPP            (isec2[ 6])  /*  Latitude of pole point                       */
-#define  ISEC2_GME_LonPP            (isec2[ 7])  /*  Longitude of pole point                      */
-#define  ISEC2_GME_LonMPL           (isec2[ 8])  /*  Longitude of the first diamond               */
-#define  ISEC2_GME_BFlag            (isec2[ 9])  /*  Flag for storage sequence (Table B)          */
 
-/* Spherical harmonic coeficients */
+extern double grid_missval;
+extern int (*proj_lonlat_to_lcc_func)();
+extern int (*proj_lcc_to_lonlat_func)();
 
-#define  ISEC2_PentaJ               (isec2[ 1])  /*  J pentagonal resolution parameter            */
-#define  ISEC2_PentaK               (isec2[ 2])  /*  K pentagonal resolution parameter            */
-#define  ISEC2_PentaM               (isec2[ 3])  /*  M pentagonal resolution parameter            */
-#define  ISEC2_RepType              (isec2[ 4])  /*  Representation type                          */
-#define  ISEC2_RepMode              (isec2[ 5])  /*  Representation mode                          */
+typedef unsigned char mask_t;
 
-/* Gaussian grids */
+typedef struct grid_t grid_t;
 
-#define  ISEC2_NumLon               (isec2[ 1])  /*  Number of points along a parallel (Ni)       */
-#define  ISEC2_NumLat               (isec2[ 2])  /*  Number of points along a meridian (Nj)       */
-#define  ISEC2_FirstLat             (isec2[ 3])  /*  Latitude of the first grid point             */
-#define  ISEC2_FirstLon             (isec2[ 4])  /*  Longitude of the first grid point            */
-#define  ISEC2_ResFlag              (isec2[ 5])  /*  Resolution flag: 128 regular grid            */
-#define  ISEC2_LastLat              (isec2[ 6])  /*  Latitude of the last grid point              */
-#define  ISEC2_LastLon              (isec2[ 7])  /*  Longitude of the last grid point             */
-#define  ISEC2_LonIncr              (isec2[ 8])  /*  i direction increment                        */
-#define  ISEC2_LatIncr              (isec2[ 9])  /*  j direction increment                        */
-#define  ISEC2_NumPar               (isec2[ 9])  /*  Number of parallels between a pole and the E.*/
-#define  ISEC2_ScanFlag             (isec2[10])  /*  Scanning mode flags                          */
-#define  ISEC2_NumVCP               (isec2[11])  /*  Number of vertical coordinate parameters     */
+struct gridVirtTable
+{
+  void (*destroy)(grid_t *gridptr);
+  grid_t *(*copy)(grid_t *gridptr);
+  void (*copyScalarFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*copyArrayFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
+  void (*defXVals)(grid_t *gridptr, const double *xvals);
+  void (*defYVals)(grid_t *gridptr, const double *yvals);
+  void (*defMask)(grid_t *gridptr, const int *mask);
+  void (*defMaskGME)(grid_t *gridptr, const int *mask);
+  void (*defXBounds)(grid_t *gridptr, const double *xbounds);
+  void (*defYBounds)(grid_t *gridptr, const double *ybounds);
+  void (*defArea)(grid_t *gridptr, const double *area);
+  double (*inqXVal)(grid_t *gridptr, size_t index);
+  double (*inqYVal)(grid_t *gridptr, size_t index);
+  size_t (*inqXVals)(grid_t *gridptr, double *xvals);
+  size_t (*inqXCvals)(grid_t *gridptr, char **xcvals);
+  int (*inqXIsc)(grid_t *gridptr);
+  size_t (*inqYVals)(grid_t *gridptr, double *yvals);
+  size_t (*inqYCvals)(grid_t *gridptr, char **ycvals);
+  int (*inqYIsc)(grid_t *gridptr);
+  const double *(*inqXValsPtr)(grid_t *gridptr);
+  const char **(*inqXCvalsPtr)(grid_t *gridptr);
+  const double *(*inqYValsPtr)(grid_t *gridptr);
+  const char **(*inqYCvalsPtr)(grid_t *gridptr);
+  /* return if for both grids, all xval and all yval are equal */
+  bool (*compareXYFull)(grid_t *gridRef, grid_t *gridTest);
+  /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are
+   * respectively equal */
+  bool (*compareXYAO)(grid_t *gridRef, grid_t *gridTest);
+  void (*inqArea)(grid_t *gridptr, double *area);
+  const double *(*inqAreaPtr)(grid_t *gridptr);
+  int (*hasArea)(grid_t *gridptr);
+  size_t (*inqMask)(grid_t *gridptr, int *mask);
+  int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
+  size_t (*inqXBounds)(grid_t *gridptr, double *xbounds);
+  size_t (*inqYBounds)(grid_t *gridptr, double *ybounds);
+  const double *(*inqXBoundsPtr)(grid_t *gridptr);
+  const double *(*inqYBoundsPtr)(grid_t *gridptr);
+};
 
-/* Lambert */
-#define  ISEC2_Lambert_Lov          (isec2[ 6])  /*  Orientation of the grid                      */
-#define  ISEC2_Lambert_dx           (isec2[ 8])  /*  X-direction grid length                      */
-#define  ISEC2_Lambert_dy           (isec2[ 9])  /*  Y-direction grid length                      */
-#define  ISEC2_Lambert_ProjFlag     (isec2[12])  /*  Projection centre flag                       */
-#define  ISEC2_Lambert_LatS1        (isec2[13])  /*  First lat at which the secant cone cuts the sphere */
-#define  ISEC2_Lambert_LatS2        (isec2[14])  /*  Second lat at which the secant cone cuts the sphere */
-#define  ISEC2_Lambert_LatSP        (isec2[19])  /*  Latitude of the southern pole                */
-#define  ISEC2_Lambert_LonSP        (isec2[20])  /*  Longitude of the southern pole               */
+struct gridaxis_t {
+  char    name[CDI_MAX_NAME];
+  char    longname[CDI_MAX_NAME];
+  char    units[CDI_MAX_NAME];
+  char    dimname[CDI_MAX_NAME];
+  const char *stdname;
+  size_t  size;                  // number of values
+  short   flag;                  // 0: undefined 1:vals 2:first+inc
+  double  first, last, inc;
+  double *vals;
+  int clength;
+  char  **cvals;
+  double *bounds;
+};
 
+// GME Grid
+struct grid_gme_t {
+  int     nd, ni, ni2, ni3;       /* parameter for GRID_GME         */
+};
 
-#define  ISEC2_Reduced              (isec2[16])  /* 0: regular, 1: reduced grid                   */
+struct grid_t {
+  char    vdimname[CDI_MAX_NAME];
+  char    mapname[CDI_MAX_NAME];
+  char    mapping[CDI_MAX_NAME];
+  char   *name;
+  int     self;
+  size_t  size;
+  int     type;                   /* grid type                      */
+  int     datatype;               /* grid data type                 */
+  int     proj;                   /* grid projection                */
+  int     projtype;               /* grid projection type           */
+  mask_t *mask;
+  mask_t *mask_gme;
+  double *area;
+  struct grid_gme_t  gme;
+  int     number, position;       /* parameter for GRID_REFERENCE   */
+  int     trunc;                  /* parameter for GRID_SPECTEAL    */
+  int     nvertex;
+  char   *reference;
+  unsigned char uuid[CDI_UUID_SIZE]; /* uuid for grid reference        */
+  int    *rowlon;
+  int     nrowlon;
+  int     np;                     /* number of parallels between a pole and the equator */
+  signed char isCyclic;           /* three possible states:
+                                   * -1 if unknown,
+                                   * 0 if found not cyclic, or
+                                   * 1 for global cyclic grids
+                                   */
+  bool    lcomplex;
+  bool    hasdims;
+  bool uvRelativeToGrid;  /* Some models deliver wind U,V relative to the grid-cell */
+  struct gridaxis_t x;
+  struct gridaxis_t y;
+  const struct gridVirtTable *vtable;
+  cdi_atts_t atts;
+  int  scanningMode;
+  bool iScansNegatively, jScansPositively, jPointsAreConsecutive;
+  /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
+               64  = 128 * 0                + 64 *        1         + 32 * 0
+               00  = 128 * 0                + 64 *        0         + 32 * 0
+               96  = 128 * 0                + 64 *        1         + 32 * 1
+     Default / implicit scanning mode is 64:
+                        i and j scan positively, i points are consecutive (row-major)        */
+};
 
-#define  ISEC2_RowLonPtr            (&isec2[22])
-#define  ISEC2_RowLon(i)            (isec2[22+i]) /* Number of points along each parallel         */
 
-/* */
+void grid_init(grid_t *gridptr);
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size);
+void grid_free(grid_t *gridptr);
+grid_t *grid_to_pointer(int gridID);
+extern const struct gridVirtTable cdiGridVtable;
 
-#define  ISEC2_LatSP                (isec2[12])  /* Latitude of the southern pole of rotation     */
-#define  ISEC2_LonSP                (isec2[13])  /* Longitude of the southern pole of rotation    */
+unsigned cdiGridCount(void);
 
-#define  FSEC2_RotAngle             (fsec2[ 0])  /* Angle of rotation                             */
-#define  FSEC2_StrFact              (fsec2[ 1])  /* Stretching factor                             */
+void gridVerifyProj(int gridID);
 
-/*
- *  Macros for the bit map section ( Section 3 )
- */
-#define  ISEC3_PredefBitmap         (isec3[ 0])  /* Predefined bitmap                             */
-#define  ISEC3_MissVal              (isec3[ 1])  /* Missing data value for integers               */
-#define  FSEC3_MissVal              (fsec3[ 1])  /* Missing data value for floats                 */
-
-/*
- *  Macros for the binary data section ( Section 4 )
- */
-#define  ISEC4_NumValues            (isec4[ 0])  /* Number of data values for encode/decode       */
-#define  ISEC4_NumBits              (isec4[ 1])  /* Number of bits used for each encoded value    */
-#define  ISEC4_NumNonMissValues     (isec4[20])  /* Number of non-missing values                  */
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-void  gribFixZSE(int flag);     /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
-void  gribSetConst(int flag);   /* 1: Don't pack constant fields on regular grids */
-void  gribSetDebug(int debug);  /* 1: Debugging */
-void  gribSetRound(int round);
-void  gribSetRefDP(double refval);
-void  gribSetRefSP(float  refval);
-void  gribSetValueCheck(int vcheck);
-
-
-void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
-               float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, const char *hoper, int *kret);
-
-void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
-               double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-               int kleng, int *kword, const char *hoper, int *kret);
-
-
-const char *cgribexLibraryVersion(void);
-
-void  gribDebug(int debug);
-void  gribSetCalendar(int calendar);
+const double *gridInqXvalsPtr(int gridID);
+const double *gridInqYvalsPtr(int gridID);
 
-void  gribDateTime(int *isec1, int *date, int *time);
-int   gribRefDate(int *isec1);
-int   gribRefTime(int *isec1);
-int   gribTimeIsFC(int *isec1);
+const char **gridInqXCvalsPtr(int gridID);
+const char **gridInqYCvalsPtr(int gridID);
 
-void  gribPrintSec0(int *isec0);
-void  gribPrintSec1(int *isec0, int *isec1);
-void  gribPrintSec2DP(int *isec0, int *isec2, double *fsec2);
-void  gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2);
-void  gribPrintSec3DP(int *isec0, int *isec3, double *fsec3);
-void  gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3);
-void  gribPrintSec4DP(int *isec0, int *isec4, double *fsec4);
-void  gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4);
-void  gribPrintSec4Wave(int *isec4);
+const double *gridInqXboundsPtr(int gridID);
+const double *gridInqYboundsPtr(int gridID);
+const double *gridInqAreaPtr(int gridID);
 
-void  gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
-void  gribRepair1(int nrec, long recsize, unsigned char *gribbuffer);
+const char *gridInqReferencePtr(int gridID);
 
-int   gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize);
+int gridGenerate(const grid_t *grid);
 
-int   gribBzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
-int   gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
-int   gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
+//int gridIsEqual(int gridID1, int gridID2);
 
-int   gribOpen(const char *filename, const char *mode);
-void  gribClose(int fileID);
+void cdiGridGetIndexList(unsigned, int * );
 
-int   gribRead(int fileID, unsigned char *buffer, size_t *buffersize);
-int   gribWrite(int fileID, unsigned char *buffer, size_t buffersize);
-off_t gribGetPos(int fileID);
-int   gribGetSize(int fileID);
-int   gribCheckSeek(int fileID, long *offset, int *version);
-int   gribFileSeek(int fileID, long *offset);
-int   gribReadSize(int fileID);
-int   gribVersion(unsigned char *buffer, size_t buffersize);
+void
+gridUnpack(char * unpackBuffer, int unpackBufferSize,
+           int * unpackBufferPos, int originNamespace, void *context,
+           int force_id);
 
-int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
+struct addIfNewRes
+{
+  int Id;
+  int isNew;
+};
 
-double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
-double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 
+int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
+                           double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0);
 
-#if defined (__cplusplus)
-}
 #endif
-
-#endif  /* _CGRIBEX_H */ 
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef  CDF_LAZY_GRID_H_
+#define  CDF_LAZY_GRID_H_
 
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <stdarg.h>
-#include <ctype.h>
-
-#ifdef HAVE_LIBNETCDF
+#ifdef HAVE_MMAP
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #endif
-
-#if  defined  (HAVE_LIBCGRIBEX)
+#ifdef HAVE_LIBPTHREAD
+#include <pthread.h>
 #endif
 
-int cdiDefaultCalendar = CALENDAR_PROLEPTIC;
+#include <string.h>
 
-int cdiDefaultInstID   = CDI_UNDEFID;
-int cdiDefaultModelID  = CDI_UNDEFID;
-int cdiDefaultTableID  = CDI_UNDEFID;
-//int cdiNcMissingValue  = CDI_UNDEFID;
-int cdiNcChunksizehint = CDI_UNDEFID;
-int cdiChunkType       = CHUNK_GRID;
-int cdiSplitLtype105   = CDI_UNDEFID;
 
-int cdiIgnoreAttCoordinates = FALSE;
-int cdiIgnoreValidRange     = FALSE;
-int cdiSkipRecords          = 0;
-int cdiConvention           = CDI_CONVENTION_ECHAM;
-int cdiInventoryMode        = 1;
-int CDI_Version_Info        = 1;
-int CDI_cmor_mode           = 0;
-size_t CDI_netcdf_hdr_pad   = 0UL;
-bool CDI_netcdf_lazy_grid_load = false;
+struct cdfLazyGrid
+{
+  grid_t base;
+  const struct gridVirtTable *baseVtable;
+  struct cdfLazyGridIds {
+    int datasetNCId, varNCId;
+  } cellAreaGet, xBoundsGet, yBoundsGet;
+  struct xyValGet {
+    double scalefactor, addoffset;
+    size_t start[3], count[3], size, dimsize;
+    int datasetNCId, varNCId;
+    short ndims;
+  } xValsGet, yValsGet;
+#ifdef HAVE_LIBPTHREAD
+  pthread_mutex_t loadSerialize;
+#endif
+};
 
-char *cdiPartabPath   = NULL;
-int   cdiPartabIntern = 1;
 
-double cdiDefaultMissval = -9.E33;
+extern double *cdfPendingLoad;
 
-static const char Filetypes[][9] = {
-  "UNKNOWN",
-  "GRIB",
-  "GRIB2",
-  "NetCDF",
-  "NetCDF2",
-  "NetCDF4",
-  "NetCDF4c",
-  "SERVICE",
-  "EXTRA",
-  "IEG",
-  "HDF5",
-};
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
 
-int CDI_Debug   = 0;    /* If set to 1, debugging           */
-int CDI_Recopt = 0;
+void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid);
 
-int cdiGribApiDebug     = 0;
-int cdiDefaultLeveltype = -1;
-int cdiDataUnreduced = 0;
-int cdiSortName = 0;
-int cdiHaveMissval = 0;
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
+#ifdef HAVE_LIBNETCDF
 
-static long cdiGetenvInt(const char *envName)
-{
-  char *envString;
-  long envValue = -1;
-  long fact = 1;
 
-  envString = getenv(envName);
+static struct gridVirtTable cdfLazyGridVtable;
+double *cdfPendingLoad;
+#ifdef HAVE_LIBPTHREAD
+static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
+#else
+static bool cdfLazyInitialized;
+#endif
 
-  if ( envString )
-    {
-      int loop, len;
 
-      len = (int) strlen(envString);
-      for ( loop = 0; loop < len; loop++ )
-	{
-	  if ( ! isdigit((int) envString[loop]) )
-	    {
-	      switch ( tolower((int) envString[loop]) )
-		{
-		case 'k':  fact = 1024;        break;
-		case 'm':  fact = 1048576;     break;
-		case 'g':  fact = 1073741824;  break;
-		default:
-		  fact = 0;
-		  Message("Invalid number string in %s: %s", envName, envString);
-		  Warning("%s must comprise only digits [0-9].",envName);
-		  break;
-		}
-	      break;
-	    }
-	}
+#ifdef HAVE_LIBPTHREAD
+#define lock_lazy_load(plGrid) pthread_mutex_lock(&((plGrid)->loadSerialize))
+#define unlock_lazy_load(plGrid) pthread_mutex_unlock(&((plGrid)->loadSerialize))
+#define destroy_lazy_load_lock(plGrid) pthread_mutex_destroy(&((plGrid)->loadSerialize))
+#define init_lazy_load_lock(plGrid) pthread_mutex_init(&((plGrid)->loadSerialize), NULL)
+#else
+#define lock_lazy_load(plGrid)
+#define unlock_lazy_load(plGrid)
+#define destroy_lazy_load_lock(plGrid)
+#define init_lazy_load_lock(plGrid)
+#endif
 
-      if ( fact ) envValue = fact*atol(envString);
 
-      if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
-    }
 
-  return (envValue);
+void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid)
+{
+  if (lazyGrid->base.area == cdfPendingLoad)  lazyGrid->base.area = NULL;
+  if (lazyGrid->base.x.vals == cdfPendingLoad) lazyGrid->base.x.vals = NULL;
+  if (lazyGrid->base.y.vals == cdfPendingLoad) lazyGrid->base.y.vals = NULL;
+  if (lazyGrid->base.x.bounds == cdfPendingLoad) lazyGrid->base.x.bounds = NULL;
+  if (lazyGrid->base.y.bounds == cdfPendingLoad) lazyGrid->base.y.bounds = NULL;
+  destroy_lazy_load_lock(lazyGrid);
 }
 
-static void
-cdiPrintDefaults(void)
+static void cdfLazyGridDelete(grid_t *grid)
 {
-  fprintf(stderr, "default instID     :  %d\n"
-          "default modelID    :  %d\n"
-          "default tableID    :  %d\n"
-          "default missval    :  %g\n", cdiDefaultInstID,
-          cdiDefaultModelID, cdiDefaultTableID, cdiDefaultMissval);
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
+  cdfLazyGridDestroy(cdfGrid);
+  baseDestroy(grid);
 }
 
-void cdiPrintVersion(void)
+static void cdfLazyGridDestroyOnce(void)
 {
-  fprintf(stderr, "     CDI library version : %s\n", cdiLibraryVersion());
-#if  defined  (HAVE_LIBCGRIBEX)
-  fprintf(stderr, " CGRIBEX library version : %s\n", cgribexLibraryVersion());
-#endif
-#if  defined  (HAVE_LIBGRIB_API)
-  fprintf(stderr, "GRIB_API library version : %s\n", gribapiLibraryVersionString());
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-  fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
-#endif
-#if  defined  (HAVE_NC4HDF5)
-  fprintf(stderr, "    HDF5 library version : %s\n", hdfLibraryVersion());
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-  fprintf(stderr, " SERVICE library version : %s\n", srvLibraryVersion());
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-  fprintf(stderr, "   EXTRA library version : %s\n", extLibraryVersion());
-#endif
-#if  defined  (HAVE_LIBIEG)
-  fprintf(stderr, "     IEG library version : %s\n", iegLibraryVersion());
+  /*
+#ifdef HAVE_MMAP
+  size_t pgSize = cdiGetPageSize(false);
+  munmap(cdfPendingLoad, pgSize);
 #endif
-  fprintf(stderr, "    FILE library version : %s\n", fileLibraryVersion());
+  */
 }
 
-void cdiDebug(int level)
+static void
+cdfLazyGridDefArea(grid_t *grid, const double *area)
 {
-  if ( level == 1 || (level &  2) ) CDI_Debug = 1;
-
-  if ( CDI_Debug ) Message("debug level %d", level);
-
-  if ( level == 1 || (level &  4) ) memDebug(1);
-
-  if ( level == 1 || (level &  8) ) fileDebug(1);
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->area == cdfPendingLoad) grid->area = NULL;
+  cdfGrid->cellAreaGet.datasetNCId = -1;
+  cdfGrid->cellAreaGet.varNCId = -1;
+  cdfGrid->baseVtable->defArea(grid, area);
+  unlock_lazy_load(cdfGrid);
+}
 
-  if ( level == 1 || (level & 16) )
-    {
-#if  defined  (HAVE_LIBCGRIBEX)
-      gribSetDebug(1);
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-      cdfDebug(1);
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-      srvDebug(1);
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-      extDebug(1);
-#endif
-#if  defined  (HAVE_LIBIEG)
-      iegDebug(1);
-#endif
-    }
 
-  if ( CDI_Debug )
+static const double *
+cdfLazyGridInqAreaPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->area == cdfPendingLoad)
     {
-      cdiPrintDefaults();
-      cdiPrintDatatypes();
+      grid->area = (double *)Malloc((size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->cellAreaGet.datasetNCId,
+                         lazyGrid->cellAreaGet.varNCId, grid->area);
     }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqAreaPtr(grid);
 }
 
-
-int cdiHaveFiletype(int filetype)
+static void
+cdfLazyGridInqArea(grid_t *grid, double *area)
 {
-  int status = 0;
+  grid->vtable->inqAreaPtr(grid);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lazyGrid->baseVtable->inqArea(grid, area);
+}
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:  { status = 1; break; }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:  { status = 1; break; }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:  { status = 1; break; }
-#endif
-#if  defined  (HAVE_LIBGRIB)
-#if  defined  (HAVE_LIBGRIB_API) || defined  (HAVE_LIBCGRIBEX)
-    case FILETYPE_GRB:  { status = 1; break; }
-#endif
-#if  defined  (HAVE_LIBGRIB_API)
-    case FILETYPE_GRB2: { status = 1; break; }
-#endif
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:   { status = 1; break; }
-#if  defined  (HAVE_NETCDF2)
-    case FILETYPE_NC2:  { status = 1; break; }
-#endif
-#if  defined  (HAVE_NETCDF4)
-    case FILETYPE_NC4:  { status = 1; break; }
-    case FILETYPE_NC4C: { status = 1; break; }
-#endif
-#endif
-    default: { status = 0; break; }
-    }
 
-  return (status);
+static void
+cdfLazyLoadXYVals(struct xyValGet *valsGet, double **valsp)
+{
+  double *grid_vals = (double *)Malloc(valsGet->size * sizeof (double));
+  *valsp = grid_vals;
+  if ( valsGet->ndims == 3 )
+    cdf_get_vara_double(valsGet->datasetNCId, valsGet->varNCId,
+                        valsGet->start, valsGet->count, grid_vals);
+  else
+    cdf_get_var_double(valsGet->datasetNCId, valsGet->varNCId, grid_vals);
+  cdf_scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
 }
 
-void cdiDefTableID(int tableID)
+static const double *
+cdfLazyGridInqXValsPtr(grid_t *grid)
 {
-  cdiDefaultTableID = tableID;
-  int modelID = cdiDefaultModelID = tableInqModel(tableID);
-  cdiDefaultInstID = modelInqInstitut(modelID);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->x.vals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->xValsGet, &grid->x.vals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXValsPtr(grid);
 }
 
-static
-void cdiSetChunk(const char *chunkAlgo)
+static const double *
+cdfLazyGridInqYValsPtr(grid_t *grid)
 {
-  //char *pch;
-  //size_t len = strlen(chunkAlgo);
-  int algo = -1;
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->y.vals == cdfPendingLoad)
+    cdfLazyLoadXYVals(&lazyGrid->yValsGet, &grid->y.vals);
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYValsPtr(grid);
+}
 
-  if      ( strcmp("auto",  chunkAlgo)   == 0 ) algo = CHUNK_AUTO;
-  else if ( strcmp("grid",  chunkAlgo)   == 0 ) algo = CHUNK_GRID;
-  else if ( strcmp("lines", chunkAlgo)   == 0 ) algo = CHUNK_LINES;
-  /*
-  else if ( (pch = strstr(chunkAlgo,"x")) != 0 )
+static double
+cdfLazyGridInqXYVal(grid_t *grid, size_t index,
+                    const struct xyValGet *valsGet, double *vals,
+                    const double *(*inqValsPtr)(grid_t *gridptr))
+{
+  size_t size = valsGet->size;
+  double v;
+  if ( vals == cdfPendingLoad )
     {
-      int ix, iy;
-      ix = atoi(chunkAlgo);
-      iy = atoi(pch+1);
-      if ( ix > 0 && iy > 0 )
+      /* prevent full load if only first/last values get inspected */
+      if ( index == 0 || index == size - 1 )
         {
-          cdiChunkX = ix;
-          cdiChunkY = iy;
-          algo = CHUNK_USER;
+          size_t indexND[3];
+          if ( valsGet->ndims == 3 )
+            {
+              indexND[0] = 0;
+              indexND[1] = index / valsGet->count[2];
+              indexND[2] = index % valsGet->count[2];
+            }
+          else if ( valsGet->ndims == 2)
+            {
+              indexND[0] = index / (size_t)grid->x.size;
+              indexND[1] = index % (size_t)grid->x.size;
+            }
+          else
+            indexND[0] = index;
+          cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId, indexND, &v);
         }
       else
-        Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
+        {
+          const double *grid_vals = inqValsPtr(grid);
+          v = grid_vals[index];
+        }
     }
-  */
+  else if ( vals )
+    v = vals[index];
   else
-    Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
+    v = 0.0;
+  return v;
+}
 
-  if ( algo != -1 )
-    {
-      cdiChunkType = algo;
-      if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
-    }
+static void
+cdfLazyGridDefXVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->x.vals == cdfPendingLoad)
+    grid->x.vals = NULL;
+  cdfGrid->xValsGet.datasetNCId = -1;
+  cdfGrid->xValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
 }
 
+static void
+cdfLazyGridDefYVals(grid_t *grid, const double *vals)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->y.vals == cdfPendingLoad)
+    grid->y.vals = NULL;
+  cdfGrid->yValsGet.datasetNCId = -1;
+  cdfGrid->yValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
+}
 
-void cdiInitialize(void)
+static double
+cdfLazyGridInqXVal(grid_t *grid, size_t index)
 {
-  static int Init_CDI = FALSE;
-  char *envstr;
-  long value;
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->xValsGet,
+                                  grid->x.vals, grid->vtable->inqXValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
 
-  if ( ! Init_CDI )
-    {
-      Init_CDI = TRUE;
+static double
+cdfLazyGridInqYVal(grid_t *grid, size_t index)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  double rv = cdfLazyGridInqXYVal(grid, index, &lazyGrid->yValsGet,
+                                  grid->y.vals, grid->vtable->inqYValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
 
-#if  defined  (HAVE_LIBCGRIBEX)
-      gribFixZSE(1);   // 1: Fix ZeroShiftError of simple packed spherical harmonics
-      gribSetConst(1); // 1: Don't pack constant fields on regular grids
-#endif
+static bool
+cdfLazyXYValGetCompare(struct cdfLazyGrid *lazyGridRef,
+                       struct cdfLazyGrid *lazyGridTest)
+{
+  struct xyValGet *valsGetXRef = &lazyGridRef->xValsGet,
+    *valsGetYRef = &lazyGridRef->yValsGet,
+    *valsGetXTest = &lazyGridTest->xValsGet,
+    *valsGetYTest = &lazyGridTest->yValsGet;
+  if (valsGetXRef->datasetNCId == -1
+      || valsGetXTest->datasetNCId == -1
+      || valsGetYRef->datasetNCId == -1
+      || valsGetYTest->datasetNCId == -1)
+    return lazyGridRef->baseVtable->compareXYFull(&lazyGridRef->base,
+                                                  &lazyGridTest->base);
+  return valsGetXRef->datasetNCId != valsGetXTest->datasetNCId
+    ||   valsGetXRef->varNCId     != valsGetXTest->varNCId
+    ||   valsGetYRef->datasetNCId != valsGetYTest->datasetNCId
+    ||   valsGetYRef->varNCId     != valsGetYTest->varNCId;
+}
 
-      value = cdiGetenvInt("CDI_DEBUG");
-      if ( value >= 0 ) CDI_Debug = (int) value;
+static bool
+cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
+{
+  bool diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYFull(gridRef, gridTest);
+  return diff;
+}
 
-      value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
-      if ( value >= 0 ) cdiGribApiDebug = (int) value;
+static bool
+cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
+{
+  bool diff;
+  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
+  if (gridTest->vtable == &cdfLazyGridVtable)
+    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
+  else
+    diff = lazyGridRef->baseVtable->compareXYAO(gridRef, gridTest);
+  return diff;
+}
 
-      value = cdiGetenvInt("CDI_RECOPT");
-      if ( value >= 0 ) CDI_Recopt = (int) value;
 
-      value = cdiGetenvInt("CDI_REGULARGRID");
-      if ( value >= 0 ) cdiDataUnreduced = (int) value;
-
-      value = cdiGetenvInt("CDI_SORTNAME");
-      if ( value >= 0 ) cdiSortName = (int) value;
-
-      value = cdiGetenvInt("CDI_HAVE_MISSVAL");
-      if ( value >= 0 ) cdiHaveMissval = (int) value;
-
-      value = cdiGetenvInt("CDI_LEVELTYPE");
-      if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
-
-      value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
-      if ( value >= 0 ) CDI_netcdf_hdr_pad = (size_t) value;
-
-      envstr = getenv("CDI_MISSVAL");
-      if ( envstr ) cdiDefaultMissval = atof(envstr);
-      /*
-      envstr = getenv("NC_MISSING_VALUE");
-      if ( envstr ) cdiNcMissingValue = atoi(envstr);
-      */
-      envstr = getenv("NC_CHUNKSIZEHINT");
-      if ( envstr ) cdiNcChunksizehint = atoi(envstr);
-
-      envstr = getenv("CDI_CHUNK_ALGO");
-      if ( envstr ) cdiSetChunk(envstr);
-
-      envstr = getenv("SPLIT_LTYPE_105");
-      if ( envstr ) cdiSplitLtype105 = atoi(envstr);
-
-      envstr = getenv("IGNORE_ATT_COORDINATES");
-      if ( envstr ) cdiIgnoreAttCoordinates = atoi(envstr);
-
-      envstr = getenv("IGNORE_VALID_RANGE");
-      if ( envstr ) cdiIgnoreValidRange = atoi(envstr);
-
-      envstr = getenv("CDI_SKIP_RECORDS");
-      if ( envstr )
-	{
-	  cdiSkipRecords = atoi(envstr);
-	  cdiSkipRecords = cdiSkipRecords > 0 ? cdiSkipRecords : 0;
-	}
-
-      envstr = getenv("CDI_CONVENTION");
-      if ( envstr )
-	{
-	  if ( strcmp(envstr, "CF") == 0 || strcmp(envstr, "cf") == 0 )
-	    {
-	      cdiConvention = CDI_CONVENTION_CF;
-	      if ( CDI_Debug )
-		Message("CDI convention was set to CF!");
-	    }
-	}
-
-      envstr = getenv("CDI_INVENTORY_MODE");
-      if ( envstr )
-	{
-	  if ( strncmp(envstr, "time", 4) == 0 )
-	    {
-	      cdiInventoryMode = 2;
-	      if ( CDI_Debug )
-		Message("Inventory mode was set to timestep!");
-	    }
-	}
-
-      envstr = getenv("CDI_VERSION_INFO");
-      if ( envstr )
-        {
-          int ival = atoi(envstr);
-          if ( ival == 0 || ival == 1 )
-            {
-              CDI_Version_Info = ival;
-              if ( CDI_Debug )
-                Message("CDI_Version_Info = %s", envstr);
-            }
-        }
-
-
-      envstr = getenv("CDI_CALENDAR");
-      if ( envstr )
-	{
-	  if      ( strncmp(envstr, "standard", 8) == 0 )
-	    cdiDefaultCalendar = CALENDAR_STANDARD;
-	  else if ( strncmp(envstr, "proleptic", 9) == 0 )
-	    cdiDefaultCalendar = CALENDAR_PROLEPTIC;
-	  else if ( strncmp(envstr, "360days", 7) == 0 )
-	    cdiDefaultCalendar = CALENDAR_360DAYS;
-	  else if ( strncmp(envstr, "365days", 7) == 0 )
-	    cdiDefaultCalendar = CALENDAR_365DAYS;
-	  else if ( strncmp(envstr, "366days", 7) == 0 )
-	    cdiDefaultCalendar = CALENDAR_366DAYS;
-	  else if ( strncmp(envstr, "none", 4) == 0 )
-	    cdiDefaultCalendar = CALENDAR_NONE;
-
-	  if ( CDI_Debug )
-	    Message("Default calendar set to %s!", envstr);
-	}
-#if  defined  (HAVE_LIBCGRIBEX)
-      gribSetCalendar(cdiDefaultCalendar);
-#endif
-
-      envstr = getenv("PARTAB_INTERN");
-      if ( envstr ) cdiPartabIntern = atoi(envstr);
-
-      envstr = getenv("PARTAB_PATH");
-      if ( envstr ) cdiPartabPath = strdup(envstr);
+static const double *
+cdfLazyGridInqXBoundsPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->x.bounds == cdfPendingLoad)
+    {
+      grid->x.bounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->xBoundsGet.datasetNCId,
+                         lazyGrid->xBoundsGet.varNCId, grid->x.bounds);
     }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqXBoundsPtr(grid);
 }
 
-
-const char *strfiletype(int filetype)
+static void
+cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
 {
-  const char *name;
-  int size = (int) (sizeof(Filetypes)/sizeof(char *));
-
-  if ( filetype > 0 && filetype < size )
-    name = Filetypes[filetype];
-  else
-    name = Filetypes[0];
-
-  return (name);
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->x.bounds == cdfPendingLoad)
+    grid->x.bounds = NULL;
+  cdfGrid->xBoundsGet.datasetNCId = -1;
+  cdfGrid->xBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXBounds(grid, xbounds);
+  unlock_lazy_load(cdfGrid);
 }
 
-
-void cdiDefGlobal(const char *string, int val)
+static void
+cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
 {
-  if      ( strcmp(string, "REGULARGRID")      == 0 ) cdiDataUnreduced = val;
-  else if ( strcmp(string, "GRIBAPI_DEBUG")    == 0 ) cdiGribApiDebug = val;
-  else if ( strcmp(string, "SORTNAME")         == 0 ) cdiSortName = val;
-  else if ( strcmp(string, "HAVE_MISSVAL")     == 0 ) cdiHaveMissval = val;
-  else if ( strcmp(string, "NC_CHUNKSIZEHINT") == 0 ) cdiNcChunksizehint = val;
-  else if ( strcmp(string, "CMOR_MODE")        == 0 ) CDI_cmor_mode = val;
-  else if ( strcmp(string, "NETCDF_HDR_PAD")   == 0 ) CDI_netcdf_hdr_pad = (size_t) val;
-  else if ( strcmp(string, "NETCDF_LAZY_GRID_LOAD") == 0)
-    CDI_netcdf_lazy_grid_load = (bool)val;
-  else Warning("Unsupported global key: %s", string);
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(cdfGrid);
+  if (grid->y.bounds == cdfPendingLoad)
+    grid->y.bounds = NULL;
+  cdfGrid->yBoundsGet.datasetNCId = -1;
+  cdfGrid->yBoundsGet.varNCId = -1;
+  cdfGrid->baseVtable->defYBounds(grid, ybounds);
+  unlock_lazy_load(cdfGrid);
 }
 
-
-void cdiDefMissval(double missval)
+static const double *
+cdfLazyGridInqYBoundsPtr(grid_t *grid)
 {
-  cdiInitialize();
-
-  cdiDefaultMissval = missval;
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->y.bounds == cdfPendingLoad)
+    {
+      grid->y.bounds = (double *)Malloc((size_t)grid->nvertex
+                                       * (size_t)grid->size * sizeof(double));
+      cdf_get_var_double(lazyGrid->yBoundsGet.datasetNCId,
+                         lazyGrid->yBoundsGet.varNCId, grid->y.bounds);
+    }
+  unlock_lazy_load(lazyGrid);
+  return lazyGrid->baseVtable->inqYBoundsPtr(grid);
 }
 
-
-double cdiInqMissval(void)
+static void
+cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
-  cdiInitialize();
-
-  return (cdiDefaultMissval);
+  struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)gridptrDup,
+    *lazyGridOrig = (struct cdfLazyGrid *)gridptrOrig;
+  lazyGridOrig->baseVtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  lazyGridDup->baseVtable = lazyGridOrig->baseVtable;
+  lazyGridDup->cellAreaGet = lazyGridOrig->cellAreaGet;
+  lazyGridDup->xBoundsGet = lazyGridOrig->xBoundsGet;
+  lazyGridDup->yBoundsGet = lazyGridOrig->yBoundsGet;
+  lazyGridDup->xValsGet = lazyGridOrig->xValsGet;
+  lazyGridDup->yValsGet = lazyGridOrig->yValsGet;
+  init_lazy_load_lock(lazyGridDup);
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
+static void
+cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = (size_t)gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
+  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
+  if ( nrowlon )
+    {
+      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
+    }
 
-#if defined (HAVE_CONFIG_H)
-#endif
+  if ( gridptrOrig->x.vals != NULL && gridptrOrig->x.vals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
 
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+      gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
+    }
 
+  if ( gridptrOrig->y.vals != NULL && gridptrOrig->y.vals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->y.size;
 
-void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
-{
-  unsigned uparam = (unsigned)param;
-  unsigned upnum;
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
+    }
 
-  *pdis = 0xff   & uparam;
-  *pcat = 0xff   & uparam >> 8;
-  upnum = 0xffff & uparam >> 16;
-  if ( upnum > 0x7fffU ) upnum = 0x8000U - upnum;
-  *pnum = (int)upnum;
-}
+  if ( gridptrOrig->x.bounds != NULL && gridptrOrig->x.bounds != cdfPendingLoad )
+    {
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->x.size)
+        * (size_t)gridptrOrig->nvertex;
 
+      gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
+    }
 
-int cdiEncodeParam(int pnum, int pcat, int pdis)
-{
-  unsigned uparam, upnum;
+  if ( gridptrOrig->y.bounds != NULL && gridptrOrig->y.bounds != cdfPendingLoad )
+    {
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
+        * (size_t)gridptrOrig->nvertex;
 
-  if ( pcat < 0 || pcat > 255 ) pcat = 255;
-  if ( pdis < 0 || pdis > 255 ) pdis = 255;
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
+    }
 
-  upnum = (unsigned)pnum;
-  if ( pnum < 0 ) upnum = (unsigned)(0x8000 - pnum);
+  {
+    if ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
+      {
+        size_t size = gridsize;
 
-  uparam = upnum << 16 | (unsigned)(pcat << 8) | (unsigned)pdis;
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
+      }
+  }
 
-  return ((int)uparam);
-}
+  if ( gridptrOrig->mask != NULL )
+    {
+      size_t size = gridsize;
 
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
+    }
 
-void cdiDecodeDate(int date, int *year, int *month, int *day)
-{
+  if ( gridptrOrig->mask_gme != NULL )
+    {
+      size_t size = gridsize;
 
-  int iyear = date / 10000;
-  *year = iyear;
-  int idate = abs(date - iyear * 10000),
-    imonth = idate / 100;
-  *month = imonth;
-  *day   = idate - imonth * 100;
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+    }
 }
 
-
-int cdiEncodeDate(int year, int month, int day)
+static grid_t *
+cdfLazyGridCopy(grid_t *gridptrOrig)
 {
-  int iyear = abs(year),
-    date = iyear * 10000 + month * 100 + day;
-  if ( year < 0 ) date = -date;
-  return (date);
+  struct cdfLazyGrid *lazyGridDup
+    = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
+  return &lazyGridDup->base;
 }
 
-
-void cdiDecodeTime(int time, int *hour, int *minute, int *second)
+static void
+cdfLazyGridInitOnce(void)
 {
-  int ihour = time / 10000,
-    itime = time - ihour * 10000,
-    iminute = itime / 100;
-  *hour   = ihour;
-  *minute = iminute;
-  *second = itime - iminute * 100;
+  cdfLazyGridVtable = cdiGridVtable;
+  cdfLazyGridVtable.destroy = cdfLazyGridDelete;
+  cdfLazyGridVtable.copy = cdfLazyGridCopy;
+  cdfLazyGridVtable.copyScalarFields = cdfLazyGridCopyScalarFields;
+  cdfLazyGridVtable.copyArrayFields = cdfLazyGridCopyArrayFields;
+  cdfLazyGridVtable.defArea = cdfLazyGridDefArea;
+  cdfLazyGridVtable.inqAreaPtr = cdfLazyGridInqAreaPtr;
+  cdfLazyGridVtable.inqArea = cdfLazyGridInqArea;
+  cdfLazyGridVtable.inqXValsPtr = cdfLazyGridInqXValsPtr;
+  cdfLazyGridVtable.inqYValsPtr = cdfLazyGridInqYValsPtr;
+  cdfLazyGridVtable.inqXVal = cdfLazyGridInqXVal;
+  cdfLazyGridVtable.inqYVal = cdfLazyGridInqYVal;
+  cdfLazyGridVtable.defXVals = cdfLazyGridDefXVals;
+  cdfLazyGridVtable.defYVals = cdfLazyGridDefYVals;
+  cdfLazyGridVtable.compareXYFull = cdfLazyCompareXYFull;
+  cdfLazyGridVtable.compareXYAO = cdfLazyCompareXYAO;
+  cdfLazyGridVtable.defXBounds = cdfLazyGridDefXBounds;
+  cdfLazyGridVtable.defYBounds = cdfLazyGridDefYBounds;
+  cdfLazyGridVtable.inqXBoundsPtr = cdfLazyGridInqXBoundsPtr;
+  cdfLazyGridVtable.inqYBoundsPtr = cdfLazyGridInqYBoundsPtr;
+  /* create inaccessible memory area, if possible, this serves as
+   * dummy value for pointers to data not yet loaded */
+  /*
+#ifdef HAVE_MMAP
+  {
+    size_t pgSize = cdiGetPageSize(false);
+    static const char devZero[] = "/dev/zero";
+    int fd = open(devZero, O_RDWR);
+    if (fd == -1)
+      SysError("Could not open %s to map anonymous memory", devZero);
+    void *cdfInvalid = mmap(NULL, pgSize, PROT_NONE, MAP_PRIVATE, fd, 0);
+    if (cdfInvalid == MAP_FAILED)
+      SysError("Could not mmap anonymous memory");
+    cdfPendingLoad = cdfInvalid;
+    int rc = close(fd);
+    if (rc == -1)
+      SysError("Could not close %s file handle %d after mapping anonymous"
+               " memory", devZero, fd);
+  }
+#else
+  */
+  cdfPendingLoad = (double *)&cdfPendingLoad;
+  //#endif
+  atexit(cdfLazyGridDestroyOnce);
+#ifndef HAVE_LIBPTHREAD
+  cdfLazyInitialized = true;
+#endif
 }
 
-
-int cdiEncodeTime(int hour, int minute, int second)
+static void
+cdfBaseGridInit(grid_t *grid, int gridtype)
 {
-  int time = hour*10000 + minute*100 + second;
-
-  return time;
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
 }
 
-
-void cdiParamToString(int param, char *paramstr, int maxlen)
+static void
+cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
 {
-  int dis, cat, num;
-  int len;
-
-  cdiDecodeParam(param, &num, &cat, &dis);
-
-  size_t umaxlen = maxlen >= 0 ? (unsigned)maxlen : 0U;
-  if ( dis == 255 && (cat == 255 || cat == 0 ) )
-    len = snprintf(paramstr, umaxlen, "%d", num);
-  else  if ( dis == 255 )
-    len = snprintf(paramstr, umaxlen, "%d.%d", num, cat);
-  else
-    len = snprintf(paramstr, umaxlen, "%d.%d.%d", num, cat, dis);
-
-  if ( len >= maxlen || len < 0)
-    fprintf(stderr, "Internal problem (%s): size of input string is too small!\n", __func__);
+#ifdef HAVE_LIBPTHREAD
+  pthread_once(&cdfLazyInitialized, cdfLazyGridInitOnce);
+#else
+  if (cdfLazyInitialized) ; else cdfLazyGridInitOnce();
+#endif
+  cdfBaseGridInit(&grid->base, gridtype);
+  grid->baseVtable = grid->base.vtable;
+  grid->cellAreaGet.datasetNCId = -1;
+  grid->cellAreaGet.varNCId = -1;
+  grid->xValsGet.datasetNCId = -1;
+  grid->xValsGet.varNCId = -1;
+  grid->yValsGet.datasetNCId = -1;
+  grid->yValsGet.varNCId = -1;
+  grid->xBoundsGet.datasetNCId = -1;
+  grid->xBoundsGet.varNCId = -1;
+  grid->yBoundsGet.datasetNCId = -1;
+  grid->yBoundsGet.varNCId = -1;
+  grid->base.vtable = &cdfLazyGridVtable;
+  init_lazy_load_lock(grid);
 }
 
 
-const char *cdiUnitNamePtr(int cdi_unit)
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
 {
-  const char *cdiUnits[] = {
-    /*  0 */  "undefined",
-    /*  1 */  "Pa",
-    /*  2 */  "hPa",
-    /*  3 */  "mm",
-    /*  4 */  "cm",
-    /*  5 */  "dm",
-    /*  6 */  "m",
-  };
-  enum { numUnits = (int) (sizeof(cdiUnits)/sizeof(char *)) };
-  const char *name = ( cdi_unit > 0 && cdi_unit < numUnits ) ?
-    cdiUnits[cdi_unit] : NULL;
-  return name;
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
+  cdfLazyGridInit(grid, gridtype);
 }
 
-size_t
-cdiGetPageSize(bool largePageAlign)
+
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
 {
-  long pagesize = -1L;
-#if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
-  bool nameAssigned = false;
-  int name;
-#  if HAVE_DECL__SC_LARGE_PAGESIZE
-  if (largePageAlign)
-    {
-      name = _SC_LARGE_PAGESIZE;
-      nameAssigned = true;
-    }
-  else
-#  else
-    (void)largePageAlign;
-#  endif
-    {
-#  if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
-      name =
-#    if HAVE_DECL__SC_PAGESIZE
-        _SC_PAGESIZE
-#    elif HAVE_DECL__SC_PAGE_SIZE
-        _SC_PAGE_SIZE
-#    endif
-        ;
-      nameAssigned = true;
-#  endif
-    }
-  if (nameAssigned)
-    pagesize = sysconf(name);
-#endif
-  if (pagesize == -1L)
-    pagesize =
-#if HAVE_DECL_PAGESIZE
-      PAGESIZE
-#elif HAVE_DECL_PAGE_SIZE
-      PAGE_SIZE
-#else
-      commonPageSize
-#endif
-      ;
-  return (size_t)pagesize;
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
+  cdfBaseGridInit((grid_t*)grid, gridtype);
 }
 
+#endif
 
 /*
  * Local Variables:
@@ -5658,12585 +5803,10162 @@ cdiGetPageSize(bool largePageAlign)
  * require-trailing-newline: t
  * End:
  */
+#ifndef CDI_CKSUM_H_
+#define CDI_CKSUM_H_
 
-/* Automatically generated by m214003 at 2016-06-03, do not edit */
-
-/* CGRIBEXLIB_VERSION="1.7.5" */
+#include <inttypes.h>
 
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wconversion"
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#pragma GCC diagnostic warning "-Wstrict-overflow"
-#endif
+uint32_t cdiCheckSum(int type, int count, const void *data);
 
-#ifdef _ARCH_PWR6
-#pragma options nostrict
 #endif
 
-#if defined (HAVE_CONFIG_H)
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
 #endif
 
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <sys/types.h>
 #include <inttypes.h>
+#include <sys/types.h>
 
+void
+memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len);
 
+void
+memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
+               size_t elem_size);
 
-#ifndef _TEMPLATES_H
-#define _TEMPLATES_H
-
-#define CAT(X,Y)      X##_##Y
-#define TEMPLATE(X,Y) CAT(X,Y)
+uint32_t
+memcrc_finish(uint32_t *state, off_t total_size);
 
-#endif 
-#ifndef GRIB_INT_H
-#define GRIB_INT_H
+uint32_t
+memcrc(const unsigned char *b, size_t n);
 
-#if defined (HAVE_CONFIG_H)
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
+#ifndef SERIALIZE_H
+#define SERIALIZE_H
 
+#include <string.h>
 
-#if ! defined   (_CGRIBEX_H)
+#ifndef  CDI_CKSUM_H_
 #endif
-#if ! defined   (_ERROR_H)
-#endif
-#if ! defined   (_DTYPES_H)
-#endif
-
-#if ! defined   (FALSE)
-#  define  FALSE  0
+#ifndef  ERROR_H
 #endif
 
-#if ! defined   (TRUE)
-#  define  TRUE  1
-#endif
+/*
+ * Generic interfaces for (de-)marshalling
+ */
+int serializeGetSize(int count, int datatype, void *context);
+void serializePack(const void *data, int count, int datatype,
+                   void *buf, int buf_size, int *position, void *context);
+void serializeUnpack(const void *buf, int buf_size, int *position,
+                     void *data, int count, int datatype, void *context);
 
-#if ! defined   (UCHAR)
-#  define  UCHAR  unsigned char
-#endif
+/*
+ * (de-)marshalling function for common data structures
+ */
+static inline int
+serializeStrTabGetPackSize(const char **strTab, int numStr,
+                           void *context)
+{
+  xassert(numStr >= 0);
+  int packBuffSize = 0;
+  for (size_t i = 0; i < (size_t)numStr; ++i)
+  {
+    size_t len = strlen(strTab[i]);
+    packBuffSize +=
+      serializeGetSize(1, CDI_DATATYPE_INT, context)
+      + serializeGetSize((int)len, CDI_DATATYPE_TXT, context);
+  }
+  packBuffSize +=
+    serializeGetSize(1, CDI_DATATYPE_UINT32, context);
+  return packBuffSize;
+}
 
+static inline void
+serializeStrTabPack(const char **strTab, int numStr,
+                    void *buf, int buf_size, int *position, void *context)
+{
+  uint32_t d = 0;
+  xassert(numStr >= 0);
+  for (size_t i = 0; i < (size_t)numStr; ++i)
+  {
+    int len = (int)strlen(strTab[i]);
+    serializePack(&len, 1, CDI_DATATYPE_INT,
+                  buf, buf_size, position, context);
+    serializePack(strTab[i], len, CDI_DATATYPE_TXT,
+                  buf, buf_size, position, context);
+    d ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
+  }
+  serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                buf, buf_size, position, context);
+}
 
-#if defined (CRAY) || defined (SX) || defined (__uxpch__)
-#  define VECTORCODE
-#endif
+static inline void
+serializeStrTabUnpack(const void *buf, int buf_size, int *position,
+                      char **strTab, int numStr, void *context)
+{
+  uint32_t d, d2 = 0;
+  xassert(numStr >= 0);
+  for (size_t i = 0; i < (size_t)numStr; ++i)
+    {
+      int len;
+      serializeUnpack(buf, buf_size, position,
+                      &len, 1, CDI_DATATYPE_INT, context);
+      serializeUnpack(buf, buf_size, position,
+                      strTab[i], len, CDI_DATATYPE_TXT, context);
+      strTab[i][len] = '\0';
+      d2 ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
+    }
+  serializeUnpack(buf, buf_size, position,
+                  &d, 1, CDI_DATATYPE_UINT32, context);
+  xassert(d == d2);
+}
 
+/*
+ * Interfaces for marshalling within a single memory domain
+ */
+int serializeGetSizeInCore(int count, int datatype, void *context);
+void serializePackInCore(const void *data, int count, int datatype,
+                          void *buf, int buf_size, int *position, void *context);
+void serializeUnpackInCore(const void *buf, int buf_size, int *position,
+                           void *data, int count, int datatype, void *context);
 
-#if defined (VECTORCODE)
-#if  defined  (INT32)
-#  define  GRIBPACK     unsigned INT32
-#  define  PACK_GRIB    packInt32
-#  define  UNPACK_GRIB  unpackInt32
-#else
-#  define  GRIBPACK     unsigned INT64
-#  define  PACK_GRIB    packInt64
-#  define  UNPACK_GRIB  unpackInt64
 #endif
-#else
-#  define  GRIBPACK     unsigned char
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
 #endif
 
-#define  U_BYTEORDER     static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1}
-#define  IS_BIGENDIAN()  (u_byteorder.c[sizeof(long) - 1])
+#include <inttypes.h>
+#include <sys/types.h>
+#include <stdlib.h>
 
-#if defined (__xlC__) /* performance problems on IBM */
-#ifndef DBL_IS_NAN
-#  define DBL_IS_NAN(x)     ((x) != (x))
-#endif
-#else
-#ifndef DBL_IS_NAN
-#if  defined  (HAVE_DECL_ISNAN)
-#  define DBL_IS_NAN(x)     (isnan(x))
-#elif  defined  (FP_NAN)
-#  define DBL_IS_NAN(x)     (fpclassify(x) == FP_NAN)
-#else
-#  define DBL_IS_NAN(x)     ((x) != (x))
-#endif
-#endif
-#endif
 
-#ifndef IS_EQUAL
-#  define IS_NOT_EQUAL(x,y) (x < y || y < x)
-#  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
-#endif
+uint32_t cdiCheckSum(int type, int count, const void *buffer)
+{
+  uint32_t s = 0U;
+  xassert(count >= 0);
+  size_t elemSize = (size_t)serializeGetSizeInCore(1, type, NULL);
+  memcrc_r_eswap(&s, (const unsigned char *)buffer, (size_t)count, elemSize);
+  s = memcrc_finish(&s, (off_t)(elemSize * (size_t)count));
+  return s;
+}
 
-/* dummy use of unused parameters to silence compiler warnings */
-#ifndef UNUSED
-#  define  UNUSED(x) (void)(x)
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
 #endif
 
-#define  JP23SET    0x7FFFFF  /* 2**23 - 1 (---> 8388607)  */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
 
-#define  POW_2_M24  0.000000059604644775390625  /*  pow(2.0, -24.0) */
+const char *cdiStringError(int cdiErrno)
+{
+  static const char UnknownError[] = "Unknown Error";
+  static const char _EISDIR[]      = "Is a directory";
+  static const char _EISEMPTY[]    = "File is empty";
+  static const char _EUFTYPE[]     = "Unsupported file type";
+  static const char _ELIBNAVAIL[]  = "Unsupported file type (library support not compiled in)";
+  static const char _EUFSTRUCT[]   = "Unsupported file structure";
+  static const char _EUNC4[]       = "Unsupported NetCDF4 structure";
+  static const char _EDIMSIZE[]    = "Invalid dimension size";
+  static const char _ELIMIT[]      = "Internal limits exceeded";
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+  switch (cdiErrno) {
+  case CDI_ESYSTEM:
+    {
+      const char *cp = strerror(errno);
+      if ( cp == NULL ) break;
+      return cp;
+    }
+  case CDI_EISDIR:     return _EISDIR;
+  case CDI_EISEMPTY:   return _EISEMPTY;
+  case CDI_EUFTYPE:    return _EUFTYPE;
+  case CDI_ELIBNAVAIL: return _ELIBNAVAIL;
+  case CDI_EUFSTRUCT:  return _EUFSTRUCT;
+  case CDI_EUNC4:      return _EUNC4;
+  case CDI_EDIMSIZE:   return _EDIMSIZE;
+  case CDI_ELIMIT:     return _ELIMIT;
+  }
 
-#define intpow2(x) (ldexp(1.0, (x)))
+  return UnknownError;
+}
 
-int gribrec_len(unsigned b1, unsigned b2, unsigned b3);
-int correct_bdslen(int bdslen, long recsize, long gribpos);
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _GRIBAPI_H
+#define _GRIBAPI_H
 
-/* CDI converter routines */
+#ifdef HAVE_LIBGRIB_API
+#include <grib_api.h>
+#ifndef  ERROR_H
+#endif
+#endif
 
-/* param format:  DDDCCCNNN */
+#ifndef  _CDI_INT_H
+#endif
 
-void    cdiDecodeParam(int param, int *dis, int *cat, int *num);
-int     cdiEncodeParam(int dis, int cat, int num);
+#define  GRIBAPI_MISSVAL  -9.E33
 
-/* date format:  YYYYMMDD */
-/* time format:  hhmmss   */
+/* GRIB2 Level Types */
+#define  GRIB2_LTYPE_SURFACE               1
+#define  GRIB2_LTYPE_CLOUD_BASE            2
+#define  GRIB2_LTYPE_CLOUD_TOP             3
+#define  GRIB2_LTYPE_ISOTHERM0             4
+#define  GRIB2_LTYPE_TOA                   8
+#define  GRIB2_LTYPE_SEA_BOTTOM            9
+#define  GRIB2_LTYPE_ATMOSPHERE           10
+#define  GRIB2_LTYPE_ISOBARIC            100
+#define  GRIB2_LTYPE_MEANSEA             101
+#define  GRIB2_LTYPE_ALTITUDE            102
+#define  GRIB2_LTYPE_HEIGHT              103
+#define  GRIB2_LTYPE_SIGMA               104
+#define  GRIB2_LTYPE_HYBRID              105
+#define  GRIB2_LTYPE_LANDDEPTH           106
+#define  GRIB2_LTYPE_ISENTROPIC          107
+#define  GRIB2_LTYPE_SNOW                114
+#define  GRIB2_LTYPE_REFERENCE           150
+#define  GRIB2_LTYPE_SEADEPTH            160  /* Depth Below Sea Level                                 */
+#define  GRIB2_LTYPE_LAKE_BOTTOM         162  /* Lake or River Bottom                                  */
+#define  GRIB2_LTYPE_SEDIMENT_BOTTOM     163  /* Bottom Of Sediment Layer                              */
+#define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TA  164  /* Bottom Of Thermally Active Sediment Layer             */
+#define  GRIB2_LTYPE_SEDIMENT_BOTTOM_TW  165  /* Bottom Of Sediment Layer Penetrated By Thermal Wave   */
+#define  GRIB2_LTYPE_MIX_LAYER           166  /* Mixing Layer                                          */
 
-void    cdiDecodeDate(int date, int *year, int *month, int *day);
-int     cdiEncodeDate(int year, int month, int day);
+/* GRIB2 Data representation type (Grid Type) */
+#define  GRIB2_GTYPE_LATLON                0  /*  latitude/longitude                                   */
+#define  GRIB2_GTYPE_LATLON_ROT            1  /*  rotated latitude/longitude                           */
+#define  GRIB2_GTYPE_LATLON_STR            2  /*  stretched latitude/longitude                         */
+#define  GRIB2_GTYPE_LATLON_ROTSTR         3  /*  rotated and stretched latitude/longitude             */
+#define  GRIB2_GTYPE_GAUSSIAN             40  /*  gaussian grid                                        */
+#define  GRIB2_GTYPE_GAUSSIAN_ROT         41  /*  rotated gaussian grid                                */
+#define  GRIB2_GTYPE_GAUSSIAN_STR         42  /*  stretched gaussian grid                              */
+#define  GRIB2_GTYPE_GAUSSIAN_ROTSTR      43  /*  rotated and stretched gaussian grid                  */
+#define  GRIB2_GTYPE_LCC                  30  /*  Lambert conformal                                    */
+#define  GRIB2_GTYPE_SPECTRAL             50  /*  spherical harmonics                                  */
+#define  GRIB2_GTYPE_GME                 100  /*  hexagonal GME grid                                   */
+#define  GRIB2_GTYPE_UNSTRUCTURED        101  /*  General Unstructured Grid                            */
 
-void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
-int     cdiEncodeTime(int hour, int minute, int second);
+const char *gribapiLibraryVersionString(void);
+void gribContainersNew(stream_t * streamptr);
+void gribContainersDelete(stream_t * streamptr);
 
-/* CALENDAR types */
+#ifdef HAVE_LIBGRIB_API
+static inline void *gribHandleNew(int editionNumber)
+{
+  void *gh = (void *)grib_handle_new_from_samples(NULL, (editionNumber == 1) ? "GRIB1" : "GRIB2");
 
-#define  CALENDAR_STANDARD        0  /* don't change this value (used also in cgribexlib)! */
-#define  CALENDAR_PROLEPTIC       1
-#define  CALENDAR_360DAYS         2
-#define  CALENDAR_365DAYS         3
-#define  CALENDAR_366DAYS         4
-#define  CALENDAR_NONE            5
+  if ( gh == NULL ) Error("grib_handle_new_from_samples failed!");
 
-extern FILE *grprsm;
+  return gh;
+}
 
-extern int  CGRIBEX_Debug;
+static inline int my_grib_set_double(grib_handle* h, const char* key, double val)
+{
+  if ( cdiGribApiDebug )
+    fprintf(stderr, "grib_set_double(\tgrib_handle* h, \"%s\", %f)\n", key, val);
 
-void   gprintf(const char *caller, const char *fmt, ...);
+  int ret_val = grib_set_double(h, key, val);
+  if (ret_val != 0)
+    fprintf(stderr, "!!! failed call to grib_set_double(\tgrib_handle* h, \"%s\", %f) !!!\n", key, val);
+  return ret_val;
+}
 
-void   grsdef(void);
+static inline int my_grib_set_long(grib_handle* h, const char* key, long val)
+{
+  if ( cdiGribApiDebug )
+    fprintf(stderr, "grib_set_long(  \tgrib_handle* h, \"%s\", %ld)\n", key, val);
 
-void   prtbin(int kin, int knbit, int *kout, int *kerr);
-void   confp3(double pval, int *kexp, int *kmant, int kbits, int kround);
-double decfp2(int kexp, int kmant);
-void   ref2ibm(double *pref, int kbits);
+  int ret_val = grib_set_long(h, key, val);
+  if (ret_val != 0)
+    fprintf(stderr, "!!! failed call to grib_set_long(  \tgrib_handle* h, \"%s\", %ld) !!!\n", key, val);
+  return ret_val;
+}
 
-void   scale_complex_double(double *fpdata, int pcStart, int pcScale, int trunc, int inv);
-void   scale_complex_float(float *fpdata, int pcStart, int pcScale, int trunc, int inv);
-void   scatter_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
-void   scatter_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
-void   gather_complex_double(double *fpdata, size_t pcStart, size_t trunc, size_t nsp);
-void   gather_complex_float(float *fpdata, size_t pcStart, size_t trunc, size_t nsp);
+static inline int my_grib_set_string(grib_handle* h, const char* key, const char* val, size_t* length)
+{
+  if ( cdiGribApiDebug )
+    fprintf(stderr, "grib_set_string(\tgrib_handle* h, \"%s\", \"%s\")\n", key, val);
 
-void   scm0_double(double *pdl, double *pdr, double *pfl, double *pfr, int klg);
-int    qu2reg2(double *pfield, int *kpoint, int klat, int klon,
-	       double *ztemp, double msval, int *kret);
-int    qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
-		      double msval, int *kret, int omisng, int operio, int oveggy);
-int    qu2reg3_float(float *pfield, int *kpoint, int klat, int klon,
-		     float msval, int *kret, int omisng, int operio, int oveggy);
+  int ret_val = grib_set_string(h, key, val, length);
+  if (ret_val != 0)
+    fprintf(stderr, "!!! grib_set_string(\tgrib_handle* h, \"%s\", \"%s\") !!!\n", key, val);
+  return ret_val;
+}
 
-#if  defined  (INT32)
-long   packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc);
-#endif
-long   packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc);
-#if  defined  (INT32)
-long   unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc);
+static inline void gribHandleDelete(void *gh)
+{
+  grib_handle_delete((struct grib_handle *)gh);
+}
+#else
+#define gribHandleNew(editionNumber) (NULL)
+#define gribHandleDelete(gh)
 #endif
-long   unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc);
-
-void  grib_encode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
-			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-			 int kleng, int *kword, int efunc, int *kret);
-void  grib_encode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
-			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-			int kleng, int *kword, int efunc, int *kret);
-
-void  grib_decode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
-			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-			 int kleng, int *kword, int dfunc, int *kret);
-void  grib_decode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
-			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-			int kleng, int *kword, int dfunc, int *kret);
 
+typedef struct {
+  bool init;
+  void *gribHandle;
+}
+gribContainer_t;
 
-int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
-		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize);
-int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
-		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
-		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp);
+#endif  /* _GRIBAPI_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef CGRIBEX_H
+#define CGRIBEX_H
 
-#if defined (__cplusplus)
-}
-#endif
+#include <stdio.h>
+#include <stdbool.h>
+#include <sys/types.h>
 
-#endif  /* GRIB_INT_H */
-#ifndef _GRIBDECODE_H
-#define _GRIBDECODE_H
+#define  GRIB_MISSVAL  -9.E33
 
-#define  UNDEFINED          9.999e20
+/* GRIB1 Level Types */
+#define  GRIB1_LTYPE_SURFACE               1
+#define  GRIB1_LTYPE_CLOUD_BASE            2
+#define  GRIB1_LTYPE_CLOUD_TOP             3
+#define  GRIB1_LTYPE_ISOTHERM0             4
+#define  GRIB1_LTYPE_TOA                   8
+#define  GRIB1_LTYPE_SEA_BOTTOM            9
+#define  GRIB1_LTYPE_ATMOSPHERE           10
+#define  GRIB1_LTYPE_99                   99
+#define  GRIB1_LTYPE_ISOBARIC            100
+#define  GRIB1_LTYPE_ISOBARIC_PA         210
+#define  GRIB1_LTYPE_MEANSEA             102
+#define  GRIB1_LTYPE_ALTITUDE            103
+#define  GRIB1_LTYPE_HEIGHT              105
+#define  GRIB1_LTYPE_SIGMA               107
+#define  GRIB1_LTYPE_SIGMA_LAYER         108
+#define  GRIB1_LTYPE_HYBRID              109
+#define  GRIB1_LTYPE_HYBRID_LAYER        110
+#define  GRIB1_LTYPE_LANDDEPTH           111
+#define  GRIB1_LTYPE_LANDDEPTH_LAYER     112
+#define  GRIB1_LTYPE_ISENTROPIC          113
+#define  GRIB1_LTYPE_SEADEPTH            160  /* Depth Below Sea Level                                 */
+#define  GRIB1_LTYPE_LAKE_BOTTOM         162  /* Lake or River Bottom                                  */
+#define  GRIB1_LTYPE_SEDIMENT_BOTTOM     163  /* Bottom Of Sediment Layer                              */
+#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TA  164  /* Bottom Of Thermally Active Sediment Layer             */
+#define  GRIB1_LTYPE_SEDIMENT_BOTTOM_TW  165  /* Bottom Of Sediment Layer Penetrated By Thermal Wave   */
+#define  GRIB1_LTYPE_MIX_LAYER           166  /* Mixing Layer                                          */
 
+/* GRIB1 Data representation type (Grid Type) [Table 6] */
+#define  GRIB1_GTYPE_LATLON                0  /*  latitude/longitude                                   */
+#define  GRIB1_GTYPE_LATLON_ROT           10  /*  rotated latitude/longitude                           */
+#define  GRIB1_GTYPE_LATLON_STR           20  /*  stretched latitude/longitude                         */
+#define  GRIB1_GTYPE_LATLON_ROTSTR        30  /*  rotated and stretched latitude/longitude             */
+#define  GRIB1_GTYPE_GAUSSIAN              4  /*  gaussian grid                                        */
+#define  GRIB1_GTYPE_GAUSSIAN_ROT         14  /*  rotated gaussian grid                                */
+#define  GRIB1_GTYPE_GAUSSIAN_STR         24  /*  stretched gaussian grid                              */
+#define  GRIB1_GTYPE_GAUSSIAN_ROTSTR      34  /*  rotated and stretched gaussian grid                  */
+#define  GRIB1_GTYPE_LCC                   3  /*  Lambert conformal                                    */
+#define  GRIB1_GTYPE_SPECTRAL             50  /*  spherical harmonics                                  */
+#define  GRIB1_GTYPE_GME                 192  /*  hexagonal GME grid                                   */
 
-#define  GET_INT3(a,b,c)    ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 16)+(b<<8)+c))
-#define  GET_INT2(a,b)      ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 8) + b))
-#define  GET_INT1(a)        ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (a&127))
+/*
+ *  Macros for the indicator section ( Section 0 )
+ */
+#define  ISEC0_GRIB_Len             (isec0[ 0])  /*  Number of octets in the GRIB message              */
+#define  ISEC0_GRIB_Version         (isec0[ 1])  /*  GRIB edition number                               */
 
-/* this requires a 32-bit default integer machine */
-#define  GET_UINT4(a,b,c,d) ((int) ((a << 24) + (b << 16) + (c << 8) + (d)))
-#define  GET_UINT3(a,b,c)   ((int) ((a << 16) + (b << 8)  + (c)))
-#define  GET_UINT2(a,b)     ((int) ((a << 8)  + (b)))
-#define  GET_UINT1(a)       ((int)  (a))
 
-#define  BUDG_START(s)      (s[0]=='B' && s[1]=='U' && s[2]=='D' && s[3]=='G')
-#define  TIDE_START(s)      (s[0]=='T' && s[1]=='I' && s[2]=='D' && s[3]=='E')
-#define  GRIB_START(s)      (s[0]=='G' && s[1]=='R' && s[2]=='I' && s[3]=='B')
-#define  GRIB_FIN(s)        (s[0]=='7' && s[1]=='7' && s[2]=='7' && s[3]=='7')
+/*
+ *  Macros for the product definition section ( Section 1 )
+ */
+#define  ISEC1_TABLE4_MINUTE      0
+#define  ISEC1_TABLE4_HOUR        1
+#define  ISEC1_TABLE4_DAY         2
+#define  ISEC1_TABLE4_3HOURS     10
+#define  ISEC1_TABLE4_6HOURS     11
+#define  ISEC1_TABLE4_12HOURS    12
+#define  ISEC1_TABLE4_QUARTER    13
+#define  ISEC1_TABLE4_30MINUTES  14
 
-/* GRIB1 Section 0: Indicator Section (IS) */
 
-#define  GRIB1_SECLEN(s)     GET_INT3(s[ 4], s[ 5], s[ 6])
-#define  GRIB_EDITION(s)     GET_UINT1(s[ 7])
+#define  ISEC1_CodeTable            (isec1[ 0])  /*  Version number of code table                 */
+#define  ISEC1_CenterID             (isec1[ 1])  /*  Identification of centre                     */
+#define  ISEC1_ModelID              (isec1[ 2])  /*  Identification of model                      */
+#define  ISEC1_GridDefinition       (isec1[ 3])  /*  Grid definition                              */
+#define  ISEC1_Sec2Or3Flag          (isec1[ 4])  /*  Section 2 or 3 included                      */
+#define  ISEC1_Parameter            (isec1[ 5])  /*  Parameter indicator                          */
+#define  ISEC1_LevelType            (isec1[ 6])  /*  Type of level indicator                      */
+#define  ISEC1_Level1               (isec1[ 7])  /*  Level 1                                      */
+#define  ISEC1_Level2               (isec1[ 8])  /*  Level 2                                      */
+#define  ISEC1_Year                 (isec1[ 9])  /*  Year of century (YY)                         */
+#define  ISEC1_Month                (isec1[10])  /*  Month (MM)                                   */
+#define  ISEC1_Day                  (isec1[11])  /*  Day (DD)                                     */
+#define  ISEC1_Hour                 (isec1[12])  /*  Hour (HH)                                    */
+#define  ISEC1_Minute               (isec1[13])  /*  Minute (MM)                                  */
+#define  ISEC1_TimeUnit             (isec1[14])  /*  Time unit indicator                          */
+#define  ISEC1_TimePeriod1          (isec1[15])  /*  P1 Time period                               */
+#define  ISEC1_TimePeriod2          (isec1[16])  /*  P2 Time period                               */
+#define  ISEC1_TimeRange            (isec1[17])  /*  Time range indicator                         */
+#define  ISEC1_AvgNum               (isec1[18])  /*  Number of products included in an average    */
+#define  ISEC1_AvgMiss              (isec1[19])  /*  Number of products missing from an average   */
+#define  ISEC1_Century              (isec1[20])  /*  Century                                      */
+#define  ISEC1_SubCenterID          (isec1[21])  /*  Subcenter identifier                         */
+#define  ISEC1_DecScaleFactor       (isec1[22])  /*  Decimal scale factor                         */
+#define  ISEC1_LocalFLag            (isec1[23])  /*  Flag field to indicate local use in isec1    */
 
-/* GRIB1 Section 1: Product Definition Section (PDS) */
+#define  ISEC1_ECMWF_LocalExtension (isec1[36])
+#define  ISEC1_ECMWF_Class          (isec1[37])
 
-#define  PDS_Len             GET_UINT3(pds[ 0], pds[ 1], pds[ 2])
-#define  PDS_CodeTable       GET_UINT1(pds[ 3])
-#define  PDS_CenterID        GET_UINT1(pds[ 4])
-#define  PDS_ModelID         GET_UINT1(pds[ 5])
-#define  PDS_GridDefinition  GET_UINT1(pds[ 6])
-#define  PDS_Sec2Or3Flag     GET_UINT1(pds[ 7])
-#define  PDS_HAS_GDS         ((pds[7] & 128) != 0)
-#define  PDS_HAS_BMS         ((pds[7] &  64) != 0)
-#define  PDS_Parameter       GET_UINT1(pds[ 8])
-#define  PDS_LevelType       GET_UINT1(pds[ 9])
-#define  PDS_Level1          (pds[10])
-#define  PDS_Level2	     (pds[11])
-#define  PDS_Level	     GET_UINT2(pds[10], pds[11])
-#define  PDS_Year            GET_INT1(pds[12])
-#define  PDS_Month           GET_UINT1(pds[13])
-#define  PDS_Day             GET_UINT1(pds[14])
-#define  PDS_Hour            GET_UINT1(pds[15])
-#define  PDS_Minute          GET_UINT1(pds[16])
-#define  PDS_Date            (PDS_Year*10000+PDS_Month*100+PDS_Day)
-#define  PDS_Time            (PDS_Hour*100+PDS_Minute)
-#define  PDS_TimeUnit        GET_UINT1(pds[17])
-#define  PDS_TimePeriod1     GET_UINT1(pds[18])
-#define  PDS_TimePeriod2     GET_UINT1(pds[19])
-#define  PDS_TimeRange       GET_UINT1(pds[20])
-#define  PDS_AvgNum          GET_UINT2(pds[21], pds[22])
-#define  PDS_AvgMiss         GET_UINT1(pds[23])
-#define  PDS_Century         GET_UINT1(pds[24])
-#define  PDS_Subcenter       GET_UINT1(pds[25])
-#define  PDS_DecimalScale    GET_INT2(pds[26],pds[27])
 
+/*
+ *  Macros for the grid definition section ( Section 2 )
+ */
+#define  ISEC2_GridType             (isec2[ 0])  /* Data representation type */
 
-/* GRIB1 Section 2: Grid Description Section (GDS) */
+/* Triangular grids */
 
-#define  GDS_Len             ((gds) == NULL ? 0 : GET_UINT3(gds[ 0], gds[ 1], gds[ 2]))
-#define  GDS_NV              GET_UINT1(gds[ 3])
-#define  GDS_PVPL            GET_UINT1(gds[ 4])
-#define  GDS_PV	             ((gds[3] ==    0) ? -1 : (int) gds[4] - 1)
-#define  GDS_PL	             ((gds[4] == 0xFF) ? -1 : (int) gds[3] * 4 + (int) gds[4] - 1)
-#define  GDS_GridType        GET_UINT1(gds[ 5])
+#define  ISEC2_GME_NI2              (isec2[ 1])  /*  Number of factor 2 in factorisation of Ni    */
+#define  ISEC2_GME_NI3              (isec2[ 2])  /*  Number of factor 3 in factorisation of Ni    */
+#define  ISEC2_GME_ND               (isec2[ 3])  /*  Nubmer of diamonds                           */
+#define  ISEC2_GME_NI               (isec2[ 4])  /*  Number of tri. subdiv. of the icosahedron    */
+#define  ISEC2_GME_AFlag            (isec2[ 5])  /*  Flag for orientation of diamonds (Table A)   */
+#define  ISEC2_GME_LatPP            (isec2[ 6])  /*  Latitude of pole point                       */
+#define  ISEC2_GME_LonPP            (isec2[ 7])  /*  Longitude of pole point                      */
+#define  ISEC2_GME_LonMPL           (isec2[ 8])  /*  Longitude of the first diamond               */
+#define  ISEC2_GME_BFlag            (isec2[ 9])  /*  Flag for storage sequence (Table B)          */
 
+/* Spherical harmonic coeficients */
 
-/* GRIB1 Triangular grid of DWD */
-#define  GDS_GME_NI2         GET_UINT2(gds[ 6], gds[ 7])
-#define  GDS_GME_NI3         GET_UINT2(gds[ 8], gds[ 9])
-#define  GDS_GME_ND          GET_UINT3(gds[10], gds[11], gds[12])
-#define  GDS_GME_NI          GET_UINT3(gds[13], gds[14], gds[15])
-#define  GDS_GME_AFlag       GET_UINT1(gds[16])
-#define  GDS_GME_LatPP       GET_INT3(gds[17], gds[18], gds[19])
-#define  GDS_GME_LonPP       GET_INT3(gds[20], gds[21], gds[22])
-#define  GDS_GME_LonMPL      GET_INT3(gds[23], gds[24], gds[25])
-#define  GDS_GME_BFlag       GET_UINT1(gds[27])
+#define  ISEC2_PentaJ               (isec2[ 1])  /*  J pentagonal resolution parameter            */
+#define  ISEC2_PentaK               (isec2[ 2])  /*  K pentagonal resolution parameter            */
+#define  ISEC2_PentaM               (isec2[ 3])  /*  M pentagonal resolution parameter            */
+#define  ISEC2_RepType              (isec2[ 4])  /*  Representation type                          */
+#define  ISEC2_RepMode              (isec2[ 5])  /*  Representation mode                          */
 
-/* GRIB1 Spectral */
-#define  GDS_PentaJ          GET_UINT2(gds[ 6], gds[ 7])
-#define  GDS_PentaK          GET_UINT2(gds[ 8], gds[ 9])
-#define  GDS_PentaM          GET_UINT2(gds[10], gds[11])
-#define  GDS_RepType         GET_UINT1(gds[12])
-#define  GDS_RepMode         GET_UINT1(gds[13])
+/* Gaussian grids */
 
-/* GRIB1 Regular grid */
-#define  GDS_NumLon          GET_UINT2(gds[ 6], gds[ 7])
-#define  GDS_NumLat          GET_UINT2(gds[ 8], gds[ 9])
-#define  GDS_FirstLat        GET_INT3(gds[10], gds[11], gds[12])
-#define  GDS_FirstLon        GET_INT3(gds[13], gds[14], gds[15])
-#define  GDS_ResFlag         GET_UINT1(gds[16])
-#define  GDS_LastLat         GET_INT3(gds[17], gds[18], gds[19])
-#define  GDS_LastLon         GET_INT3(gds[20], gds[21], gds[22])
-#define  GDS_LonIncr         GET_UINT2(gds[23], gds[24])
-#define  GDS_LatIncr         GET_UINT2(gds[25], gds[26])
-#define  GDS_NumPar          GET_UINT2(gds[25], gds[26])
-#define  GDS_ScanFlag        GET_UINT1(gds[27])
-#define  GDS_LatSP           GET_INT3(gds[32], gds[33], gds[34])
-#define  GDS_LonSP           GET_INT3(gds[35], gds[36], gds[37])
-#define  GDS_RotAngle        (GET_Real(&(gds[38])))
+#define  ISEC2_NumLon               (isec2[ 1])  /*  Number of points along a parallel (Ni)       */
+#define  ISEC2_NumLat               (isec2[ 2])  /*  Number of points along a meridian (Nj)       */
+#define  ISEC2_FirstLat             (isec2[ 3])  /*  Latitude of the first grid point             */
+#define  ISEC2_FirstLon             (isec2[ 4])  /*  Longitude of the first grid point            */
+#define  ISEC2_ResFlag              (isec2[ 5])  /*  Resolution flag: 128 regular grid            */
+#define  ISEC2_LastLat              (isec2[ 6])  /*  Latitude of the last grid point              */
+#define  ISEC2_LastLon              (isec2[ 7])  /*  Longitude of the last grid point             */
+#define  ISEC2_LonIncr              (isec2[ 8])  /*  i direction increment                        */
+#define  ISEC2_LatIncr              (isec2[ 9])  /*  j direction increment                        */
+#define  ISEC2_NumPar               (isec2[ 9])  /*  Number of parallels between a pole and the E.*/
+#define  ISEC2_ScanFlag             (isec2[10])  /*  Scanning mode flags                          */
+#define  ISEC2_NumVCP               (isec2[11])  /*  Number of vertical coordinate parameters     */
 
-/* GRIB1 Lambert */
-#define  GDS_Lambert_Lov     GET_INT3(gds[17], gds[18], gds[19])
-#define  GDS_Lambert_dx	     GET_INT3(gds[20], gds[21], gds[22])
-#define  GDS_Lambert_dy	     GET_INT3(gds[23], gds[24], gds[25])
-#define  GDS_Lambert_ProjFlag GET_UINT1(gds[26])
-#define  GDS_Lambert_LatS1   GET_INT3(gds[28], gds[29], gds[30])
-#define  GDS_Lambert_LatS2   GET_INT3(gds[31], gds[32], gds[33])
-#define  GDS_Lambert_LatSP   GET_INT3(gds[34], gds[35], gds[36])
-#define  GDS_Lambert_LonSP   GET_INT3(gds[37], gds[37], gds[37])
+/* Lambert */
+#define  ISEC2_Lambert_Lov          (isec2[ 6])  /*  Orientation of the grid                      */
+#define  ISEC2_Lambert_dx           (isec2[ 8])  /*  X-direction grid length                      */
+#define  ISEC2_Lambert_dy           (isec2[ 9])  /*  Y-direction grid length                      */
+#define  ISEC2_Lambert_ProjFlag     (isec2[12])  /*  Projection centre flag                       */
+#define  ISEC2_Lambert_LatS1        (isec2[13])  /*  First lat at which the secant cone cuts the sphere */
+#define  ISEC2_Lambert_LatS2        (isec2[14])  /*  Second lat at which the secant cone cuts the sphere */
+#define  ISEC2_Lambert_LatSP        (isec2[19])  /*  Latitude of the southern pole                */
+#define  ISEC2_Lambert_LonSP        (isec2[20])  /*  Longitude of the southern pole               */
 
-/* GRIB1 Section 3: Bit Map Section (BMS) */
 
-#define  BMS_Len	     ((bms) == NULL ? 0 : (int) (bms[0]<<16)+(bms[1]<<8)+bms[2])
-#define  BMS_UnusedBits      (bms[3])
-#define  BMS_Numeric         
-#define  BMS_Bitmap	     ((bms) == NULL ? NULL : (bms)+6)
-#define  BMS_BitmapSize      (((((bms[0]<<16)+(bms[1]<<8)+bms[2]) - 6)<<3) - bms[3])
+#define  ISEC2_Reduced              (isec2[16])  /* 0: regular, 1: reduced grid                   */
 
-/* GRIB1 Section 4: Binary Data Section (BDS) */
+#define  ISEC2_RowLonPtr            (&isec2[22])
+#define  ISEC2_RowLon(i)            (isec2[22+i]) /* Number of points along each parallel         */
 
-#define  BDS_Len	    ((int) ((bds[0]<<16)+(bds[1]<<8)+bds[2]))
-#define  BDS_Flag	    (bds[3])
-#define  BDS_BinScale       GET_INT2(bds[ 4], bds[ 5])
-#define  BDS_RefValue       (decfp2((int)bds[ 6], GET_UINT3(bds[ 7], bds[ 8], bds[ 9])))
-#define  BDS_NumBits        ((int) bds[10])
-#define  BDS_RealCoef       (decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14])))
-#define  BDS_PackData       ((int) ((bds[zoff+11]<<8) + bds[zoff+12]))
-#define  BDS_Power          GET_INT2(bds[zoff+13], bds[zoff+14])
-#define  BDS_Z              (bds[13])
+/* */
 
-/* GRIB1 Section 5: End Section (ES) */
+#define  ISEC2_LatSP                (isec2[12])  /* Latitude of the southern pole of rotation     */
+#define  ISEC2_LonSP                (isec2[13])  /* Longitude of the southern pole of rotation    */
 
-/* GRIB2 */
+#define  FSEC2_RotAngle             (fsec2[ 0])  /* Angle of rotation                             */
+#define  FSEC2_StrFact              (fsec2[ 1])  /* Stretching factor                             */
 
-#define  GRIB2_SECLEN(section)   (GET_UINT4(section[0], section[1], section[2], section[3]))
-#define  GRIB2_SECNUM(section)   (GET_UINT1(section[4]))
+/*
+ *  Macros for the bit map section ( Section 3 )
+ */
+#define  ISEC3_PredefBitmap         (isec3[ 0])  /* Predefined bitmap                             */
+#define  ISEC3_MissVal              (isec3[ 1])  /* Missing data value for integers               */
+#define  FSEC3_MissVal              (fsec3[ 1])  /* Missing data value for floats                 */
 
-#endif  /* _GRIBDECODE_H */
-#ifndef _GRIB_ENCODE_H
-#define _GRIB_ENCODE_H
+/*
+ *  Macros for the binary data section ( Section 4 )
+ */
+#define  ISEC4_NumValues            (isec4[ 0])  /* Number of data values for encode/decode       */
+#define  ISEC4_NumBits              (isec4[ 1])  /* Number of bits used for each encoded value    */
+#define  ISEC4_NumNonMissValues     (isec4[20])  /* Number of non-missing values                  */
 
-#include <limits.h>
 
-#define PutnZero(n) \
-{ \
-  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
-  z += n; \
-}
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-#define Put1Byte(Value)  (lGrib[z++] = (GRIBPACK)(Value))
-#define Put2Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
-                         (lGrib[z++] = (GRIBPACK)(Value)))
-#define Put3Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
-                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
-                         (lGrib[z++] = (GRIBPACK)(Value)))
-#define Put4Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 24)),      \
-                         (lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
-                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
-                         (lGrib[z++] = (GRIBPACK)(Value)))
 
-#define Put1Int(Value)  {ival = Value; if ( ival < 0 ) ival =     0x80 - ival; Put1Byte(ival);}
-#define Put2Int(Value)  {ival = Value; if ( ival < 0 ) ival =   0x8000 - ival; Put2Byte(ival);}
-#define Put3Int(Value)  {ival = Value; if ( ival < 0 ) ival = 0x800000 - ival; Put3Byte(ival);}
+void  gribFixZSE(int flag);     /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
+void  gribSetConst(int flag);   /* 1: Don't pack constant fields on regular grids */
+void  gribSetDebug(int debug);  /* 1: Debugging */
+void  gribSetRound(int round);
+void  gribSetRefDP(double refval);
+void  gribSetRefSP(float  refval);
+void  gribSetValueCheck(int vcheck);
 
-enum {
-  BitsPerInt = (int) (sizeof(int) * CHAR_BIT),
-};
 
+void  gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
+               float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
+               int kleng, int *kword, const char *hoper, int *kret);
 
-#define Put1Real(Value)          \
-{                                \
-  confp3(Value, &exponent, &mantissa, BitsPerInt, 1); \
-  Put1Byte(exponent);            \
-  Put3Byte(mantissa);            \
-}
+void  gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
+               double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
+               int kleng, int *kword, const char *hoper, int *kret);
 
-#endif  /* _GRIB_ENCODE_H */
-#ifndef CODEC_COMMON_H
-#define CODEC_COMMON_H
-#define gribSwapByteOrder_uint16(ui16)  ((uint16_t)((ui16<<8) | (ui16>>8)))
-#endif  /* CODEC_COMMON_H */
-/* 
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -qopenmp -DOMP_SIMD minmax_val.c
- result on hama2 (icc 16.0.0):
-     float:
-minmax_val: fmin: -500000  fmax: 499999  time:   1.22s
-simd      : fmin: -500000  fmax: 499999  time:   1.20s
-    double:
-minmax_val: fmin: -500000  fmax: 499999  time:   2.86s
-orig      : fmin: -500000  fmax: 499999  time:   2.74s
-simd      : fmin: -500000  fmax: 499999  time:   2.70s
-avx       : fmin: -500000  fmax: 499999  time:   2.99s
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
- result on thunder5 (gcc 6.1.0):
-float:
-minmax_val: fmin: -500000  fmax: 499999  time:   8.25s
-  simd    : fmin: -500000  fmax: 499999  time:   1.24s
-double:
-minmax_val: fmin: -500000  fmax: 499999  time:   2.73s
-  orig    : fmin: -500000  fmax: 499999  time:   9.24s
-  simd    : fmin: -500000  fmax: 499999  time:   2.78s
-  avx     : fmin: -500000  fmax: 499999  time:   2.90s
+const char *cgribexLibraryVersion(void);
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL minmax_val.c
- result on bailung (gcc 4.8.2):
-  orig    : fmin: -500000  fmax: 499999  time:   4.82s
-  sse2    : fmin: -500000  fmax: 499999  time:   4.83s
+void  gribDebug(int debug);
+void  gribSetCalendar(int calendar);
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
- result on thunder5 (gcc 4.8.2):
-  orig    : fmin: -500000  fmax: 499999  time:   3.10s
-  simd    : fmin: -500000  fmax: 499999  time:   3.10s # omp simd in gcc 4.9
-  avx     : fmin: -500000  fmax: 499999  time:   2.84s
+void  gribDateTime(int *isec1, int *date, int *time);
+int   gribRefDate(int *isec1);
+int   gribRefTime(int *isec1);
+bool  gribTimeIsFC(int *isec1);
 
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
- result on thunder5 (icc 14.0.2):
-  orig    : fmin: -500000  fmax: 499999  time:   2.83s
-  simd    : fmin: -500000  fmax: 499999  time:   2.83s
-  avx     : fmin: -500000  fmax: 499999  time:   2.92s
+void  gribPrintSec0(int *isec0);
+void  gribPrintSec1(int *isec0, int *isec1);
+void  gribPrintSec2DP(int *isec0, int *isec2, double *fsec2);
+void  gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2);
+void  gribPrintSec3DP(int *isec0, int *isec3, double *fsec3);
+void  gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3);
+void  gribPrintSec4DP(int *isec0, int *isec4, double *fsec4);
+void  gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4);
+void  gribPrintSec4Wave(int *isec4);
 
-xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_MINMAXVAL minmax_val.c
- result on blizzard (xlc 12):
-  orig    : fmin: -500000  fmax: 499999  time:   7.26s
-  pwr6u6  : fmin: -500000  fmax: 499999  time:   5.92s
-*/
-#if defined(_ARCH_PWR6)
-#pragma options nostrict
-#endif
+void  gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
+void  gribRepair1(int nrec, long recsize, unsigned char *gribbuffer);
 
-#include <stdlib.h>
+int   gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize);
 
-//#undef _GET_X86_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _ARCH_PWR6
+int   gribBzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
+int   gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
+int   gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
 
-#if defined(_GET_IBM_COUNTER)
-#include <libhpc.h>
-#elif defined(_GET_X86_COUNTER)
-#include <x86intrin.h>
-#elif defined(_GET_MACH_COUNTER)
-#include <mach/mach_time.h>
-#endif
+int   gribOpen(const char *filename, const char *mode);
+void  gribClose(int fileID);
 
-#if   defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
-#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4)
-#define GNUC_PUSH_POP
-#endif
-#endif
+int   gribRead(int fileID, unsigned char *buffer, size_t *buffersize);
+int   gribWrite(int fileID, unsigned char *buffer, size_t buffersize);
+off_t gribGetPos(int fileID);
+size_t gribGetSize(int fileID);
+int   gribCheckSeek(int fileID, long *offset, int *version);
+int   gribFileSeek(int fileID, long *offset);
+size_t gribReadSize(int fileID);
+int   gribVersion(unsigned char *buffer, size_t buffersize);
 
-#ifndef DISABLE_SIMD
-#if   defined(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
-#else
-#define DISABLE_SIMD
-#endif
-#endif
+int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
 
-#ifdef DISABLE_SIMD
-#define DISABLE_SIMD_MINMAXVAL
+double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
+
+
+#if defined (__cplusplus)
+}
 #endif
 
-#if !defined(TEST_MINMAXVAL)
-#define DISABLE_SIMD_MINMAXVAL
+#endif  /* CGRIBEX_H */ 
+
+#ifdef  HAVE_CONFIG_H
 #endif
 
-#ifdef DISABLE_SIMD_MINMAXVAL
-# if defined(ENABLE_AVX)
-#  define _ENABLE_AVX
-# endif
-# if defined(ENABLE_SSE2)
-#  define _ENABLE_SSE2
-# endif
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef  HAVE_LIBNETCDF
 #endif
 
-#ifndef DISABLE_SIMD_MINMAXVAL
-# if defined(__AVX__)
-#  define _ENABLE_AVX
-# endif
-# if defined(__SSE2__)
-#  define _ENABLE_SSE2
-# endif
+#ifdef  HAVE_LIBCGRIBEX
 #endif
 
-#include <float.h>
-#include <stdint.h>
-#include <inttypes.h>
+int cdiDefaultCalendar = CALENDAR_PROLEPTIC;
 
-#if defined(_ENABLE_AVX)
-#include <immintrin.h>
-#elif defined(_ENABLE_SSE2)
-#include <emmintrin.h>
-#endif
+int cdiDefaultInstID   = CDI_UNDEFID;
+int cdiDefaultModelID  = CDI_UNDEFID;
+int cdiDefaultTableID  = CDI_UNDEFID;
+//int cdiNcMissingValue  = CDI_UNDEFID;
+int cdiNcChunksizehint = CDI_UNDEFID;
+int cdiChunkType       = CDI_CHUNK_GRID;
+int cdiSplitLtype105   = CDI_UNDEFID;
 
+bool cdiIgnoreAttCoordinates = false;
+bool cdiCoordinatesLonLat    = false;
+bool cdiIgnoreValidRange     = false;
+int cdiSkipRecords          = 0;
+int cdiConvention           = CDI_CONVENTION_ECHAM;
+int cdiInventoryMode        = 1;
+int CDI_Version_Info        = 1;
+int CDI_cmor_mode           = 0;
+int CDI_reduce_dim          = 0;
+size_t CDI_netcdf_hdr_pad   = 0UL;
+bool CDI_netcdf_lazy_grid_load = false;
 
-#if defined(_ENABLE_AVX)
+char *cdiPartabPath   = NULL;
+int   cdiPartabIntern = 1;
 
-static
-void avx_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
-{
-  double fmin[4], fmax[4];
-  __m256d current_max, current_min, work;
+double cdiDefaultMissval = -9.E33;
 
-  // load max and min values into all four slots of the YMM registers
-  current_min = _mm256_set1_pd(*min);
-  current_max = _mm256_set1_pd(*max);
+static const char Filetypes[][9] = {
+  "UNKNOWN",
+  "GRIB",
+  "GRIB2",
+  "NetCDF",
+  "NetCDF2",
+  "NetCDF4",
+  "NetCDF4c",
+  "NetCDF5",
+  "SERVICE",
+  "EXTRA",
+  "IEG",
+  "HDF5",
+};
 
-  // Work input until "buf" reaches 32 byte alignment
-  while ( ((unsigned long)buf) % 32 != 0 && nframes > 0) {
+int CDI_Debug   = 0;    /* If set to 1, debugging           */
+int CDI_Recopt = 0;
 
-    // Load the next double into the work buffer
-    work = _mm256_set1_pd(*buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf++;
-    nframes--;
-  }
+int cdiGribApiDebug     = 0;
+int cdiDefaultLeveltype = -1;
+int cdiDataUnreduced = 0;
+int cdiSortName = 0;
+int cdiSortParam = 0;
+int cdiHaveMissval = 0;
 
-  while (nframes >= 16) {
 
-    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
+static long cdiGetenvInt(const char *envName)
+{
+  long envValue = -1;
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+  char *envString = getenv(envName);
+  if ( envString )
+    {
+      long fact = 1;
+      int len = (int) strlen(envString);
+      for ( int loop = 0; loop < len; loop++ )
+	{
+	  if ( ! isdigit((int) envString[loop]) )
+	    {
+	      switch ( tolower((int) envString[loop]) )
+		{
+		case 'k':  fact = 1024;        break;
+		case 'm':  fact = 1048576;     break;
+		case 'g':  fact = 1073741824;  break;
+		default:
+		  fact = 0;
+		  Message("Invalid number string in %s: %s", envName, envString);
+		  Warning("%s must comprise only digits [0-9].",envName);
+		  break;
+		}
+	      break;
+	    }
+	}
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+      if ( fact ) envValue = fact*atol(envString);
 
-    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
+      if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
+    }
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+  return envValue;
+}
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
-    nframes -= 16;
-  }
+static void
+cdiPrintDefaults(void)
+{
+  fprintf(stderr, "default instID     :  %d\n"
+          "default modelID    :  %d\n"
+          "default tableID    :  %d\n"
+          "default missval    :  %g\n", cdiDefaultInstID,
+          cdiDefaultModelID, cdiDefaultTableID, cdiDefaultMissval);
+}
 
-  // work through aligned buffers
-  while (nframes >= 4) {
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
-    nframes -= 4;
-  }
+void cdiPrintVersion(void)
+{
+  fprintf(stderr, "     CDI library version : %s\n", cdiLibraryVersion());
+#ifdef  HAVE_LIBCGRIBEX
+  fprintf(stderr, " CGRIBEX library version : %s\n", cgribexLibraryVersion());
+#endif
+#ifdef  HAVE_LIBGRIB_API
+  fprintf(stderr, "GRIB_API library version : %s\n", gribapiLibraryVersionString());
+#endif
+#ifdef  HAVE_LIBNETCDF
+  fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
+#endif
+#ifdef  HAVE_NC4HDF5
+  fprintf(stderr, "    HDF5 library version : %s\n", hdfLibraryVersion());
+#endif
+#ifdef  HAVE_LIBSERVICE
+  fprintf(stderr, " SERVICE library version : %s\n", srvLibraryVersion());
+#endif
+#ifdef  HAVE_LIBEXTRA
+  fprintf(stderr, "   EXTRA library version : %s\n", extLibraryVersion());
+#endif
+#ifdef  HAVE_LIBIEG
+  fprintf(stderr, "     IEG library version : %s\n", iegLibraryVersion());
+#endif
+  fprintf(stderr, "    FILE library version : %s\n", fileLibraryVersion());
+}
 
-  // work through the remainung values
-  while ( nframes > 0) {
-    work = _mm256_set1_pd(*buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf++;
-    nframes--;
-  }
+static void cdiPrintDatatypes(void)
+{
+#define XSTRING(x)	#x
+#define STRING(x)	XSTRING(x)
+  fprintf (stderr, "+-------------+-------+\n"
+           "| types       | bytes |\n"
+           "+-------------+-------+\n"
+           "| void *      |   %3d |\n"
+           "+-------------+-------+\n"
+           "| char        |   %3d |\n"
+           "+-------------+-------+\n"
+           "| bool        |   %3d |\n"
+           "| short       |   %3d |\n"
+           "| int         |   %3d |\n"
+           "| long        |   %3d |\n"
+           "| long long   |   %3d |\n"
+           "| size_t      |   %3d |\n"
+           "| off_t       |   %3d |\n"
+           "+-------------+-------+\n"
+           "| float       |   %3d |\n"
+           "| double      |   %3d |\n"
+           "| long double |   %3d |\n"
+           "+-------------+-------+\n\n"
+           "+-------------+-----------+\n"
+           "| INT32       | %-9s |\n"
+           "| INT64       | %-9s |\n"
+           "| FLT32       | %-9s |\n"
+           "| FLT64       | %-9s |\n"
+           "+-------------+-----------+\n"
+           "\n  byte ordering is %s\n\n",
+           (int) sizeof(void *), (int) sizeof(char), (int) sizeof(bool),
+           (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), (int) sizeof(long long),
+           (int) sizeof(size_t), (int) sizeof(off_t),
+           (int) sizeof(float), (int) sizeof(double), (int) sizeof(long double),
+           STRING(INT32), STRING(INT64), STRING(FLT32), STRING(FLT64),
+           ((HOST_ENDIANNESS == CDI_BIGENDIAN) ? "BIGENDIAN"
+            : ((HOST_ENDIANNESS == CDI_LITTLEENDIAN) ? "LITTLEENDIAN"
+               : "Unhandled endianness!")));
+#undef STRING
+#undef XSTRING
+}
 
-  // find min & max value through shuffle tricks
 
-  work = current_min;
-  work = _mm256_shuffle_pd(work, work, 5);
-  work = _mm256_min_pd (work, current_min);
-  current_min = work;
-  work = _mm256_permute2f128_pd(work, work, 1);
-  work = _mm256_min_pd (work, current_min);
-  _mm256_storeu_pd(fmin, work);
+void cdiDebug(int level)
+{
+  if ( level == 1 || (level &  2) ) CDI_Debug = 1;
 
-  work = current_max;
-  work = current_max;
-  work = _mm256_shuffle_pd(work, work, 5);
-  work = _mm256_max_pd (work, current_max);
-  current_max = work;
-  work = _mm256_permute2f128_pd(work, work, 1);
-  work = _mm256_max_pd (work, current_max);
-  _mm256_storeu_pd(fmax, work);
+  if ( CDI_Debug ) Message("debug level %d", level);
 
-  *min = fmin[0];
-  *max = fmax[0];
+  if ( level == 1 || (level &  4) ) memDebug(1);
 
-  return;
+  if ( level == 1 || (level &  8) ) fileDebug(1);
+
+  if ( level == 1 || (level & 16) )
+    {
+#if  defined  (HAVE_LIBCGRIBEX)
+      gribSetDebug(1);
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+      cdfDebug(1);
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+      srvDebug(1);
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+      extDebug(1);
+#endif
+#if  defined  (HAVE_LIBIEG)
+      iegDebug(1);
+#endif
+    }
+
+  if ( CDI_Debug )
+    {
+      cdiPrintDefaults();
+      cdiPrintDatatypes();
+    }
 }
 
-#elif defined(_ENABLE_SSE2)
 
-static
-void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
+int cdiHaveFiletype(int filetype)
 {
-  __m128d current_max, current_min, work;
-  
-  // load starting max and min values into all slots of the XMM registers
-  current_min = _mm_set1_pd(*min);
-  current_max = _mm_set1_pd(*max);
-  
-  // work on input until buf reaches 16 byte alignment
-  while ( ((unsigned long)buf) % 16 != 0 && nframes > 0) {
-    
-    // load one double and replicate
-    work = _mm_set1_pd(*buf);    
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);    
-    buf++;
-    nframes--;
-  }
-  
-  while (nframes >= 8) {
-    // use 64 byte prefetch for double octetts
-    // __builtin_prefetch(buf+64,0,0); // for GCC 4.3.2 +
-
-    work = _mm_load_pd(buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf += 2;
-    work = _mm_load_pd(buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf += 2;
-    work = _mm_load_pd(buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf += 2;
-    work = _mm_load_pd(buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf += 2;
-    nframes -= 8;
-  }
-
-  // work through smaller chunks of aligned buffers without prefetching
-  while (nframes >= 2) {
-    work = _mm_load_pd(buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf += 2;
-    nframes -= 2;
-  }
-
-  // work through the remaining value
-  while ( nframes > 0) {
-    // load the last double and replicate
-    work = _mm_set1_pd(*buf);
-    current_min = _mm_min_pd(current_min, work);
-    current_max = _mm_max_pd(current_max, work);
-    buf++;
-    nframes--;
-  }
+  int status = 0;
 
-  // find final min and max value through shuffle tricks
-  work = current_min;
-  work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
-  work = _mm_min_pd (work, current_min);
-  _mm_store_sd(min, work);
-  work = current_max;
-  work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
-  work = _mm_max_pd (work, current_max);
-  _mm_store_sd(max, work);
+  switch (filetype)
+    {
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:  status = 1; break;
+#endif
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:  status = 1; break;
+#endif
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:  status = 1; break;
+#endif
+#ifdef  HAVE_LIBGRIB
+#if  defined  (HAVE_LIBGRIB_API) || defined  (HAVE_LIBCGRIBEX)
+    case CDI_FILETYPE_GRB:  status = 1; break;
+#endif
+#ifdef  HAVE_LIBGRIB_API
+    case CDI_FILETYPE_GRB2: status = 1; break;
+#endif
+#endif
+#ifdef  HAVE_LIBNETCDF
+    case CDI_FILETYPE_NC:   status = 1; break;
+#ifdef  HAVE_NETCDF2
+    case CDI_FILETYPE_NC2:  status = 1; break;
+#endif
+#ifdef  HAVE_NETCDF4
+    case CDI_FILETYPE_NC4:  status = 1; break;
+    case CDI_FILETYPE_NC4C: status = 1; break;
+#endif
+#ifdef  HAVE_NETCDF5
+    case CDI_FILETYPE_NC5:  status = 1; break;
+#endif
+#endif
+    default: status = 0; break;
+    }
 
-  return;
+  return status;
 }
 
-#endif // SIMD
-
-#if defined(_ARCH_PWR6)
-static
-void pwr6_minmax_val_double_unrolled6(const double *restrict data, size_t datasize, double *fmin, double *fmax)
+void cdiDefTableID(int tableID)
 {
-#define __UNROLL_DEPTH_1 6
-
-  // to allow pipelining we have to unroll 
-
-  {
-    size_t i, j;
-    size_t residual =  datasize % __UNROLL_DEPTH_1;
-    size_t ofs = datasize - residual;
-    double register dmin[__UNROLL_DEPTH_1];
-    double register dmax[__UNROLL_DEPTH_1];
-
-    for ( j = 0; j < __UNROLL_DEPTH_1; j++) 
-      {
-	dmin[j] = data[0];
-	dmax[j] = data[0];
-      }
-    
-    for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_1 ) 
-      {
-	for (j = 0; j < __UNROLL_DEPTH_1; j++) 
-	  {
-	    dmin[j] = __fsel(dmin[j] - data[i+j], data[i+j], dmin[j]);
-	    dmax[j] = __fsel(data[i+j] - dmax[j], data[i+j], dmax[j]);
-	  }
-      }
-
-    for (j = 0; j < residual; j++) 
-      {
-	dmin[j] = __fsel(dmin[j] - data[ofs+j], data[ofs+j], dmin[j]);
-	dmax[j] = __fsel(data[ofs+j] - dmax[j], data[ofs+j], dmax[j]);
-      }
-
-    for ( j = 0; j < __UNROLL_DEPTH_1; j++) 
-      {
-	*fmin = __fsel(*fmin - dmin[j], dmin[j], *fmin);
-	*fmax = __fsel(dmax[j] - *fmax, dmax[j], *fmax);
-      }
-  }
-#undef __UNROLL_DEPTH_1
+  cdiDefaultTableID = tableID;
+  int modelID = cdiDefaultModelID = tableInqModel(tableID);
+  cdiDefaultInstID = modelInqInstitut(modelID);
 }
-#endif
-
-#if defined(TEST_MINMAXVAL) && defined(__GNUC__)
-static
-void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
-static
-void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
-static
-void minmax_val_float(const float *restrict data, long datasize, float *fmin, float *fmax) __attribute__ ((noinline));
-static
-void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax) __attribute__ ((noinline));
-#endif
 
-#if defined(GNUC_PUSH_POP)
-#pragma GCC push_options
-#pragma GCC optimize ("O3", "fast-math")
-#endif
 static
-void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax)
+void cdiSetChunk(const char *chunkAlgo)
 {
-  double dmin = *fmin, dmax = *fmax;
+  //char *pch;
+  //size_t len = strlen(chunkAlgo);
+  int algo = -1;
 
-#if   defined(CRAY)
-#pragma _CRI ivdep
-#elif defined(SX)
-#pragma vdir nodep
-#elif defined(__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-  for ( size_t i = 0; i < datasize; ++i )
+  if      ( strcmp("auto",  chunkAlgo)   == 0 ) algo = CDI_CHUNK_AUTO;
+  else if ( strcmp("grid",  chunkAlgo)   == 0 ) algo = CDI_CHUNK_GRID;
+  else if ( strcmp("lines", chunkAlgo)   == 0 ) algo = CDI_CHUNK_LINES;
+  /*
+  else if ( (pch = strstr(chunkAlgo,"x")) != 0 )
     {
-      dmin = dmin < data[i] ? dmin : data[i];
-      dmax = dmax > data[i] ? dmax : data[i];
+      int ix, iy;
+      ix = atoi(chunkAlgo);
+      iy = atoi(pch+1);
+      if ( ix > 0 && iy > 0 )
+        {
+          cdiChunkX = ix;
+          cdiChunkY = iy;
+          algo = CHUNK_USER;
+        }
+      else
+        Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
     }
+  */
+  else
+    Warning("Invalid environment variable CDI_CHUNK_ALGO: %s", chunkAlgo);
 
-  *fmin = dmin;
-  *fmax = dmax;
+  if ( algo != -1 )
+    {
+      cdiChunkType = algo;
+      if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
+    }
 }
 
-static
-void minmax_val_float(const float *restrict data, long idatasize, float *fmin, float *fmax)
+
+void cdiInitialize(void)
 {
-  size_t datasize = (size_t)idatasize;
-  float dmin = *fmin, dmax = *fmax;
+  static bool Init_CDI = false;
 
-#if   defined(CRAY)
-#pragma _CRI ivdep
-#elif defined(SX)
-#pragma vdir nodep
-#elif defined(__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-  for ( size_t i = 0; i < datasize; ++i )
+  if ( ! Init_CDI )
     {
-      dmin = dmin < data[i] ? dmin : data[i];
-      dmax = dmax > data[i] ? dmax : data[i];
-    }
+      Init_CDI = true;
+      char *envstr;
+      long value;
 
-  *fmin = dmin;
-  *fmax = dmax;
-}
-#if defined(GNUC_PUSH_POP)
-#pragma GCC pop_options
+#ifdef  HAVE_LIBCGRIBEX
+      gribFixZSE(1);   // 1: Fix ZeroShiftError of simple packed spherical harmonics
+      gribSetConst(1); // 1: Don't pack constant fields on regular grids
 #endif
 
-// TEST
-#if defined(OMP_SIMD)
+      value = cdiGetenvInt("CDI_DEBUG");
+      if ( value >= 0 ) CDI_Debug = (int) value;
 
-#if defined(GNUC_PUSH_POP)
-#pragma GCC push_options
-#pragma GCC optimize ("O3", "fast-math")
-#endif
-static
-void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax)
-{
-  double dmin = *fmin, dmax = *fmax;
+      value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
+      if ( value >= 0 ) cdiGribApiDebug = (int) value;
 
-#if defined(_OPENMP)
-#pragma omp simd reduction(min:dmin) reduction(max:dmax)
-#endif
-  for ( size_t i = 0; i < datasize; ++i )
-    {
-      dmin = dmin < data[i] ? dmin : data[i];
-      dmax = dmax > data[i] ? dmax : data[i];
-    }
+      value = cdiGetenvInt("CDI_RECOPT");
+      if ( value >= 0 ) CDI_Recopt = (int) value;
 
-  *fmin = dmin;
-  *fmax = dmax;
-}
-static
-void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax)
-{
-  float dmin = *fmin, dmax = *fmax;
+      value = cdiGetenvInt("CDI_REGULARGRID");
+      if ( value >= 0 ) cdiDataUnreduced = (int) value;
 
-#if defined(_OPENMP)
-#pragma omp simd reduction(min:dmin) reduction(max:dmax)
-#endif
-  for ( size_t i = 0; i < datasize; ++i )
-    {
-      dmin = dmin < data[i] ? dmin : data[i];
-      dmax = dmax > data[i] ? dmax : data[i];
-    }
+      value = cdiGetenvInt("CDI_SORTNAME");
+      if ( value >= 0 ) cdiSortName = (int) value;
 
-  *fmin = dmin;
-  *fmax = dmax;
-}
-#if defined(GNUC_PUSH_POP)
-#pragma GCC pop_options
-#endif
-#endif
+      value = cdiGetenvInt("CDI_SORTPARAM");
+      if ( value >= 0 ) cdiSortParam = (int) value;
 
-static
-void minmax_val_double(const double *restrict data, long idatasize, double *fmin, double *fmax)
-{
-#if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER) 
-  uint64_t start_minmax, end_minmax;
-#endif
-  size_t datasize = (size_t)idatasize;
+      value = cdiGetenvInt("CDI_HAVE_MISSVAL");
+      if ( value >= 0 ) cdiHaveMissval = (int) value;
 
-  if ( idatasize >= 1 ) ; else return;
+      value = cdiGetenvInt("CDI_LEVELTYPE");
+      if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
 
-#if defined(_GET_X86_COUNTER) 
-  start_minmax = _rdtsc();
-#endif
-#if defined(_GET_MACH_COUNTER) 
-  start_minmax = mach_absolute_time();
-#endif
+      value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
+      if ( value >= 0 ) CDI_netcdf_hdr_pad = (size_t) value;
 
-#if defined(_ENABLE_AVX)
+      envstr = getenv("CDI_MISSVAL");
+      if ( envstr ) cdiDefaultMissval = atof(envstr);
+      /*
+      envstr = getenv("NC_MISSING_VALUE");
+      if ( envstr ) cdiNcMissingValue = atoi(envstr);
+      */
+      envstr = getenv("NC_CHUNKSIZEHINT");
+      if ( envstr ) cdiNcChunksizehint = atoi(envstr);
 
-  avx_minmax_val_double(data, datasize, fmin, fmax);
+      envstr = getenv("CDI_CHUNK_ALGO");
+      if ( envstr ) cdiSetChunk(envstr);
 
-#elif defined(_ENABLE_SSE2)
+      envstr = getenv("SPLIT_LTYPE_105");
+      if ( envstr ) cdiSplitLtype105 = atoi(envstr);
 
-  sse2_minmax_val_double(data, datasize, fmin, fmax);
+      envstr = getenv("IGNORE_ATT_COORDINATES");
+      if ( envstr ) cdiIgnoreAttCoordinates = atoi(envstr) > 0;
 
-#else
+      envstr = getenv("CDI_COORDINATES_LONLAT");
+      if ( envstr ) cdiCoordinatesLonLat = atoi(envstr) > 0;
 
-#if defined(_ARCH_PWR6)
-#define __UNROLL_DEPTH_1 6
+      envstr = getenv("IGNORE_VALID_RANGE");
+      if ( envstr ) cdiIgnoreValidRange = atoi(envstr) > 0;
 
-  // to allow pipelining we have to unroll 
+      envstr = getenv("CDI_SKIP_RECORDS");
+      if ( envstr )
+	{
+	  cdiSkipRecords = atoi(envstr);
+	  cdiSkipRecords = cdiSkipRecords > 0 ? cdiSkipRecords : 0;
+	}
 
-#if defined(_GET_IBM_COUNTER)
-  hpmStart(1, "minmax fsel");
-#endif
+      envstr = getenv("CDI_CONVENTION");
+      if ( envstr )
+	{
+	  if ( strcmp(envstr, "CF") == 0 || strcmp(envstr, "cf") == 0 )
+	    {
+	      cdiConvention = CDI_CONVENTION_CF;
+	      if ( CDI_Debug )
+		Message("CDI convention was set to CF!");
+	    }
+	}
 
-  pwr6_minmax_val_double_unrolled6(data, datasize, fmin, fmax);
+      envstr = getenv("CDI_INVENTORY_MODE");
+      if ( envstr )
+	{
+	  if ( strncmp(envstr, "time", 4) == 0 )
+	    {
+	      cdiInventoryMode = 2;
+	      if ( CDI_Debug )
+		Message("Inventory mode was set to timestep!");
+	    }
+	}
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStop(1);
-#endif
+      envstr = getenv("CDI_VERSION_INFO");
+      if ( envstr )
+        {
+          int ival = atoi(envstr);
+          if ( ival == 0 || ival == 1 )
+            {
+              CDI_Version_Info = ival;
+              if ( CDI_Debug )
+                Message("CDI_Version_Info = %s", envstr);
+            }
+        }
 
-#undef __UNROLL_DEPTH_1
 
-#else // original loop
+      envstr = getenv("CDI_CALENDAR");
+      if ( envstr )
+	{
+	  if      ( strncmp(envstr, "standard", 8) == 0 )
+	    cdiDefaultCalendar = CALENDAR_STANDARD;
+	  else if ( strncmp(envstr, "gregorian", 9) == 0 )
+	    cdiDefaultCalendar = CALENDAR_GREGORIAN;
+	  else if ( strncmp(envstr, "proleptic", 9) == 0 )
+	    cdiDefaultCalendar = CALENDAR_PROLEPTIC;
+	  else if ( strncmp(envstr, "360days", 7) == 0 )
+	    cdiDefaultCalendar = CALENDAR_360DAYS;
+	  else if ( strncmp(envstr, "365days", 7) == 0 )
+	    cdiDefaultCalendar = CALENDAR_365DAYS;
+	  else if ( strncmp(envstr, "366days", 7) == 0 )
+	    cdiDefaultCalendar = CALENDAR_366DAYS;
+	  else if ( strncmp(envstr, "none", 4) == 0 )
+	    cdiDefaultCalendar = CALENDAR_NONE;
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStart(1, "minmax base");
+	  if ( CDI_Debug )
+	    Message("Default calendar set to %s!", envstr);
+	}
+#ifdef  HAVE_LIBCGRIBEX
+      gribSetCalendar(cdiDefaultCalendar);
 #endif
 
-  minmax_val_double_orig(data, datasize, fmin, fmax);
+      envstr = getenv("PARTAB_INTERN");
+      if ( envstr ) cdiPartabIntern = atoi(envstr);
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStop(1);
-#endif
+      envstr = getenv("PARTAB_PATH");
+      if ( envstr ) cdiPartabPath = strdup(envstr);
+    }
+}
 
-#endif // _ARCH_PWR6 && original loop
-#endif // SIMD
 
-#if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER)
-#if defined(_GET_X86_COUNTER) 
-  end_minmax = _rdtsc();
-#endif
-#if defined(_GET_MACH_COUNTER) 
-  end_minmax = mach_absolute_time();
-#endif
-#if defined(_ENABLE_AVX)
-  printf("AVX minmax cycles:: %" PRIu64 "\n",  end_minmax-start_minmax);
-  fprintf (stderr, "AVX min: %lf max: %lf\n", *fmin, *fmax);
-#elif defined(_ENABLE_SSE2)
-  printf("SSE2 minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-  fprintf (stderr, "SSE2 min: %lf max: %lf\n", *fmin, *fmax);
-#else
-  printf("loop minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-  fprintf (stderr, "loop min: %lf max: %lf\n", *fmin, *fmax);
-#endif
-#endif
+const char *strfiletype(int filetype)
+{
+  int size = (int) (sizeof(Filetypes)/sizeof(char *));
+  const char *name = (filetype > 0 && filetype < size) ? Filetypes[filetype] : Filetypes[0];
 
-  return;
+  return name;
 }
 
-#if defined(TEST_MINMAXVAL)
 
-#include <stdio.h>
-#include <sys/time.h>
+void cdiDefGlobal(const char *string, int val)
+{
+  if      ( strcmp(string, "REGULARGRID")      == 0 ) cdiDataUnreduced = val;
+  else if ( strcmp(string, "GRIBAPI_DEBUG")    == 0 ) cdiGribApiDebug = val;
+  else if ( strcmp(string, "SORTNAME")         == 0 ) cdiSortName = val;
+  else if ( strcmp(string, "SORTPARAM")        == 0 ) cdiSortParam = val;
+  else if ( strcmp(string, "HAVE_MISSVAL")     == 0 ) cdiHaveMissval = val;
+  else if ( strcmp(string, "NC_CHUNKSIZEHINT") == 0 ) cdiNcChunksizehint = val;
+  else if ( strcmp(string, "CMOR_MODE")        == 0 ) CDI_cmor_mode = val;
+  else if ( strcmp(string, "REDUCE_DIM")       == 0 ) CDI_reduce_dim = val;
+  else if ( strcmp(string, "NETCDF_HDR_PAD")   == 0 ) CDI_netcdf_hdr_pad = (size_t) val;
+  else if ( strcmp(string, "NETCDF_LAZY_GRID_LOAD") == 0)
+    CDI_netcdf_lazy_grid_load = (bool)val;
+  else Warning("Unsupported global key: %s", string);
+}
 
-static
-double dtime()
+
+void cdiDefMissval(double missval)
 {
-  double tseconds = 0.0;
-  struct timeval mytime;
-  gettimeofday(&mytime, NULL);
-  tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
-  return (tseconds);
+  cdiInitialize();
+
+  cdiDefaultMissval = missval;
 }
 
-#define NRUN 10000
 
-int main(void)
+double cdiInqMissval(void)
 {
-  long datasize = 1000000;
-  double t_begin, t_end;
+  cdiInitialize();
 
-#if   defined(_OPENMP)
-  printf("_OPENMP=%d\n", _OPENMP);
-#endif
+  return cdiDefaultMissval;
+}
 
-#if   defined(__ICC)
-  printf("icc\n");
-#elif defined(__clang__)
-  printf("clang\n");
-#elif defined(__GNUC__)
-  printf("gcc\n");
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+
+#if defined (HAVE_CONFIG_H)
 #endif
 
-  {
-    float fmin, fmax;
-    float *data_sp = (float*) malloc(datasize*sizeof(float));
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-    for ( long i = 0; i < datasize/2; i++ )        data_sp[i] = (float) (i);
-    for ( long i = datasize/2; i < datasize; i++ ) data_sp[i] = (float) (-datasize + i);
 
-    printf("float:\n");
+void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
+{
+  unsigned uparam = (unsigned)param;
+  unsigned upnum;
 
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_sp[0];
-	minmax_val_float(data_sp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+  *pdis = 0xff   & uparam;
+  *pcat = 0xff   & uparam >> 8;
+  upnum = 0xffff & uparam >> 16;
+  if ( upnum > 0x7fffU ) upnum = 0x8000U - upnum;
+  *pnum = (int)upnum;
+}
 
-#if defined(OMP_SIMD)
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_sp[0];
-	minmax_val_float_simd(data_sp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-#endif
 
-    free(data_sp);
-  }
+int cdiEncodeParam(int pnum, int pcat, int pdis)
+{
+  unsigned uparam, upnum;
 
-  {
-    double fmin, fmax;
-    double *data_dp = (double*) malloc(datasize*sizeof(double));
+  if ( pcat < 0 || pcat > 255 ) pcat = 255;
+  if ( pdis < 0 || pdis > 255 ) pdis = 255;
 
-    // for ( long i = datasize-1; i >= 0; i-- ) data[i] = (double) (-datasize/2 + i);
-    for ( long i = 0; i < datasize/2; i++ )        data_dp[i] = (double) (i);
-    for ( long i = datasize/2; i < datasize; i++ ) data_dp[i] = (double) (-datasize + i);
+  upnum = (unsigned)pnum;
+  if ( pnum < 0 ) upnum = (unsigned)(0x8000 - pnum);
 
-    printf("double:\n");
+  uparam = upnum << 16 | (unsigned)(pcat << 8) | (unsigned)pdis;
 
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	minmax_val_double(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+  return ((int)uparam);
+}
 
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	minmax_val_double_orig(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("orig      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 
-#if defined(OMP_SIMD)
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	minmax_val_double_simd(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-#endif
+void cdiDecodeDate(int date, int *year, int *month, int *day)
+{
 
-#if defined(_ENABLE_AVX)
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	avx_minmax_val_double(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("avx       : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-#elif defined(_ENABLE_SSE2)
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	sse2_minmax_val_double(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("sse2      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-#endif
-#if defined(_ARCH_PWR6)
-    t_begin = dtime();
-    for ( int i = 0; i < NRUN; ++i )
-      {
-	fmin = fmax = data_dp[0];
-	pwr6_minmax_val_double_unrolled6(data_dp, datasize, &fmin, &fmax);
-      }
-    t_end = dtime();
-    printf("pwr6u6  : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
-#endif
-    free(data_dp);
-  }
+  int iyear = date / 10000;
+  *year = iyear;
+  int idate = abs(date - iyear * 10000),
+    imonth = idate / 100;
+  *month = imonth;
+  *day   = idate - imonth * 100;
+}
 
-  return (0);
+
+int cdiEncodeDate(int year, int month, int day)
+{
+  int iyear = abs(year),
+    date = iyear * 10000 + month * 100 + day;
+  if ( year < 0 ) date = -date;
+  return (date);
 }
-#endif // TEST_MINMAXVAL
 
-#undef DISABLE_SIMD_MINMAXVAL
-#undef _ENABLE_AVX
-#undef _ENABLE_SSE2
-#undef GNUC_PUSH_POP
-/*
-### new version with gribSwapByteOrder_uint16()
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
- result on hama2 (icc 16.0.2):
-   float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 1.8731s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.0898s
-  double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.68089s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30798s
-     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.23864s
 
-gcc -g -Wall -O3 -march=native -Wa,-q -std=c99 -DTEST_ENCODE encode_array.c
- result on hama2 (gcc 6.1.0):
-float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.22871s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.30281s
-double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.2669s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.81643s
-     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.98415s
+void cdiDecodeTime(int time, int *hour, int *minute, int *second)
+{
+  int ihour = time / 10000,
+    itime = time - ihour * 10000,
+    iminute = itime / 100;
+  *hour   = ihour;
+  *minute = iminute;
+  *second = itime - iminute * 100;
+}
 
-###
-icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
- result on hama2 (icc 16.0.0):
-   float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.10691s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.63584s
-  double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.5768s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.17742s
-     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.9488s
 
-gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
- result on hama2 (gcc 5.2.0):
-   float:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 5.32775s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.87125s
-  double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.85873s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 12.9979s
+int cdiEncodeTime(int hour, int minute, int second)
+{
+  int time = hour*10000 + minute*100 + second;
 
-###
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
- result on bailung (gcc 4.7):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 8.4166s
-  sse41   : val1: 1  val2: 1  val3: 2  valn: 66  time: 7.1522s
+  return time;
+}
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
- result on thunder5 (gcc 4.7):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 6.21976s
-  avx     : val1: 1  val2: 1  val3: 2  valn: 66  time: 4.54485s
 
-icc -g -Wall -O3 -march=native -std=c99 -vec-report=1 -DTEST_ENCODE encode_array.c
- result on thunder5 (icc 13.2):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 14.6279s
-  avx     : val1: 1  val2: 1  val3: 2  valn: 66  time:  4.9776s
+void cdiParamToString(int param, char *paramstr, int maxlen)
+{
+  int dis, cat, num;
+  int len;
 
-xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_ENCODE encode_array.c
- result on blizzard (xlc 12):
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 132.25s
-  unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  27.202s
-  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 106.627s  // without -qhot
-  unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  39.929s  // without -qhot
-*/
-#ifdef _ARCH_PWR6
-#pragma options nostrict
-#endif
+  cdiDecodeParam(param, &num, &cat, &dis);
 
-#ifdef TEST_ENCODE
-#include <stdio.h>
-#include <stdlib.h>
-#define  GRIBPACK     unsigned char
-#define  IS_BIGENDIAN()  (u_byteorder.c[sizeof(long) - 1])
-#define  U_BYTEORDER     static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1}
-#define  Error(x,y)
-#endif
+  size_t umaxlen = maxlen >= 0 ? (unsigned)maxlen : 0U;
+  if ( dis == 255 && (cat == 255 || cat == 0 ) )
+    len = snprintf(paramstr, umaxlen, "%d", num);
+  else  if ( dis == 255 )
+    len = snprintf(paramstr, umaxlen, "%d.%d", num, cat);
+  else
+    len = snprintf(paramstr, umaxlen, "%d.%d.%d", num, cat, dis);
 
-//#undef _GET_X86_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _ARCH_PWR6
+  if ( len >= maxlen || len < 0)
+    fprintf(stderr, "Internal problem (%s): size of input string is too small!\n", __func__);
+}
 
-#if defined _GET_IBM_COUNTER
-#include <libhpc.h>
-#elif defined _GET_X86_COUNTER
-#include <x86intrin.h>
-#elif defined _GET_MACH_COUNTER
-#include <mach/mach_time.h>
-#endif
 
-#include <stdint.h>
+const char *cdiUnitNamePtr(int cdi_unit)
+{
+  const char *cdiUnits[] = {
+    /*  0 */  "undefined",
+    /*  1 */  "Pa",
+    /*  2 */  "hPa",
+    /*  3 */  "mm",
+    /*  4 */  "cm",
+    /*  5 */  "dm",
+    /*  6 */  "m",
+  };
+  enum { numUnits = (int) (sizeof(cdiUnits)/sizeof(char *)) };
+  const char *name = ( cdi_unit > 0 && cdi_unit < numUnits ) ?
+    cdiUnits[cdi_unit] : NULL;
+  return name;
+}
 
-#ifndef DISABLE_SIMD
-#if   defined(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
-#else
-#define DISABLE_SIMD
+size_t
+cdiGetPageSize(bool largePageAlign)
+{
+  long pagesize = -1L;
+#if HAVE_DECL__SC_LARGE_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE || HAVE_DECL__SC_PAGESIZE
+  bool nameAssigned = false;
+  int name;
+#  if HAVE_DECL__SC_LARGE_PAGESIZE
+  if (largePageAlign)
+    {
+      name = _SC_LARGE_PAGESIZE;
+      nameAssigned = true;
+    }
+  else
+#  else
+    (void)largePageAlign;
+#  endif
+    {
+#  if HAVE_DECL__SC_PAGESIZE || HAVE_DECL__SC_PAGE_SIZE
+      name =
+#    if HAVE_DECL__SC_PAGESIZE
+        _SC_PAGESIZE
+#    elif HAVE_DECL__SC_PAGE_SIZE
+        _SC_PAGE_SIZE
+#    endif
+        ;
+      nameAssigned = true;
+#  endif
+    }
+  if (nameAssigned)
+    pagesize = sysconf(name);
 #endif
+  if (pagesize == -1L)
+    pagesize =
+#if HAVE_DECL_PAGESIZE
+      PAGESIZE
+#elif HAVE_DECL_PAGE_SIZE
+      PAGE_SIZE
+#else
+      commonPageSize
 #endif
+      ;
+  return (size_t)pagesize;
+}
 
-#ifdef DISABLE_SIMD
-#define DISABLE_SIMD_ENCODE
-#endif
 
-//#define DISABLE_SIMD_ENCODE
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
 
-#ifdef DISABLE_SIMD_ENCODE
-# ifdef ENABLE_AVX
-#  define _ENABLE_AVX
-# endif
-# ifdef ENABLE_SSE4_1
-#  define _ENABLE_SSE4_1
-# endif
+/* Automatically generated by m214003 at 2017-09-29, do not edit */
+
+/* CGRIBEXLIB_VERSION="1.9.0" */
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#pragma GCC diagnostic warning "-Wstrict-overflow"
 #endif
 
-#ifndef DISABLE_SIMD_ENCODE
-# ifdef __AVX__
-#  define _ENABLE_AVX
-# endif
-# ifdef __SSE4_1__
-#  define _ENABLE_SSE4_1
-# endif
+#ifdef _ARCH_PWR6
+#pragma options nostrict
 #endif
 
-#if defined _ENABLE_AVX
-#include <immintrin.h>
-#elif defined _ENABLE_SSE4_1
-#include <smmintrin.h>
+#if defined (HAVE_CONFIG_H)
 #endif
 
-#if defined _ENABLE_AVX
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <inttypes.h>
 
-static
-void avx_encode_array_2byte_double(size_t datasize, 
-				   unsigned char * restrict lGrib,
-				   const double * restrict data, 
-				   double zref, double factor, size_t *gz) 
-{
-  size_t i, j, residual;
-  const double *dval = data;
-  __m128i *sgrib = (__m128i *) (lGrib+(*gz));
 
-  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
 
-  const __m256d c0 = _mm256_set1_pd(zref);
-  const __m256d c1 = _mm256_set1_pd(factor);
-  const __m256d c2 = _mm256_set1_pd(0.5);
-  
-  __m256d d0, d3, d2, d1;
-  __m128i i0, i1, i2, i3;
-  __m128i s0, s1;  
+#ifndef CGRIBEX_TEMPLATES_H
+#define CGRIBEX_TEMPLATES_H
 
-  residual = datasize % 16;
+#define CAT(X,Y)      X##_##Y
+#define TEMPLATE(X,Y) CAT(X,Y)
 
-  for (i = 0; i < (datasize-residual); i += 16)
-    {
-      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
-      //_____________________________________________________________________________
+#endif 
+#ifndef GRIB_INT_H
+#define GRIB_INT_H
 
-      d0 = _mm256_loadu_pd (dval);
-      d0 = _mm256_sub_pd (d0, c0);
-      d0 = _mm256_mul_pd (d0, c1);
-      d0 = _mm256_add_pd (d0, c2);
+#if defined (HAVE_CONFIG_H)
+#endif
 
-      i0 = _mm256_cvttpd_epi32 (d0);
-      
-      //_____________________________________________________________________________
-      
-      d1 = _mm256_loadu_pd (dval+4);
-      d1 = _mm256_sub_pd (d1, c0);
-      d1 = _mm256_mul_pd (d1, c1);
-      d1 = _mm256_add_pd (d1, c2);
-      
-      i1 = _mm256_cvttpd_epi32 (d1);
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include <float.h>
 
-      //_____________________________________________________________________________
 
-      s0 = _mm_packus_epi32(i0, i1);
-      s0 = _mm_shuffle_epi8 (s0, swap);
-      (void) _mm_storeu_si128 (sgrib, s0);
+#if ! defined   (CGRIBEX_H)
+#endif
+#if ! defined   (ERROR_H)
+#endif
+#if ! defined   (DTYPES_H)
+#endif
 
-      //_____________________________________________________________________________
 
-      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
+#if ! defined   (UCHAR)
+#define  UCHAR  unsigned char
+#endif
 
-      //_____________________________________________________________________________
-      
-      d2 = _mm256_loadu_pd (dval+8);
-      d2 = _mm256_sub_pd (d2, c0);
-      d2 = _mm256_mul_pd (d2, c1);
-      d2 = _mm256_add_pd (d2, c2);
-      
-      i2 = _mm256_cvttpd_epi32 (d2);
 
-      //_____________________________________________________________________________
-      
-      d3 = _mm256_loadu_pd (dval+12);
-      d3 = _mm256_sub_pd (d3, c0);
-      d3 = _mm256_mul_pd (d3, c1);
-      d3 = _mm256_add_pd (d3, c2);
-      
-      i3 = _mm256_cvttpd_epi32 (d3);
+#if defined (CRAY) || defined (SX) || defined (__uxpch__)
+#define VECTORCODE
+#endif
 
-      //_____________________________________________________________________________
 
-      s1 = _mm_packus_epi32(i2, i3);
-      s1 = _mm_shuffle_epi8 (s1, swap);
-      (void) _mm_storeu_si128 (sgrib+1, s1);
+#if defined (VECTORCODE)
+#if  defined  (INT32)
+#  define  GRIBPACK     unsigned INT32
+#  define  PACK_GRIB    packInt32
+#  define  UNPACK_GRIB  unpackInt32
+#else
+#  define  GRIBPACK     unsigned INT64
+#  define  PACK_GRIB    packInt64
+#  define  UNPACK_GRIB  unpackInt64
+#endif
+#else
+#  define  GRIBPACK     unsigned char
+#endif
 
-      //_____________________________________________________________________________
-           
-      dval += 16;
-      sgrib += 2;
-    }
+#define  U_BYTEORDER     static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1}
+#define  IS_BIGENDIAN()  (u_byteorder.c[sizeof(long) - 1])
 
-  if (i != datasize)
-    {
-      uint16_t ui16;
-      for ( j = i; j < datasize; j++ )
-	{
-	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
-	  lGrib[*gz+2*j  ] = ui16 >>  8;
-	  lGrib[*gz+2*j+1] = ui16;
-	}
-    }
-  
-  *gz += 2*datasize;
+#if defined (__xlC__) /* performance problems on IBM */
+#ifndef DBL_IS_NAN
+#  define DBL_IS_NAN(x)     ((x) != (x))
+#endif
+#else
+#ifndef DBL_IS_NAN
+#if  defined  (HAVE_DECL_ISNAN)
+#  define DBL_IS_NAN(x)     (isnan(x))
+#elif  defined  (FP_NAN)
+#  define DBL_IS_NAN(x)     (fpclassify(x) == FP_NAN)
+#else
+#  define DBL_IS_NAN(x)     ((x) != (x))
+#endif
+#endif
+#endif
 
-  return;
-}
+#ifndef IS_EQUAL
+#  define IS_NOT_EQUAL(x,y) (x < y || y < x)
+#  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
+#endif
 
-#define grib_encode_array_2byte_double avx_encode_array_2byte_double
+/* dummy use of unused parameters to silence compiler warnings */
+#ifndef UNUSED
+#define  UNUSED(x) (void)(x)
+#endif
 
-#elif defined _ENABLE_SSE4_1
+#define  JP24SET    0xFFFFFF  /* 2**24     (---> 16777215) */
+#define  JP23SET    0x7FFFFF  /* 2**23 - 1 (--->  8388607) */
 
-static
-void sse41_encode_array_2byte_double(size_t datasize, 
-				     unsigned char * restrict lGrib,
-				     const double * restrict data, 
-				     double zref, double factor, size_t *gz) 
-{
-  size_t i, j, residual;
-  const double *dval = data;
-  __m128i *sgrib = (__m128i *) (lGrib+(*gz));
+#define  POW_2_M24  0.000000059604644775390625  /* pow(2.0, -24.0) */
 
-  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-  const __m128d c0 = _mm_set1_pd(zref);
-  const __m128d c1 = _mm_set1_pd(factor);
-  const __m128d c2 = _mm_set1_pd(0.5);
-  
-  __m128d d0, d4, d3, d2, d1;
-  __m128i i0, i1, i2, i3, i4;
-  __m128i s0, s1;  
+#define intpow2(x) (ldexp(1.0, (x)))
 
-  residual = datasize % 16;
+unsigned correct_bdslen(unsigned bdslen, long recsize, long gribpos);
 
-  for (i = 0; i < (datasize-residual); i += 16)
-    {
-      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
-      //_____________________________________________________________________________
+/* CDI converter routines */
 
-      d0 = _mm_loadu_pd (dval);
-      d0 = _mm_sub_pd (d0, c0);
-      d0 = _mm_mul_pd (d0, c1);
-      d0 = _mm_add_pd (d0, c2);
-      
-      d4 = _mm_loadu_pd (dval+2);
-      d4 = _mm_sub_pd (d4, c0);
-      d4 = _mm_mul_pd (d4, c1);
-      d4 = _mm_add_pd (d4, c2);
+/* param format:  DDDCCCNNN */
 
-      i0 = _mm_cvttpd_epi32 (d0);
-      i4 = _mm_cvttpd_epi32 (d4);  
-      i0 = _mm_unpacklo_epi64 (i0, i4);
+void    cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis);
+int     cdiEncodeParam(int pnum, int pcat, int pdis);
 
-      //_____________________________________________________________________________
-      
-      d1 = _mm_loadu_pd (dval+4);
-      d1 = _mm_sub_pd (d1, c0);
-      d1 = _mm_mul_pd (d1, c1);
-      d1 = _mm_add_pd (d1, c2);
-      
-      d4 = _mm_loadu_pd (dval+6);
-      d4 = _mm_sub_pd (d4, c0);
-      d4 = _mm_mul_pd (d4, c1);
-      d4 = _mm_add_pd (d4, c2);
-      
-      i1 = _mm_cvttpd_epi32 (d1);
-      i4 = _mm_cvttpd_epi32 (d4);  
-      i1 = _mm_unpacklo_epi64 (i1, i4);
+/* date format:  YYYYMMDD */
+/* time format:  hhmmss   */
 
-      //_____________________________________________________________________________
+void    cdiDecodeDate(int date, int *year, int *month, int *day);
+int     cdiEncodeDate(int year, int month, int day);
 
-      s0 = _mm_packus_epi32(i0, i1);
-      s0 = _mm_shuffle_epi8 (s0, swap);
-      (void) _mm_storeu_si128 (sgrib, s0);
+void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
+int     cdiEncodeTime(int hour, int minute, int second);
 
-      //_____________________________________________________________________________
+/* CALENDAR types */
 
-      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
-
-      //_____________________________________________________________________________
-      
-      d2 = _mm_loadu_pd (dval+8);
-      d2 = _mm_sub_pd (d2, c0);
-      d2 = _mm_mul_pd (d2, c1);
-      d2 = _mm_add_pd (d2, c2);
-      
-      d4 = _mm_loadu_pd (dval+10);
-      d4 = _mm_sub_pd (d4, c0);
-      d4 = _mm_mul_pd (d4, c1);
-      d4 = _mm_add_pd (d4, c2);
-      
-      i2 = _mm_cvttpd_epi32 (d2);
-      i4  = _mm_cvttpd_epi32 (d4);  
-      i2 = _mm_unpacklo_epi64 (i2, i4);
-
-      //_____________________________________________________________________________
-      
-      d3 = _mm_loadu_pd (dval+12);
-      d3 = _mm_sub_pd (d3, c0);
-      d3 = _mm_mul_pd (d3, c1);
-      d3 = _mm_add_pd (d3, c2);
-      
-      d4 = _mm_loadu_pd (dval+14);
-      d4 = _mm_sub_pd (d4, c0);
-      d4 = _mm_mul_pd (d4, c1);
-      d4 = _mm_add_pd (d4, c2);
-      
-      i3 = _mm_cvttpd_epi32 (d3);
-      i4 = _mm_cvttpd_epi32 (d4);  
-      i3 = _mm_unpacklo_epi64 (i3, i4);
-
-      //_____________________________________________________________________________
-
-      s1 = _mm_packus_epi32(i2, i3);
-      s1 = _mm_shuffle_epi8 (s1, swap);
-      (void) _mm_storeu_si128 (sgrib+1, s1);
-
-      //_____________________________________________________________________________
-           
-      dval += 16;
-      sgrib += 2;
-    }
-
-  if (i != datasize) 
-    {
-      uint16_t ui16;
-      for ( j = i; j < datasize; j++ )
-	{
-	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
-	  lGrib[*gz+2*j  ] = ui16 >>  8;
-	  lGrib[*gz+2*j+1] = ui16;
-	}
-    }
-
-  *gz += 2*datasize;
-  
-  return;
-}
+#define  CALENDAR_STANDARD        0  /* don't change this value (used also in cgribexlib)! */
+#define  CALENDAR_GREGORIAN       1
+#define  CALENDAR_PROLEPTIC       2
+#define  CALENDAR_360DAYS         3
+#define  CALENDAR_365DAYS         4
+#define  CALENDAR_366DAYS         5
+#define  CALENDAR_NONE            6
 
-#define grib_encode_array_2byte_double sse41_encode_array_2byte_double
+extern FILE *grprsm;
 
-#else
+extern int  CGRIBEX_Debug;
 
-#define grib_encode_array_2byte_double encode_array_2byte_double
+void   gprintf(const char *caller, const char *fmt, ...);
 
-#endif // SIMD variants
+void   grsdef(void);
 
+void   prtbin(int kin, int knbit, int *kout, int *kerr);
+void   confp3(double pval, int *kexp, int *kmant, int kbits, int kround);
+double decfp2(int kexp, int kmant);
+void   ref2ibm(double *pref, int kbits);
 
-#ifdef TEST_ENCODE
+void   scale_complex_double(double *fpdata, int pcStart, int pcScale, int trunc, int inv);
+void   scale_complex_float(float *fpdata, int pcStart, int pcScale, int trunc, int inv);
+void   scatter_complex_double(double *fpdata, int pcStart, int trunc, int nsp);
+void   scatter_complex_float(float *fpdata, int pcStart, int trunc, int nsp);
+void   gather_complex_double(double *fpdata, size_t pcStart, size_t trunc, size_t nsp);
+void   gather_complex_float(float *fpdata, size_t pcStart, size_t trunc, size_t nsp);
 
-#define CAT(X,Y)      X##_##Y
-#define TEMPLATE(X,Y) CAT(X,Y)
+void   scm0_double(double *pdl, double *pdr, double *pfl, double *pfr, int klg);
+int    qu2reg2(double *pfield, int *kpoint, int klat, int klon,
+	       double *ztemp, double msval, int *kret);
+int    qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
+		      double msval, int *kret, int omisng, int operio, int oveggy);
+int    qu2reg3_float(float *pfield, int *kpoint, int klat, int klon,
+		     float msval, int *kret, int omisng, int operio, int oveggy);
 
-#ifdef T
-#undef T
+#if  defined  (INT32)
+long   packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc);
 #endif
-#define T double
-
-#ifdef T
-#undef T
+long   packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc);
+#if  defined  (INT32)
+long   unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc);
 #endif
-#define T float
+long   unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc);
 
+void  grib_encode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
+			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
+			 int kleng, int *kword, int efunc, int *kret);
+void  grib_encode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
+			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
+			int kleng, int *kword, int efunc, int *kret);
 
-#include <sys/time.h>
+void  grib_decode_double(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
+			 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
+			 int kleng, int *kword, int dfunc, int *kret);
+void  grib_decode_float(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
+			float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
+			int kleng, int *kword, int dfunc, int *kret);
 
-static
-double dtime()
-{
-  double tseconds = 0.0;
-  struct timeval mytime;
-  gettimeofday(&mytime, NULL);
-  tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
-  return (tseconds);
-}
 
-#define NRUN 10000
+int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
+		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize);
+int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
+		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
+		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp);
 
-static
-void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
-{
-  printf("%8s: val1: %d  val2: %d  val3: %d  valn: %d  time: %gs\n",
-         name, (int) lgrib[s*1+1], (int) lgrib[s*2+1], (int) lgrib[s*3+1], (int) lgrib[2*datasize-1], tt);
+#if defined (__cplusplus)
 }
+#endif
 
-int main(void)
-{
-  long datasize = 1000000;
-  double t_begin, t_end;
+#endif  /* GRIB_INT_H */
+#ifndef GRIBDECODE_H
+#define GRIBDECODE_H
 
-  float *dataf = (float*) malloc(datasize*sizeof(float));
-  double *data = (double*) malloc(datasize*sizeof(double));
-  unsigned char *lgrib = (unsigned char*) malloc(2*datasize*sizeof(unsigned char));
+#define  UNDEFINED          9.999e20
 
-  for ( long i = 0; i < datasize; ++i ) dataf[i] = (float) (-datasize/2 + i);
-  for ( long i = 0; i < datasize; ++i ) data[i] = (double) (-datasize/2 + i);
 
-  int PackStart = 0;
-  int nbpv = 16;
-  double zref = data[0];
-  size_t z;
-  double factor = 0.00390625;
-  int s = 256;
+#define  GET_INT3(a,b,c)    ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 16)+(b<<8)+c))
+#define  GET_INT2(a,b)      ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (((a & 127) << 8) + b))
+#define  GET_INT1(a)        ((1-(int) ((unsigned) (a & 128) >> 6)) * (int) (a&127))
 
-  if ( 0 )
-    {
-      encode_array_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
-      encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
-    }
+/* this requires a 32-bit default integer machine */
+#define  GET_UINT4(a,b,c,d) ((unsigned) ((a << 24) + (b << 16) + (c << 8) + (d)))
+#define  GET_UINT3(a,b,c)   ((unsigned) ((a << 16) + (b << 8)  + (c)))
+#define  GET_UINT2(a,b)     ((unsigned) ((a << 8)  + (b)))
+#define  GET_UINT1(a)       ((unsigned)  (a))
 
-#if   defined(__ICC)
-  printf("icc\n");
-#elif defined(__clang__)
-  printf("clang\n");
-#elif defined(__GNUC__)
-  printf("gcc\n");
-#endif
+#define  BUDG_START(s)      (s[0]=='B' && s[1]=='U' && s[2]=='D' && s[3]=='G')
+#define  TIDE_START(s)      (s[0]=='T' && s[1]=='I' && s[2]=='D' && s[3]=='E')
+#define  GRIB_START(s)      (s[0]=='G' && s[1]=='R' && s[2]=='I' && s[3]=='B')
+#define  GRIB_FIN(s)        (s[0]=='7' && s[1]=='7' && s[2]=='7' && s[3]=='7')
 
-  printf("float:\n");
+/* GRIB1 Section 0: Indicator Section (IS) */
 
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      encode_array_2byte_float(datasize, lgrib, dataf, (float)zref, (float)factor, &z);
-    }
-  t_end = dtime();
-  pout("orig", s, lgrib, datasize, t_end-t_begin);
+#define  GRIB1_SECLEN(s)     GET_UINT3(s[ 4], s[ 5], s[ 6])
+#define  GRIB_EDITION(s)     GET_UINT1(s[ 7])
 
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      encode_array_unrolled_float(nbpv, PackStart, datasize, lgrib, dataf, (float)zref, (float)factor, &z);
-    }
-  t_end = dtime();
-  pout("unrolled", s, lgrib, datasize, t_end-t_begin);
+/* GRIB1 Section 1: Product Definition Section (PDS) */
 
-  printf("double:\n");
+#define  PDS_Len             GET_UINT3(pds[ 0], pds[ 1], pds[ 2])
+#define  PDS_CodeTable       GET_UINT1(pds[ 3])
+#define  PDS_CenterID        GET_UINT1(pds[ 4])
+#define  PDS_ModelID         GET_UINT1(pds[ 5])
+#define  PDS_GridDefinition  GET_UINT1(pds[ 6])
+#define  PDS_Sec2Or3Flag     GET_UINT1(pds[ 7])
+#define  PDS_HAS_GDS         ((pds[7] & 128) != 0)
+#define  PDS_HAS_BMS         ((pds[7] &  64) != 0)
+#define  PDS_Parameter       GET_UINT1(pds[ 8])
+#define  PDS_LevelType       GET_UINT1(pds[ 9])
+#define  PDS_Level1          (pds[10])
+#define  PDS_Level2	     (pds[11])
+#define  PDS_Level	     GET_UINT2(pds[10], pds[11])
+#define  PDS_Year            GET_INT1(pds[12])
+#define  PDS_Month           GET_UINT1(pds[13])
+#define  PDS_Day             GET_UINT1(pds[14])
+#define  PDS_Hour            GET_UINT1(pds[15])
+#define  PDS_Minute          GET_UINT1(pds[16])
+#define  PDS_Date            (PDS_Year*10000+PDS_Month*100+PDS_Day)
+#define  PDS_Time            (PDS_Hour*100+PDS_Minute)
+#define  PDS_TimeUnit        GET_UINT1(pds[17])
+#define  PDS_TimePeriod1     GET_UINT1(pds[18])
+#define  PDS_TimePeriod2     GET_UINT1(pds[19])
+#define  PDS_TimeRange       GET_UINT1(pds[20])
+#define  PDS_AvgNum          GET_UINT2(pds[21], pds[22])
+#define  PDS_AvgMiss         GET_UINT1(pds[23])
+#define  PDS_Century         GET_UINT1(pds[24])
+#define  PDS_Subcenter       GET_UINT1(pds[25])
+#define  PDS_DecimalScale    GET_INT2(pds[26],pds[27])
 
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
-    }
-  t_end = dtime();
-  pout("orig", s, lgrib, datasize, t_end-t_begin);
 
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      encode_array_unrolled_double(nbpv, PackStart, datasize, lgrib, data, zref, factor, &z);
-    }
-  t_end = dtime();
-  pout("unrolled", s, lgrib, datasize, t_end-t_begin);
+/* GRIB1 Section 2: Grid Description Section (GDS) */
 
-#if defined _ENABLE_AVX
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      avx_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
-    }
-  t_end = dtime();
-  pout("avx", s, lgrib, datasize, t_end-t_begin);
-#elif defined _ENABLE_SSE4_1
-  t_begin = dtime();
-  for ( int i = 0; i < NRUN; ++i )
-    {
-      z = 0;
-      sse41_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
-    }
-  t_end = dtime();
-  pout("sse41", s, lgrib, datasize, t_end-t_begin);
-#endif
+#define  GDS_Len             ((gds) == NULL ? 0 : GET_UINT3(gds[0], gds[1], gds[2]))
+#define  GDS_NV              GET_UINT1(gds[ 3])
+#define  GDS_PVPL            GET_UINT1(gds[ 4])
+#define  GDS_PV	             ((gds[3] ==    0) ? -1 : (int) gds[4] - 1)
+#define  GDS_PL	             ((gds[4] == 0xFF) ? -1 : (int) gds[3] * 4 + (int) gds[4] - 1)
+#define  GDS_GridType        GET_UINT1(gds[ 5])
 
-  return 0;
-}
-#endif // TEST_ENCODE
 
-#undef DISABLE_SIMD_ENCODE
-#undef _ENABLE_AVX
-#undef _ENABLE_SSE4_1
+/* GRIB1 Triangular grid of DWD */
+#define  GDS_GME_NI2         GET_UINT2(gds[ 6], gds[ 7])
+#define  GDS_GME_NI3         GET_UINT2(gds[ 8], gds[ 9])
+#define  GDS_GME_ND          GET_UINT3(gds[10], gds[11], gds[12])
+#define  GDS_GME_NI          GET_UINT3(gds[13], gds[14], gds[15])
+#define  GDS_GME_AFlag       GET_UINT1(gds[16])
+#define  GDS_GME_LatPP       GET_INT3(gds[17], gds[18], gds[19])
+#define  GDS_GME_LonPP       GET_INT3(gds[20], gds[21], gds[22])
+#define  GDS_GME_LonMPL      GET_INT3(gds[23], gds[24], gds[25])
+#define  GDS_GME_BFlag       GET_UINT1(gds[27])
 
+/* GRIB1 Spectral */
+#define  GDS_PentaJ          GET_UINT2(gds[ 6], gds[ 7])
+#define  GDS_PentaK          GET_UINT2(gds[ 8], gds[ 9])
+#define  GDS_PentaM          GET_UINT2(gds[10], gds[11])
+#define  GDS_RepType         GET_UINT1(gds[12])
+#define  GDS_RepMode         GET_UINT1(gds[13])
 
-void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
-{
-  /*
+/* GRIB1 Regular grid */
+#define  GDS_NumLon          GET_UINT2(gds[ 6], gds[ 7])
+#define  GDS_NumLat          GET_UINT2(gds[ 8], gds[ 9])
+#define  GDS_FirstLat        GET_INT3(gds[10], gds[11], gds[12])
+#define  GDS_FirstLon        GET_INT3(gds[13], gds[14], gds[15])
+#define  GDS_ResFlag         GET_UINT1(gds[16])
+#define  GDS_LastLat         GET_INT3(gds[17], gds[18], gds[19])
+#define  GDS_LastLon         GET_INT3(gds[20], gds[21], gds[22])
+#define  GDS_LonIncr         GET_UINT2(gds[23], gds[24])
+#define  GDS_LatIncr         GET_UINT2(gds[25], gds[26])
+#define  GDS_NumPar          GET_UINT2(gds[25], gds[26])
+#define  GDS_ScanFlag        GET_UINT1(gds[27])
+#define  GDS_LatSP           GET_INT3(gds[32], gds[33], gds[34])
+#define  GDS_LonSP           GET_INT3(gds[35], gds[36], gds[37])
+#define  GDS_RotAngle        (GET_Real(&(gds[38])))
 
-    Purpose:
-    --------
+/* GRIB1 Lambert */
+#define  GDS_Lambert_Lov     GET_INT3(gds[17], gds[18], gds[19])
+#define  GDS_Lambert_dx	     GET_INT3(gds[20], gds[21], gds[22])
+#define  GDS_Lambert_dy	     GET_INT3(gds[23], gds[24], gds[25])
+#define  GDS_Lambert_ProjFlag GET_UINT1(gds[26])
+#define  GDS_Lambert_LatS1   GET_INT3(gds[28], gds[29], gds[30])
+#define  GDS_Lambert_LatS2   GET_INT3(gds[31], gds[32], gds[33])
+#define  GDS_Lambert_LatSP   GET_INT3(gds[34], gds[35], gds[36])
+#define  GDS_Lambert_LonSP   GET_INT3(gds[37], gds[37], gds[37])
 
-    Convert floating point number from machine
-    representation to GRIB representation.
+/* GRIB1 Section 3: Bit Map Section (BMS) */
 
-    Input Parameters:
-    -----------------
+#define  BMS_Len	     ((bms) == NULL ? 0 : GET_UINT3(bms[0], bms[1], bms[2]))
+#define  BMS_UnusedBits      (bms[3])
+#define  BMS_Numeric         
+#define  BMS_Bitmap	     ((bms) == NULL ? NULL : (bms)+6)
+#define  BMS_BitmapSize      (((((bms[0]<<16)+(bms[1]<<8)+bms[2]) - 6)<<3) - bms[3])
 
-       pval    - Floating point number to be converted.
-       kbits   - Number of bits in computer word.
-       kround  - Conversion type.
-                 0 , Closest number in GRIB format less than
-                     original number.
-                 1 , Closest number in GRIB format to the
-                     original number (equal to, greater than or
-                     less than original number).
+/* GRIB1 Section 4: Binary Data Section (BDS) */
 
-    Output Parameters:
-    ------------------
+#define  BDS_Len	    GET_UINT3(bds[0], bds[1], bds[2])
+#define  BDS_Flag	    (bds[3])
+#define  BDS_BinScale       GET_INT2(bds[ 4], bds[ 5])
+#define  BDS_RefValue       (decfp2((int)bds[ 6], GET_UINT3(bds[7], bds[8], bds[9])))
+#define  BDS_NumBits        ((int) bds[10])
+#define  BDS_RealCoef       (decfp2((int)bds[zoff+11], GET_UINT3(bds[zoff+12], bds[zoff+13], bds[zoff+14])))
+#define  BDS_PackData       ((int) ((bds[zoff+11]<<8) + bds[zoff+12]))
+#define  BDS_Power          GET_INT2(bds[zoff+13], bds[zoff+14])
+#define  BDS_Z              (bds[13])
 
-       kexp    - 8 Bit signed exponent.
-       kmant   - 24 Bit mantissa.
+/* GRIB1 Section 5: End Section (ES) */
 
-    Method:
-    -------
+/* GRIB2 */
 
-    Floating point number represented as 8 bit signed
-    exponent and 24 bit mantissa in integer values.
+#define  GRIB2_SECLEN(section)   (GET_UINT4(section[0], section[1], section[2], section[3]))
+#define  GRIB2_SECNUM(section)   (GET_UINT1(section[4]))
 
-    Externals.
-    ----------
+#endif  /* GRIBDECODE_H */
+#ifndef CGRIBEX_GRIB_ENCODE_H
+#define CGRIBEX_GRIB_ENCODE_H
 
-    decfp2    - Decode from IBM floating point format.
+#include <limits.h>
 
-    Reference:
-    ----------
+#define PutnZero(n) \
+{ \
+  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
+  z += n; \
+}
 
-    WMO Manual on Codes re GRIB representation.
+#define Put1Byte(Value)  (lGrib[z++] = (GRIBPACK)(Value))
+#define Put2Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put3Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
+#define Put4Byte(Value) ((lGrib[z++] = (GRIBPACK)((Value) >> 24)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >> 16)),      \
+                         (lGrib[z++] = (GRIBPACK)((Value) >>  8)),      \
+                         (lGrib[z++] = (GRIBPACK)(Value)))
 
-    Comments:
-    ---------
+#define Put1Int(Value)  {ival = Value; if ( ival < 0 ) ival =     0x80 - ival; Put1Byte(ival);}
+#define Put2Int(Value)  {ival = Value; if ( ival < 0 ) ival =   0x8000 - ival; Put2Byte(ival);}
+#define Put3Int(Value)  {ival = Value; if ( ival < 0 ) ival = 0x800000 - ival; Put3Byte(ival);}
 
-    Routine aborts if an invalid conversion type parameter
-    is used or if a 24 bit mantissa is not produced.
+enum {
+  BitsPerInt = (int) (sizeof(int) * CHAR_BIT),
+};
 
-    Author:
-    -------
-     
-    John Hennessy   ECMWF   18.06.91
 
-    Modifications:
-    --------------
+#define Put1Real(Value)          \
+{                                \
+  confp3(Value, &exponent, &mantissa, BitsPerInt, 1); \
+  Put1Byte(exponent);            \
+  Put3Byte(mantissa);            \
+}
 
-    Uwe Schulzweida   MPIfM   01/04/2001
+#endif  /* CGRIBEX_GRIB_ENCODE_H */
+#ifndef CODEC_COMMON_H
+#define CODEC_COMMON_H
+#define gribSwapByteOrder_uint16(ui16)  ((uint16_t)((ui16<<8) | (ui16>>8)))
+#endif  /* CODEC_COMMON_H */
+/* 
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -qopenmp -DOMP_SIMD minmax_val.c
+ result on hama2 (icc 16.0.0):
+     float:
+minmax_val: fmin: -500000  fmax: 499999  time:   1.22s
+simd      : fmin: -500000  fmax: 499999  time:   1.20s
+    double:
+minmax_val: fmin: -500000  fmax: 499999  time:   2.86s
+orig      : fmin: -500000  fmax: 499999  time:   2.74s
+simd      : fmin: -500000  fmax: 499999  time:   2.70s
+avx       : fmin: -500000  fmax: 499999  time:   2.99s
 
-    Convert to C from EMOS library version 130
+gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
+ result on thunder5 (gcc 6.1.0):
+float:
+minmax_val: fmin: -500000  fmax: 499999  time:   8.25s
+  simd    : fmin: -500000  fmax: 499999  time:   1.24s
+double:
+minmax_val: fmin: -500000  fmax: 499999  time:   2.73s
+  orig    : fmin: -500000  fmax: 499999  time:   9.24s
+  simd    : fmin: -500000  fmax: 499999  time:   2.78s
+  avx     : fmin: -500000  fmax: 499999  time:   2.90s
 
-    Uwe Schulzweida   MPIfM   02/08/2002
+gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL minmax_val.c
+ result on bailung (gcc 4.8.2):
+  orig    : fmin: -500000  fmax: 499999  time:   4.82s
+  sse2    : fmin: -500000  fmax: 499999  time:   4.83s
 
-     - speed up by factor 1.6 on NEC SX6
-        - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
-  */
+gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD -Wa,-q minmax_val.c
+ result on thunder5 (gcc 4.8.2):
+  orig    : fmin: -500000  fmax: 499999  time:   3.10s
+  simd    : fmin: -500000  fmax: 499999  time:   3.10s # omp simd in gcc 4.9
+  avx     : fmin: -500000  fmax: 499999  time:   2.84s
 
-  // extern int CGRIBEX_Debug;
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_MINMAXVAL -openmp -DOMP_SIMD minmax_val.c
+ result on thunder5 (icc 14.0.2):
+  orig    : fmin: -500000  fmax: 499999  time:   2.83s
+  simd    : fmin: -500000  fmax: 499999  time:   2.83s
+  avx     : fmin: -500000  fmax: 499999  time:   2.92s
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 1 . Initialise                                          */
-  /* ----------------------------------------------------------------- */
+xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_MINMAXVAL minmax_val.c
+ result on blizzard (xlc 12):
+  orig    : fmin: -500000  fmax: 499999  time:   7.26s
+  pwr6u6  : fmin: -500000  fmax: 499999  time:   5.92s
+*/
+#if defined(_ARCH_PWR6)
+#pragma options nostrict
+#endif
 
-  /*  Check conversion type parameter. */
+#include <stdlib.h>
 
-  int iround = kround;
-  if ( iround != 0 && iround != 1 )
-    {
-      Error("Invalid conversion type = %d", iround);
+//#undef _GET_X86_COUNTER
+//#undef _GET_IBM_COUNTER
+//#undef _GET_MACH_COUNTER
+//#undef _ARCH_PWR6
 
-      /*  If not aborting, arbitrarily set rounding to 'up'. */
-     iround = 1;
-    }
+#if defined(_GET_IBM_COUNTER)
+#include <libhpc.h>
+#elif defined(_GET_X86_COUNTER)
+#include <x86intrin.h>
+#elif defined(_GET_MACH_COUNTER)
+#include <mach/mach_time.h>
+#endif
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 2 . Convert value of zero.                              */
-  /* ----------------------------------------------------------------- */
+#if   defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
+#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4)
+#define GNUC_PUSH_POP
+#endif
+#endif
 
-  if ( ! (fabs(pval) > 0))
-    {
-      *kexp  = 0;
-      *kmant = 0;
-      // iexp   = 0;
-      // isign  = 0;
-      goto LABEL900;
-    }
+#ifndef DISABLE_SIMD
+#if   defined(__GNUC__) && (__GNUC__ >= 4)
+#elif defined(__ICC)    && (__ICC >= 1100)
+#elif defined(__clang__)
+#else
+#define DISABLE_SIMD
+#endif
+#endif
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 3 . Convert other values.                               */
-  /* ----------------------------------------------------------------- */
-  {
-    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
-    double zref = pval;
+#ifdef DISABLE_SIMD
+#define DISABLE_SIMD_MINMAXVAL
+#endif
 
-    /*  Sign of value. */
+#if !defined(TEST_MINMAXVAL)
+#define DISABLE_SIMD_MINMAXVAL
+#endif
 
-    int isign = zref >= 0.0 ? 0 : 128;
-    zref = fabs(zref);
-
-    /*  Exponent. */
-
-    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
+#ifdef DISABLE_SIMD_MINMAXVAL
+# if defined(ENABLE_AVX)
+#  define _ENABLE_AVX
+# endif
+# if defined(ENABLE_SSE2)
+#  define _ENABLE_SSE2
+# endif
+#endif
 
-    /* only ANSI C99 has log2 */
-    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
+#ifndef DISABLE_SIMD_MINMAXVAL
+# if defined(__AVX__)
+#  define _ENABLE_AVX
+# endif
+# if defined(__SSE2__)
+#  define _ENABLE_SSE2
+# endif
+#endif
 
-    if ( iexp < 0   ) iexp = 0;
-    if ( iexp > 127 ) iexp = 127;
+#include <float.h>
+#include <stdint.h>
+#include <inttypes.h>
 
-    double rpowref;
-    /*
-      rpowref = zref / pow(16.0, (double)(iexp - 70));
-    */
+#if defined(_ENABLE_AVX)
+#include <immintrin.h>
+#elif defined(_ENABLE_SSE2)
+#include <emmintrin.h>
+#endif
 
-    rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-    /*  Mantissa. */
+#if defined(_ENABLE_AVX)
 
-    if ( iround == 0 )
-    {
-      /*  Closest number in GRIB format less than original number. */
-      /*  Truncate for positive numbers. */
-      /*  Round up for negative numbers. */
+static
+void avx_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
+{
+  double fmin[4], fmax[4];
+  __m256d current_max, current_min, work;
 
-      if ( isign == 0 )
-	*kmant = (int)rpowref;
-      else
-	*kmant = (int)lround(rpowref + 0.5);
-    }
-    else
-    {
-      /*  Closest number in GRIB format to the original number   */
-      /*  (equal to, greater than or less than original number). */
+  // load max and min values into all four slots of the YMM registers
+  current_min = _mm256_set1_pd(*min);
+  current_max = _mm256_set1_pd(*max);
 
-      *kmant = (int)lround(rpowref);
-    }
+  // Work input until "buf" reaches 32 byte alignment
+  while ( ((unsigned long)buf) % 32 != 0 && nframes > 0) {
 
-    /*  Check that mantissa value does not exceed 24 bits. */
-    /*  If it does, adjust the exponent upwards and recalculate */
-    /*  the mantissa. */
-    /*  16777215 = 2**24 - 1 */
+    // Load the next double into the work buffer
+    work = _mm256_set1_pd(*buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf++;
+    nframes--;
+  }
 
-    if ( *kmant > 16777215 )
-    {
+  while (nframes >= 16) {
 
-    LABEL350:
+    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
 
-      ++iexp;
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
 
-      /*  Check for exponent overflow during adjustment  */
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
 
-      if ( iexp > 127 )
-      {
-        Message("Exponent overflow");
-        Message("Original number = %30.20f", pval);
-        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
-                isign, iexp, *kmant);
+    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
 
-        Error("Exponent overflow");
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
 
-        /*  If not aborting, arbitrarily set value to zero  */
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
+    nframes -= 16;
+  }
 
-        Message("Value arbitrarily set to zero.");
-        *kexp  = 0;
-        *kmant = 0;
-        // iexp  = 0;
-        // isign = 0;
-        goto LABEL900;
-      }
+  // work through aligned buffers
+  while (nframes >= 4) {
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
+    nframes -= 4;
+  }
 
-      rpowref = ldexp(zref, 4 * -(iexp - 70));
+  // work through the remainung values
+  while ( nframes > 0) {
+    work = _mm256_set1_pd(*buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf++;
+    nframes--;
+  }
 
-      if ( iround == 0 )
-      {
-        /*  Closest number in GRIB format less than original number. */
-        /*  Truncate for positive numbers. */
-        /*  Round up for negative numbers. */
+  // find min & max value through shuffle tricks
 
-        if ( isign == 0 )
-          *kmant = (int)rpowref;
-        else
-          *kmant = (int)lround(rpowref + 0.5);
-      }
-      else
-      {
-        /*  Closest number in GRIB format to the original number */
-        /*  (equal to, greater or less than original number). */
+  work = current_min;
+  work = _mm256_shuffle_pd(work, work, 5);
+  work = _mm256_min_pd (work, current_min);
+  current_min = work;
+  work = _mm256_permute2f128_pd(work, work, 1);
+  work = _mm256_min_pd (work, current_min);
+  _mm256_storeu_pd(fmin, work);
 
-        *kmant = (int)lround(rpowref);
-      }
+  work = current_max;
+  work = current_max;
+  work = _mm256_shuffle_pd(work, work, 5);
+  work = _mm256_max_pd (work, current_max);
+  current_max = work;
+  work = _mm256_permute2f128_pd(work, work, 1);
+  work = _mm256_max_pd (work, current_max);
+  _mm256_storeu_pd(fmax, work);
 
-      /*  Repeat calculation (with modified exponent) if still have */
-      /*  mantissa overflow. */
+  *min = fmin[0];
+  *max = fmax[0];
 
-      if ( *kmant > 16777215 ) goto LABEL350;
-    }
+  return;
+}
 
-    /*  Add sign bit to exponent. */
+#elif defined(_ENABLE_SSE2)
 
-    *kexp = iexp + isign;
+static
+void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
+{
+  __m128d current_max, current_min, work;
+  
+  // load starting max and min values into all slots of the XMM registers
+  current_min = _mm_set1_pd(*min);
+  current_max = _mm_set1_pd(*max);
+  
+  // work on input until buf reaches 16 byte alignment
+  while ( ((unsigned long)buf) % 16 != 0 && nframes > 0) {
+    
+    // load one double and replicate
+    work = _mm_set1_pd(*buf);    
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);    
+    buf++;
+    nframes--;
   }
+  
+  while (nframes >= 8) {
+    // use 64 byte prefetch for double octetts
+    // __builtin_prefetch(buf+64,0,0); // for GCC 4.3.2 +
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 9. Return                                               */
-  /* ----------------------------------------------------------------- */
+    work = _mm_load_pd(buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf += 2;
+    work = _mm_load_pd(buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf += 2;
+    work = _mm_load_pd(buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf += 2;
+    work = _mm_load_pd(buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf += 2;
+    nframes -= 8;
+  }
 
-LABEL900:
-  /*
-  if ( CGRIBEX_Debug )
-    {
-      double zval;
+  // work through smaller chunks of aligned buffers without prefetching
+  while (nframes >= 2) {
+    work = _mm_load_pd(buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf += 2;
+    nframes -= 2;
+  }
 
-      Message("Conversion type parameter = %4d", kround);
-      Message("Original number = %30.20f", pval);
+  // work through the remaining value
+  while ( nframes > 0) {
+    // load the last double and replicate
+    work = _mm_set1_pd(*buf);
+    current_min = _mm_min_pd(current_min, work);
+    current_max = _mm_max_pd(current_max, work);
+    buf++;
+    nframes--;
+  }
 
-      zval = decfp2(*kexp, *kmant);
+  // find final min and max value through shuffle tricks
+  work = current_min;
+  work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
+  work = _mm_min_pd (work, current_min);
+  _mm_store_sd(min, work);
+  work = current_max;
+  work = _mm_shuffle_pd(work, work, _MM_SHUFFLE2(0, 1));
+  work = _mm_max_pd (work, current_max);
+  _mm_store_sd(max, work);
 
-      Message("Converted to      %30.20f", zval);
-      Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
-    }
-  */
   return;
-} /* confp3 */
-#include <math.h>
+}
 
+#endif // SIMD
 
-double decfp2(int kexp, int kmant)
+#if defined(_ARCH_PWR6)
+static
+void pwr6_minmax_val_double_unrolled6(const double *restrict data, size_t datasize, double *fmin, double *fmax)
 {
-  /*
+#define __UNROLL_DEPTH_1 6
 
-    Purpose:
-    --------
+  // to allow pipelining we have to unroll 
 
-    Convert GRIB representation of a floating point
-    number to machine representation.
+  {
+    size_t i, j;
+    size_t residual =  datasize % __UNROLL_DEPTH_1;
+    size_t ofs = datasize - residual;
+    double register dmin[__UNROLL_DEPTH_1];
+    double register dmax[__UNROLL_DEPTH_1];
 
-    Input Parameters:
-    -----------------
+    for ( j = 0; j < __UNROLL_DEPTH_1; j++) 
+      {
+	dmin[j] = data[0];
+	dmax[j] = data[0];
+      }
+    
+    for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_1 ) 
+      {
+	for (j = 0; j < __UNROLL_DEPTH_1; j++) 
+	  {
+	    dmin[j] = __fsel(dmin[j] - data[i+j], data[i+j], dmin[j]);
+	    dmax[j] = __fsel(data[i+j] - dmax[j], data[i+j], dmax[j]);
+	  }
+      }
 
-    kexp    - 8 Bit signed exponent.
-    kmant   - 24 Bit mantissa.
+    for (j = 0; j < residual; j++) 
+      {
+	dmin[j] = __fsel(dmin[j] - data[ofs+j], data[ofs+j], dmin[j]);
+	dmax[j] = __fsel(data[ofs+j] - dmax[j], data[ofs+j], dmax[j]);
+      }
 
-    Output Parameters:
-    ------------------
+    for ( j = 0; j < __UNROLL_DEPTH_1; j++) 
+      {
+	*fmin = __fsel(*fmin - dmin[j], dmin[j], *fmin);
+	*fmax = __fsel(dmax[j] - *fmax, dmax[j], *fmax);
+      }
+  }
+#undef __UNROLL_DEPTH_1
+}
+#endif
 
-    Return value   - Floating point number represented
-                     by kexp and kmant.
+#if defined(TEST_MINMAXVAL) && defined(__GNUC__)
+static
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
+static
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax) __attribute__ ((noinline));
+static
+void minmax_val_float(const float *restrict data, long datasize, float *fmin, float *fmax) __attribute__ ((noinline));
+static
+void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax) __attribute__ ((noinline));
+#endif
 
-    Method:
-    -------
+#if defined(GNUC_PUSH_POP)
+#pragma GCC push_options
+#pragma GCC optimize ("O3", "fast-math")
+#endif
+static
+void minmax_val_double_orig(const double *restrict data, size_t datasize, double *fmin, double *fmax)
+{
+  double dmin = *fmin, dmax = *fmax;
 
-    Floating point number represented as 8 bit exponent
-    and 24 bit mantissa in integer values converted to
-    machine floating point format.
+#if   defined(CRAY)
+#pragma _CRI ivdep
+#elif defined(SX)
+#pragma vdir nodep
+#elif defined(__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+  for ( size_t i = 0; i < datasize; ++i )
+    {
+      dmin = dmin < data[i] ? dmin : data[i];
+      dmax = dmax > data[i] ? dmax : data[i];
+    }
 
-    Externals:
-    ----------
+  *fmin = dmin;
+  *fmax = dmax;
+}
 
-    None.
+static
+void minmax_val_float(const float *restrict data, long idatasize, float *fmin, float *fmax)
+{
+  size_t datasize = (size_t)idatasize;
+  float dmin = *fmin, dmax = *fmax;
 
-    Reference:
-    ----------
+#if   defined(CRAY)
+#pragma _CRI ivdep
+#elif defined(SX)
+#pragma vdir nodep
+#elif defined(__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+  for ( size_t i = 0; i < datasize; ++i )
+    {
+      dmin = dmin < data[i] ? dmin : data[i];
+      dmax = dmax > data[i] ? dmax : data[i];
+    }
 
-    WMO Manual on Codes re GRIB representation.
+  *fmin = dmin;
+  *fmax = dmax;
+}
+#if defined(GNUC_PUSH_POP)
+#pragma GCC pop_options
+#endif
 
-    Comments:
-    ---------
+// TEST
+#if defined(OMP_SIMD)
 
-    Rewritten from DECFP, to conform to programming standards.
-    Sign bit on 0 value now ignored, if present.
-    If using 32 bit reals, check power of 16 is not so small as to
-    cause overflows (underflows!); this causes warning to be given
-    on Fujitsus.
+#if defined(GNUC_PUSH_POP)
+#pragma GCC push_options
+#pragma GCC optimize ("O3", "fast-math")
+#endif
+static
+void minmax_val_double_simd(const double *restrict data, size_t datasize, double *fmin, double *fmax)
+{
+  double dmin = *fmin, dmax = *fmax;
 
-    Author:
-    -------
+#if defined(_OPENMP)
+#pragma omp simd reduction(min:dmin) reduction(max:dmax)
+#endif
+  for ( size_t i = 0; i < datasize; ++i )
+    {
+      dmin = dmin < data[i] ? dmin : data[i];
+      dmax = dmax > data[i] ? dmax : data[i];
+    }
 
-    John Hennessy   ECMWF   18.06.91
+  *fmin = dmin;
+  *fmax = dmax;
+}
+static
+void minmax_val_float_simd(const float *restrict data, size_t datasize, float *fmin, float *fmax)
+{
+  float dmin = *fmin, dmax = *fmax;
 
-    Modifications:
-    --------------
+#if defined(_OPENMP)
+#pragma omp simd reduction(min:dmin) reduction(max:dmax)
+#endif
+  for ( size_t i = 0; i < datasize; ++i )
+    {
+      dmin = dmin < data[i] ? dmin : data[i];
+      dmax = dmax > data[i] ? dmax : data[i];
+    }
 
-    Uwe Schulzweida   MPIfM   01/04/2001
+  *fmin = dmin;
+  *fmax = dmax;
+}
+#if defined(GNUC_PUSH_POP)
+#pragma GCC pop_options
+#endif
+#endif
 
-     - Convert to C from EMOS library version 130
+static
+void minmax_val_double(const double *restrict data, long idatasize, double *fmin, double *fmax)
+{
+#if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER) 
+  uint64_t start_minmax, end_minmax;
+#endif
+  size_t datasize = (size_t)idatasize;
 
-    Uwe Schulzweida   MPIfM   02/08/2002
+  if ( idatasize >= 1 ) ; else return;
 
-     - speed up by factor 2 on NEC SX6
-        - replace pow(2.0, -24.0) by constant POW_2_M24
-        - replace pow(16.0, (double)(iexp - 64)) by pow16m64tab[iexp]
-  */
+#if defined(_GET_X86_COUNTER) 
+  start_minmax = _rdtsc();
+#endif
+#if defined(_GET_MACH_COUNTER) 
+  start_minmax = mach_absolute_time();
+#endif
 
-  double pval;
-  //extern int CGRIBEX_Debug;
-  /* ----------------------------------------------------------------- */
-  /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
-  /* ----------------------------------------------------------------- */
+#if defined(_ENABLE_AVX)
 
-  //if ( CGRIBEX_Debug ) Message("KEXP = %d  KMANT = %d", kexp, kmant);
-  /*
-  if ( (kexp == 128 || kexp == 0) && kmant == 0 )
-  */
-  if ( (kexp == 128) || (kexp == 0) || (kexp == 255) )
-    {
-      pval = 0.0;
-      goto LABEL900;
-    }
+  avx_minmax_val_double(data, datasize, fmin, fmax);
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 2 . Convert other values.                               */
-  /* ----------------------------------------------------------------- */
+#elif defined(_ENABLE_SSE2)
 
-  /*  Sign of value. */
+  sse2_minmax_val_double(data, datasize, fmin, fmax);
 
-  int iexp  = kexp,
-    isign = (iexp < 128) * 2 - 1;
+#else
 
-  iexp -= iexp < 128 ? 0 : 128;
+#if defined(_ARCH_PWR6)
+#define __UNROLL_DEPTH_1 6
 
-  /*  Decode value. */
+  // to allow pipelining we have to unroll 
 
-  /* pval = isign * pow(2.0, -24.0) * kmant * pow(16.0, (double)(iexp - 64)); */
+#if defined(_GET_IBM_COUNTER)
+  hpmStart(1, "minmax fsel");
+#endif
 
-  iexp -= 64;
+  pwr6_minmax_val_double_unrolled6(data, datasize, fmin, fmax);
 
-  pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
+#if defined(_GET_IBM_COUNTER) 
+  hpmStop(1);
+#endif
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 9. Return to calling routine.                           */
-  /* ----------------------------------------------------------------- */
+#undef __UNROLL_DEPTH_1
 
-LABEL900:
+#else // original loop
 
-  //if ( CGRIBEX_Debug ) Message("Returned value = %f", pval);
+#if defined(_GET_IBM_COUNTER) 
+  hpmStart(1, "minmax base");
+#endif
 
-  return (pval);
-} /* decfp2 */
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdarg.h>
+  minmax_val_double_orig(data, datasize, fmin, fmax);
 
+#if defined(_GET_IBM_COUNTER) 
+  hpmStop(1);
+#endif
 
+#endif // _ARCH_PWR6 && original loop
+#endif // SIMD
 
-int gribRefDate(int *isec1)
-{
-  int date, ryear, rmonth, rday;
-  int century;
-
-  century = ISEC1_Century;
-  if ( century < 0 ) century = -century;
-  century -= 1;
-
-  ryear   = ISEC1_Year;
-
-  /* if ( century != 0 ) */
-    {
-      if ( ryear == 100 )
-	{
-	  ryear = 0;
-	  century += 1;
-	}
+#if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER)
+#if defined(_GET_X86_COUNTER) 
+  end_minmax = _rdtsc();
+#endif
+#if defined(_GET_MACH_COUNTER) 
+  end_minmax = mach_absolute_time();
+#endif
+#if defined(_ENABLE_AVX)
+  printf("AVX minmax cycles:: %" PRIu64 "\n",  end_minmax-start_minmax);
+  fprintf (stderr, "AVX min: %lf max: %lf\n", *fmin, *fmax);
+#elif defined(_ENABLE_SSE2)
+  printf("SSE2 minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+  fprintf (stderr, "SSE2 min: %lf max: %lf\n", *fmin, *fmax);
+#else
+  printf("loop minmax cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+  fprintf (stderr, "loop min: %lf max: %lf\n", *fmin, *fmax);
+#endif
+#endif
 
-      if ( ryear != 255 )
-	{
-	  ryear = century*100 + ryear;
-	  if ( ISEC1_Century < 0 ) ryear = -ryear;
-	}
-      else
-	ryear = 1;
-    }
+  return;
+}
 
-  rmonth  = ISEC1_Month;
-  rday    = ISEC1_Day;
+#if defined(TEST_MINMAXVAL)
 
-  date = cdiEncodeDate(ryear, rmonth, rday);
+#include <stdio.h>
+#include <sys/time.h>
 
-  return (date) ;
+static
+double dtime()
+{
+  double tseconds = 0.0;
+  struct timeval mytime;
+  gettimeofday(&mytime, NULL);
+  tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
+  return (tseconds);
 }
 
+#define NRUN 10000
 
-int gribRefTime(int *isec1)
+int main(void)
 {
-  int time, rhour, rminute;
+  long datasize = 1000000;
+  double t_begin, t_end;
 
-  rhour   = ISEC1_Hour;
-  rminute = ISEC1_Minute;
+#if   defined(_OPENMP)
+  printf("_OPENMP=%d\n", _OPENMP);
+#endif
 
-  time = cdiEncodeTime(rhour, rminute, 0);
+#if   defined(__ICC)
+  printf("icc\n");
+#elif defined(__clang__)
+  printf("clang\n");
+#elif defined(__GNUC__)
+  printf("gcc\n");
+#endif
 
-  return (time) ;
-}
+  {
+    float fmin, fmax;
+    float *data_sp = (float*) malloc(datasize*sizeof(float));
 
+    for ( long i = 0; i < datasize/2; i++ )        data_sp[i] = (float) (i);
+    for ( long i = datasize/2; i < datasize; i++ ) data_sp[i] = (float) (-datasize + i);
 
-int gribTimeIsFC(int *isec1)
-{
-  int isFC = FALSE;
-  int time_period;
+    printf("float:\n");
 
-  if ( ISEC1_TimeRange == 10 )
-    time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
-  else
-    time_period = ISEC1_TimePeriod1;
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_sp[0];
+	minmax_val_float(data_sp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 
-  if ( time_period > 0 && ISEC1_Day > 0 )
-    {
-      if ( ISEC1_TimeRange == 0 || ISEC1_TimeRange == 10 ) isFC = TRUE;
-    }
+#if defined(OMP_SIMD)
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_sp[0];
+	minmax_val_float_simd(data_sp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+#endif
 
-  return (isFC);
-}
+    free(data_sp);
+  }
 
+  {
+    double fmin, fmax;
+    double *data_dp = (double*) malloc(datasize*sizeof(double));
 
-void gribDateTime(int *isec1, int *date, int *time)
-{
-  static int lprint = TRUE;
-  int julday, secofday;
-  int64_t addsec = 0;
-  int64_t time_period = 0;
-  extern int grib_calendar;
+    // for ( long i = datasize-1; i >= 0; i-- ) data[i] = (double) (-datasize/2 + i);
+    for ( long i = 0; i < datasize/2; i++ )        data_dp[i] = (double) (i);
+    for ( long i = datasize/2; i < datasize; i++ ) data_dp[i] = (double) (-datasize + i);
 
-  int century = ISEC1_Century;
-  int ryear   = ISEC1_Year;
+    printf("double:\n");
 
-  if ( century == -255 && ryear == 127 )
-    {
-      century = 0;
-      ryear = 0;
-    }
-  else
-    {
-      if ( century < 0 ) century = -century;
-      century -= 1;
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_dp[0];
+	minmax_val_double(data_dp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("minmax_val: fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 
-      /* if ( century != 0 ) */
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
       {
-        if ( ryear == 100 )
-          {
-            ryear = 0;
-            century += 1;
-          }
+	fmin = fmax = data_dp[0];
+	minmax_val_double_orig(data_dp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("orig      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
 
-        if ( ryear != 255 )
-          {
-            ryear = century*100 + ryear;
-            if ( ISEC1_Century < 0 ) ryear = -ryear;
-          }
-        else
-          ryear = 1;
+#if defined(OMP_SIMD)
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_dp[0];
+	minmax_val_double_simd(data_dp, datasize, &fmin, &fmax);
       }
-    }
+    t_end = dtime();
+    printf("simd      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+#endif
 
-  int rmonth  = ISEC1_Month;
-  int rday    = ISEC1_Day;
+#if defined(_ENABLE_AVX)
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_dp[0];
+	avx_minmax_val_double(data_dp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("avx       : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+#elif defined(_ENABLE_SSE2)
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_dp[0];
+	sse2_minmax_val_double(data_dp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("sse2      : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+#endif
+#if defined(_ARCH_PWR6)
+    t_begin = dtime();
+    for ( int i = 0; i < NRUN; ++i )
+      {
+	fmin = fmax = data_dp[0];
+	pwr6_minmax_val_double_unrolled6(data_dp, datasize, &fmin, &fmax);
+      }
+    t_end = dtime();
+    printf("pwr6u6  : fmin: %ld  fmax: %ld  time: %6.2fs\n", (long)fmin, (long) fmax, t_end-t_begin);
+#endif
+    free(data_dp);
+  }
 
-  int rhour   = ISEC1_Hour;
-  int rminute = ISEC1_Minute;
-  int second  = 0;
+  return (0);
+}
+#endif // TEST_MINMAXVAL
 
-  /* printf("ref %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute); */
+#undef DISABLE_SIMD_MINMAXVAL
+#undef _ENABLE_AVX
+#undef _ENABLE_SSE2
+#undef GNUC_PUSH_POP
+/*
+### new version with gribSwapByteOrder_uint16()
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
+ result on hama2 (icc 16.0.2):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 1.8731s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.0898s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.68089s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30798s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.23864s
 
-  if ( ISEC1_TimeRange == 10 )
-    time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
-  else if ( ISEC1_TimeRange >=2 && ISEC1_TimeRange <= 5 )
-    time_period = ISEC1_TimePeriod2;
-  else if ( ISEC1_TimeRange == 0 )
-    time_period = ISEC1_TimePeriod1;
+gcc -g -Wall -O3 -march=native -Wa,-q -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 6.1.0):
+float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.22871s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 2.30281s
+double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.2669s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.81643s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.98415s
 
-  if ( time_period > 0 && rday > 0 )
-    {
-      encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, second, &julday, &secofday);
+###
+icc -g -Wall -O3 -march=native -std=c99 -qopt-report=5 -DTEST_ENCODE encode_array.c
+ result on hama2 (icc 16.0.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.10691s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.63584s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 13.5768s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 9.17742s
+     avx: val1: 1  val2: 1  val3: 2  valn: 66  time: 3.9488s
 
-      addsec = 0;
-      switch ( ISEC1_TimeUnit )
-	{
-	case ISEC1_TABLE4_MINUTE:    addsec =    60 * time_period; break;
-	case ISEC1_TABLE4_QUARTER:   addsec =   900 * time_period; break;
-	case ISEC1_TABLE4_30MINUTES: addsec =  1800 * time_period; break;
-	case ISEC1_TABLE4_HOUR:      addsec =  3600 * time_period; break;
-	case ISEC1_TABLE4_3HOURS:    addsec = 10800 * time_period; break;
-	case ISEC1_TABLE4_6HOURS:    addsec = 21600 * time_period; break;
-	case ISEC1_TABLE4_12HOURS:   addsec = 43200 * time_period; break;
-	case ISEC1_TABLE4_DAY:       addsec = 86400 * time_period; break;
-	default:
-	  if ( lprint )
-	    {
-	      gprintf(__func__, "Time unit %d unsupported", ISEC1_TimeUnit);
-	      lprint = FALSE;
-	    }
-	  break;
-	}
+gcc -g -Wall -O3 -std=c99 -DTEST_ENCODE encode_array.c
+ result on hama2 (gcc 5.2.0):
+   float:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 5.32775s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.87125s
+  double:
+    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 7.85873s
+unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 12.9979s
 
-      julday_add_seconds(addsec, &julday, &secofday);
+###
+gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
+ result on bailung (gcc 4.7):
+  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 8.4166s
+  sse41   : val1: 1  val2: 1  val3: 2  valn: 66  time: 7.1522s
 
-      decode_caldaysec(grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &second);
-    }
-  /*
-  printf("new %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute);
-  */
-  *date = cdiEncodeDate(ryear, rmonth, rday);
-  *time = cdiEncodeTime(rhour, rminute, 0);
+gcc -g -Wall -O3 -march=native -std=c99 -DTEST_ENCODE encode_array.c
+ result on thunder5 (gcc 4.7):
+  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 6.21976s
+  avx     : val1: 1  val2: 1  val3: 2  valn: 66  time: 4.54485s
 
-  return;
-}
+icc -g -Wall -O3 -march=native -std=c99 -vec-report=1 -DTEST_ENCODE encode_array.c
+ result on thunder5 (icc 13.2):
+  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 14.6279s
+  avx     : val1: 1  val2: 1  val3: 2  valn: 66  time:  4.9776s
 
+xlc_r -g -O3 -qhot -q64 -qarch=auto -qtune=auto -qreport -DTEST_ENCODE encode_array.c
+ result on blizzard (xlc 12):
+  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 132.25s
+  unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  27.202s
+  orig    : val1: 1  val2: 1  val3: 2  valn: 66  time: 106.627s  // without -qhot
+  unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time:  39.929s  // without -qhot
+*/
+#ifdef _ARCH_PWR6
+#pragma options nostrict
+#endif
 
-void gprintf(const char *caller, const char *fmt, ...)
-{
-  va_list args;
+#ifdef TEST_ENCODE
+#include <stdio.h>
+#include <stdlib.h>
+#define  GRIBPACK     unsigned char
+#define  IS_BIGENDIAN()  (u_byteorder.c[sizeof(long) - 1])
+#define  U_BYTEORDER     static union {unsigned long l; unsigned char c[sizeof(long)];} u_byteorder = {1}
+#define  Error(x,y)
+#endif
 
-  if ( grprsm == NULL ) Error("GRIBEX initialization missing!");
-	
-  va_start(args, fmt);
+//#undef _GET_X86_COUNTER
+//#undef _GET_MACH_COUNTER
+//#undef _GET_IBM_COUNTER
+//#undef _ARCH_PWR6
 
-   fprintf(grprsm, "%-18s : ", caller);
-  vfprintf(grprsm, fmt, args);
-   fprintf(grprsm, "\n");
+#if defined _GET_IBM_COUNTER
+#include <libhpc.h>
+#elif defined _GET_X86_COUNTER
+#include <x86intrin.h>
+#elif defined _GET_MACH_COUNTER
+#include <mach/mach_time.h>
+#endif
 
-  va_end(args);
-}
+#include <stdint.h>
+#include <math.h>
 
+#ifndef DISABLE_SIMD
+#if   defined(__GNUC__) && (__GNUC__ >= 4)
+#elif defined(__ICC)    && (__ICC >= 1100)
+#elif defined(__clang__)
+#else
+#define DISABLE_SIMD
+#endif
+#endif
 
-void
-gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
-	 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, const char *hoper, int *kret)
-{
-  int yfunc = *hoper;
+#ifdef DISABLE_SIMD
+#define DISABLE_SIMD_ENCODE
+#endif
 
-  if ( yfunc == 'C' )
-    {
-      grib_encode_double(isec0, isec1, isec2, fsec2, isec3,
-			 fsec3, isec4, fsec4, klenp, kgrib,
-			 kleng, kword, yfunc, kret);
-    }
-  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
-    {
-      grib_decode_double(isec0, isec1, isec2, fsec2, isec3,
-			 fsec3, isec4, fsec4, klenp, kgrib,
-			 kleng, kword, yfunc, kret);
-    }
-  else if ( yfunc == 'V' )
-    {
-      fprintf(stderr, "  cgribex: Version is %s\n", cgribexLibraryVersion());
-    }
-  else
-    {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
-    }
-}
+//#define DISABLE_SIMD_ENCODE
 
+#ifdef DISABLE_SIMD_ENCODE
+# ifdef ENABLE_AVX
+#  define _ENABLE_AVX
+# endif
+# ifdef ENABLE_SSE4_1
+#  define _ENABLE_SSE4_1
+# endif
+#endif
 
-void
-gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
-	 float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
-	 int kleng, int *kword, const char *hoper, int *kret)
-{
-  int yfunc = *hoper;
+#ifndef DISABLE_SIMD_ENCODE
+# ifdef __AVX__
+#  define _ENABLE_AVX
+# endif
+# ifdef __SSE4_1__
+#  define _ENABLE_SSE4_1
+# endif
+#endif
 
-  if ( yfunc == 'C' )
-    {
-      grib_encode_float(isec0, isec1, isec2, fsec2, isec3,
-			fsec3, isec4, fsec4, klenp, kgrib,
-			kleng, kword, yfunc, kret);
-    }
-  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
-    {
-      grib_decode_float(isec0, isec1, isec2, fsec2, isec3,
-			fsec3, isec4, fsec4, klenp, kgrib,
-			kleng, kword, yfunc, kret);
-    }
-  else if ( yfunc == 'V' )
-    {
-      fprintf(stderr, " cgribex: Version is %s\n", cgribexLibraryVersion());
-    }
-  else
-    {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
-    }
-}
+#if defined _ENABLE_AVX
+#include <immintrin.h>
+#elif defined _ENABLE_SSE4_1
+#include <smmintrin.h>
+#endif
 
-int CGRIBEX_Fix_ZSE  = 0;    /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
-int CGRIBEX_Const    = 0;    /* 1: Don't pack constant fields on regular grids */
-int CGRIBEX_Debug    = 0;    /* 1: Debugging */
+#if defined _ENABLE_AVX
 
-void gribSetDebug(int debug)
+static
+void avx_encode_array_2byte_double(size_t datasize, 
+				   unsigned char * restrict lGrib,
+				   const double * restrict data, 
+				   double zref, double factor, size_t *gz) 
 {
-  CGRIBEX_Debug = debug;
-
-  if ( CGRIBEX_Debug )
-    Message("debug level %d", debug);
-}
+  size_t i, j, residual;
+  const double *dval = data;
+  __m128i *sgrib = (__m128i *) (lGrib+(*gz));
 
+  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
 
-void gribFixZSE(int flag)
-{
-  CGRIBEX_Fix_ZSE = flag;
+  const __m256d c0 = _mm256_set1_pd(zref);
+  const __m256d c1 = _mm256_set1_pd(factor);
+  const __m256d c2 = _mm256_set1_pd(0.5);
+  
+  __m256d d0, d3, d2, d1;
+  __m128i i0, i1, i2, i3;
+  __m128i s0, s1;  
 
-  if ( CGRIBEX_Debug )
-    Message("Fix ZeroShiftError set to %d", flag);
-}
+  residual = datasize % 16;
 
+  for (i = 0; i < (datasize-residual); i += 16)
+    {
+      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
+      //_____________________________________________________________________________
 
-void gribSetConst(int flag)
-{
-  CGRIBEX_Const = flag;
+      d0 = _mm256_loadu_pd (dval);
+      d0 = _mm256_sub_pd (d0, c0);
+      d0 = _mm256_mul_pd (d0, c1);
+      d0 = _mm256_add_pd (d0, c2);
 
-  if ( CGRIBEX_Debug )
-    Message("Const set to %d", flag);
-}
+      i0 = _mm256_cvttpd_epi32 (d0);
+      
+      //_____________________________________________________________________________
+      
+      d1 = _mm256_loadu_pd (dval+4);
+      d1 = _mm256_sub_pd (d1, c0);
+      d1 = _mm256_mul_pd (d1, c1);
+      d1 = _mm256_add_pd (d1, c2);
+      
+      i1 = _mm256_cvttpd_epi32 (d1);
 
+      //_____________________________________________________________________________
 
-void gribSetRound(int round)
-{
-  UNUSED(round);
-}
+      s0 = _mm_packus_epi32(i0, i1);
+      s0 = _mm_shuffle_epi8 (s0, swap);
+      (void) _mm_storeu_si128 (sgrib, s0);
 
+      //_____________________________________________________________________________
 
-void gribSetRefDP(double refval)
-{
-  UNUSED(refval);
-}
+      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
 
+      //_____________________________________________________________________________
+      
+      d2 = _mm256_loadu_pd (dval+8);
+      d2 = _mm256_sub_pd (d2, c0);
+      d2 = _mm256_mul_pd (d2, c1);
+      d2 = _mm256_add_pd (d2, c2);
+      
+      i2 = _mm256_cvttpd_epi32 (d2);
 
-void gribSetRefSP(float refval)
-{
-  gribSetRefDP((double) refval);
-}
+      //_____________________________________________________________________________
+      
+      d3 = _mm256_loadu_pd (dval+12);
+      d3 = _mm256_sub_pd (d3, c0);
+      d3 = _mm256_mul_pd (d3, c1);
+      d3 = _mm256_add_pd (d3, c2);
+      
+      i3 = _mm256_cvttpd_epi32 (d3);
 
+      //_____________________________________________________________________________
 
-void gribSetValueCheck(int vcheck)
-{
-  UNUSED(vcheck);
+      s1 = _mm_packus_epi32(i2, i3);
+      s1 = _mm_shuffle_epi8 (s1, swap);
+      (void) _mm_storeu_si128 (sgrib+1, s1);
+
+      //_____________________________________________________________________________
+           
+      dval += 16;
+      sgrib += 2;
+    }
+
+  if (i != datasize)
+    {
+      uint16_t ui16;
+      for ( j = i; j < datasize; j++ )
+	{
+	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
+	  lGrib[*gz+2*j  ] = ui16 >>  8;
+	  lGrib[*gz+2*j+1] = ui16;
+	}
+    }
+  
+  *gz += 2*datasize;
+
+  return;
 }
-#include <string.h>
-#include <math.h>
 
+#define grib_encode_array_2byte_double avx_encode_array_2byte_double
 
+#elif defined _ENABLE_SSE4_1
 
-void gribPrintSec0(int *isec0)
+static
+void sse41_encode_array_2byte_double(size_t datasize, 
+				     unsigned char * restrict lGrib,
+				     const double * restrict data, 
+				     double zref, double factor, size_t *gz) 
 {
-  /*
+  size_t i, j, residual;
+  const double *dval = data;
+  __m128i *sgrib = (__m128i *) (lGrib+(*gz));
 
-    Print the information in the Indicator
-    Section (Section 0) of decoded GRIB data.
+  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
 
-    Input Parameters:
+  const __m128d c0 = _mm_set1_pd(zref);
+  const __m128d c1 = _mm_set1_pd(factor);
+  const __m128d c2 = _mm_set1_pd(0.5);
+  
+  __m128d d0, d4, d3, d2, d1;
+  __m128i i0, i1, i2, i3, i4;
+  __m128i s0, s1;  
 
-       isec0 - Array of decoded integers from Section 0
+  residual = datasize % 16;
+
+  for (i = 0; i < (datasize-residual); i += 16)
+    {
+      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
+      //_____________________________________________________________________________
 
+      d0 = _mm_loadu_pd (dval);
+      d0 = _mm_sub_pd (d0, c0);
+      d0 = _mm_mul_pd (d0, c1);
+      d0 = _mm_add_pd (d0, c2);
+      
+      d4 = _mm_loadu_pd (dval+2);
+      d4 = _mm_sub_pd (d4, c0);
+      d4 = _mm_mul_pd (d4, c1);
+      d4 = _mm_add_pd (d4, c2);
 
-    Converted from EMOS routine GRPRS0.
+      i0 = _mm_cvttpd_epi32 (d0);
+      i4 = _mm_cvttpd_epi32 (d4);  
+      i0 = _mm_unpacklo_epi64 (i0, i4);
 
-       Uwe Schulzweida   MPIfM   01/04/2001
+      //_____________________________________________________________________________
+      
+      d1 = _mm_loadu_pd (dval+4);
+      d1 = _mm_sub_pd (d1, c0);
+      d1 = _mm_mul_pd (d1, c1);
+      d1 = _mm_add_pd (d1, c2);
+      
+      d4 = _mm_loadu_pd (dval+6);
+      d4 = _mm_sub_pd (d4, c0);
+      d4 = _mm_mul_pd (d4, c1);
+      d4 = _mm_add_pd (d4, c2);
+      
+      i1 = _mm_cvttpd_epi32 (d1);
+      i4 = _mm_cvttpd_epi32 (d4);  
+      i1 = _mm_unpacklo_epi64 (i1, i4);
 
-  */
+      //_____________________________________________________________________________
 
-  grsdef();
+      s0 = _mm_packus_epi32(i0, i1);
+      s0 = _mm_shuffle_epi8 (s0, swap);
+      (void) _mm_storeu_si128 (sgrib, s0);
 
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 0 - Indicator Section.       \n");
-  fprintf(grprsm, " -------------------------------------\n");
-  fprintf(grprsm, " Length of GRIB message (octets).     %9d\n", ISEC0_GRIB_Len);
-  fprintf(grprsm, " GRIB Edition Number.                 %9d\n", ISEC0_GRIB_Version);
+      //_____________________________________________________________________________
+
+      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
+
+      //_____________________________________________________________________________
+      
+      d2 = _mm_loadu_pd (dval+8);
+      d2 = _mm_sub_pd (d2, c0);
+      d2 = _mm_mul_pd (d2, c1);
+      d2 = _mm_add_pd (d2, c2);
+      
+      d4 = _mm_loadu_pd (dval+10);
+      d4 = _mm_sub_pd (d4, c0);
+      d4 = _mm_mul_pd (d4, c1);
+      d4 = _mm_add_pd (d4, c2);
+      
+      i2 = _mm_cvttpd_epi32 (d2);
+      i4  = _mm_cvttpd_epi32 (d4);  
+      i2 = _mm_unpacklo_epi64 (i2, i4);
+
+      //_____________________________________________________________________________
+      
+      d3 = _mm_loadu_pd (dval+12);
+      d3 = _mm_sub_pd (d3, c0);
+      d3 = _mm_mul_pd (d3, c1);
+      d3 = _mm_add_pd (d3, c2);
+      
+      d4 = _mm_loadu_pd (dval+14);
+      d4 = _mm_sub_pd (d4, c0);
+      d4 = _mm_mul_pd (d4, c1);
+      d4 = _mm_add_pd (d4, c2);
+      
+      i3 = _mm_cvttpd_epi32 (d3);
+      i4 = _mm_cvttpd_epi32 (d4);  
+      i3 = _mm_unpacklo_epi64 (i3, i4);
+
+      //_____________________________________________________________________________
+
+      s1 = _mm_packus_epi32(i2, i3);
+      s1 = _mm_shuffle_epi8 (s1, swap);
+      (void) _mm_storeu_si128 (sgrib+1, s1);
+
+      //_____________________________________________________________________________
+           
+      dval += 16;
+      sgrib += 2;
+    }
+
+  if (i != datasize) 
+    {
+      uint16_t ui16;
+      for ( j = i; j < datasize; j++ )
+	{
+	  ui16 = (uint16_t) ((data[j] - zref) * factor + 0.5);
+	  lGrib[*gz+2*j  ] = ui16 >>  8;
+	  lGrib[*gz+2*j+1] = ui16;
+	}
+    }
+
+  *gz += 2*datasize;
+  
+  return;
 }
 
-void gribPrintSec1(int *isec0, int *isec1)
-{
-  /*
+#define grib_encode_array_2byte_double sse41_encode_array_2byte_double
 
-    Print the information in the Product Definition
-    Section (Section 1) of decoded GRIB data.
+#else
 
-    Input Parameters:
+#define grib_encode_array_2byte_double encode_array_2byte_double
 
-       isec0 - Array of decoded integers from Section 0
+#endif // SIMD variants
 
-       isec1 - Array of decoded integers from Section 1
 
-    Comments:
+#ifdef TEST_ENCODE
 
-       When decoding data from Experimental Edition or Edition 0,
-       routine GRIBEX adds the additional fields available in
-       Edition 1.
+#define CAT(X,Y)      X##_##Y
+#define TEMPLATE(X,Y) CAT(X,Y)
 
+#ifdef T
+#undef T
+#endif
+#define T double
 
-    Converted from EMOS routine GRPRS1.
+#ifdef T
+#undef T
+#endif
+#define T float
 
-       Uwe Schulzweida   MPIfM   01/04/2001
 
-  */
+#include <sys/time.h>
 
-  int iprev, icurr, ioffset;
-  int ibit, ierr, iout, iyear;
-  int jloop, jiloop;
-  float value;
+static
+double dtime()
+{
+  double tseconds = 0.0;
+  struct timeval mytime;
+  gettimeofday(&mytime, NULL);
+  tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
+  return (tseconds);
+}
 
-  char hversion[9];
-  /*
-  char hfirst[121], hsecond[121], hthird[121], hfourth[121];
-  */
+#define NRUN 10000
 
-  grsdef();
+static
+void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
+{
+  printf("%8s: val1: %d  val2: %d  val3: %d  valn: %d  time: %gs\n",
+         name, (int) lgrib[s*1+1], (int) lgrib[s*2+1], (int) lgrib[s*3+1], (int) lgrib[2*datasize-1], tt);
+}
 
-  /*
-    -----------------------------------------------------------------
-    Section 0 . Print required information.
-    -----------------------------------------------------------------
-  */
+int main(void)
+{
+  long datasize = 1000000;
+  double t_begin, t_end;
 
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 1 - Product Definition Section.\n");
-  fprintf(grprsm, " ---------------------------------------\n");
+  float *dataf = (float*) malloc(datasize*sizeof(float));
+  double *data = (double*) malloc(datasize*sizeof(double));
+  unsigned char *lgrib = (unsigned char*) malloc(2*datasize*sizeof(unsigned char));
 
-  fprintf(grprsm, " Code Table 2 Version Number.         %9d\n", isec1[0]);
-  fprintf(grprsm, " Originating centre identifier.       %9d\n", isec1[1]);
-  fprintf(grprsm, " Model identification.                %9d\n", isec1[2]);
-  fprintf(grprsm, " Grid definition.                     %9d\n", isec1[3]);
+  for ( long i = 0; i < datasize; ++i ) dataf[i] = (float) (-datasize/2 + i);
+  for ( long i = 0; i < datasize; ++i ) data[i] = (double) (-datasize/2 + i);
 
-  ibit = 8;
-  prtbin(isec1[4], ibit, &iout, &ierr);
-  fprintf(grprsm, " Flag (Code Table 1)                   %8.8d\n", iout);
-  fprintf(grprsm, " Parameter identifier (Code Table 2). %9d\n", isec1[5]);
+  int PackStart = 0;
+  int nbpv = 16;
+  double zref = data[0];
+  size_t z;
+  double factor = 0.00390625;
+  int s = 256;
 
-  /*
-      IERR = CHKTAB2(ISEC1,HFIRST,HSECOND,HTHIRD,HFOURTH)
-      IF( IERR .EQ. 0 ) THEN
-       DO JLOOP = 121, 1, -1
-          IF( HSECOND(JLOOP:JLOOP).NE.' ' ) THEN
-            IOFFSET = JLOOP
-            GOTO 110
-          ENDIF
-        ENDDO
-        GOTO 120
- 110    CONTINUE
-        WRITE(*,'(2H ",A,1H")') HSECOND(1:IOFFSET)
- 120    CONTINUE
-      ENDIF
-  */
+  if ( 0 )
+    {
+      encode_array_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
+      encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
+    }
 
-  if ( isec1[5] != 127 )
+#if   defined(__ICC)
+  printf("icc\n");
+#elif defined(__clang__)
+  printf("clang\n");
+#elif defined(__GNUC__)
+  printf("gcc\n");
+#endif
+
+  printf("float:\n");
+
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
     {
-      fprintf(grprsm, " Type of level (Code Table 3).        %9d\n", isec1[6]);
-      fprintf(grprsm, " Value 1 of level (Code Table 3).     %9d\n", isec1[7]);
-      fprintf(grprsm, " Value 2 of level (Code Table 3).     %9d\n", isec1[8]);
+      z = 0;
+      encode_array_2byte_float(datasize, lgrib, dataf, (float)zref, (float)factor, &z);
     }
-  else
+  t_end = dtime();
+  pout("orig", s, lgrib, datasize, t_end-t_begin);
+
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
     {
-      fprintf(grprsm, " Satellite identifier.                %9d\n", isec1[6]);
-      fprintf(grprsm, " Spectral band.                       %9d\n", isec1[7]);
+      z = 0;
+      encode_array_unrolled_float(nbpv, PackStart, datasize, lgrib, dataf, (float)zref, (float)factor, &z);
     }
+  t_end = dtime();
+  pout("unrolled", s, lgrib, datasize, t_end-t_begin);
 
-  iyear = isec1[9];
-  if ( iyear != 255 )
+  printf("double:\n");
+
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
     {
-      int date, time;
-      /* iyear  = ((isec1[20]-1)*100 + isec1[9]); */
-      gribDateTime(isec1, &date, &time);
-      iyear = date/10000;
-      fprintf(grprsm, " Year of reference time of data.      %9d  (%4d)\n", isec1[9], iyear);
+      z = 0;
+      encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
     }
-  else
+  t_end = dtime();
+  pout("orig", s, lgrib, datasize, t_end-t_begin);
+
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
     {
-      fprintf(grprsm, " Year of reference time of data MISSING  (=255)\n");
+      z = 0;
+      encode_array_unrolled_double(nbpv, PackStart, datasize, lgrib, data, zref, factor, &z);
     }
+  t_end = dtime();
+  pout("unrolled", s, lgrib, datasize, t_end-t_begin);
 
-  fprintf(grprsm, " Month of reference time of data.     %9d\n", isec1[10]);
-  fprintf(grprsm, " Day of reference time of data.       %9d\n", isec1[11]);
-  fprintf(grprsm, " Hour of reference time of data.      %9d\n", isec1[12]);
-  fprintf(grprsm, " Minute of reference time of data.    %9d\n", isec1[13]);
-  fprintf(grprsm, " Time unit (Code Table 4).            %9d\n", isec1[14]);
-  fprintf(grprsm, " Time range one.                      %9d\n", isec1[15]);
-  fprintf(grprsm, " Time range two.                      %9d\n", isec1[16]);
-  fprintf(grprsm, " Time range indicator (Code Table 5)  %9d\n", isec1[17]);
-  fprintf(grprsm, " Number averaged.                     %9d\n", isec1[18]);
-  fprintf(grprsm, " Number missing from average.         %9d\n", isec1[19]);
-  /*
-     All ECMWF data in GRIB Editions before Edition 1 is decoded
-     as 20th century data. Other centres are decoded as missing.
-  */
-  if ( isec0[1] < 1 && isec1[1] != 98 )
-    fprintf(grprsm, " Century of reference time of data.   Not given\n");
-  else
-    fprintf(grprsm, " Century of reference time of data.   %9d\n", isec1[20]);
+#if defined _ENABLE_AVX
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
+    {
+      z = 0;
+      avx_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
+    }
+  t_end = dtime();
+  pout("avx", s, lgrib, datasize, t_end-t_begin);
+#elif defined _ENABLE_SSE4_1
+  t_begin = dtime();
+  for ( int i = 0; i < NRUN; ++i )
+    {
+      z = 0;
+      sse41_encode_array_2byte_double(datasize, lgrib, data, zref, factor, &z);
+    }
+  t_end = dtime();
+  pout("sse41", s, lgrib, datasize, t_end-t_begin);
+#endif
 
-  /*   Print sub-centre  */
-  fprintf(grprsm, " Sub-centre identifier.               %9d\n", ISEC1_SubCenterID);
+  return 0;
+}
+#endif // TEST_ENCODE
 
-  /*   Decimal scale factor  */
-  fprintf(grprsm, " Units decimal scaling factor.        %9d\n", isec1[22]);
+#undef DISABLE_SIMD_ENCODE
+#undef _ENABLE_AVX
+#undef _ENABLE_SSE4_1
 
+
+void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
+{
   /*
-    -----------------------------------------------------------------
-    Section 1 . Print local DWD information.
-    -----------------------------------------------------------------
-  */
-  if ( (ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250) &&
-       (isec1[36] == 253     || isec1[36] == 254) )
-    {
-      fprintf(grprsm, " DWD local usage identifier.          %9d\n", isec1[36]);
-      if ( isec1[36] == 253 )
-	fprintf(grprsm, " (Database labelling and ensemble forecast)\n");
-      if ( isec1[36] == 254 )
-	fprintf(grprsm, " (Database labelling)\n");
 
-      fprintf(grprsm, " Year of database entry                     %3d  (%4d)\n", isec1[43], 1900+isec1[43]);
-      fprintf(grprsm, " Month of database entry                    %3d\n", isec1[44]);
-      fprintf(grprsm, " Day of database entry                      %3d\n", isec1[45]);
-      fprintf(grprsm, " Hour of database entry                     %3d\n", isec1[46]);
-      fprintf(grprsm, " Minute of database entry                   %3d\n", isec1[47]);
-      fprintf(grprsm, " DWD experiment number                %9d\n",isec1[48]);
-      fprintf(grprsm, " DWD run type                         %9d\n",isec1[49]);
-      if ( isec1[36] == 253 ) 
-	{
-	  fprintf(grprsm, " User id                              %9d\n",isec1[50]);
-	  fprintf(grprsm, " Experiment identifier                %9d\n",isec1[51]);
-	  fprintf(grprsm, " Ensemble identification type         %9d\n",isec1[52]);
-	  fprintf(grprsm, " Number of ensemble members           %9d\n",isec1[53]);
-	  fprintf(grprsm, " Actual number of ensemble member     %9d\n",isec1[54]);
-	  fprintf(grprsm, " Model version                            %2d.%2.2d\n",isec1[55],isec1[56]);
-	}
-    }
+    Purpose:
+    --------
 
-  /*
-    -----------------------------------------------------------------
-    Section 2 . Print local ECMWF information.
-    -----------------------------------------------------------------
-  */
-  /*
-    Regular MARS labelling, or reformatted Washington EPS products.
-  */
-  if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
-       (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
-       (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
-    {
-      /*   Parameters common to all definitions.  */
+    Convert floating point number from machine
+    representation to GRIB representation.
 
-      fprintf(grprsm, " ECMWF local usage identifier.        %9d\n", isec1[36]);
-      if ( isec1[36] == 1 )
-	fprintf(grprsm, " (Mars labelling or ensemble forecast)\n");
-      if ( isec1[36] == 2 )
-        fprintf(grprsm, " (Cluster means and standard deviations)\n");
-      if ( isec1[36] == 3 )
-        fprintf(grprsm, " (Satellite image data)\n");
-      if ( isec1[36] == 4 )
-        fprintf(grprsm, " (Ocean model data)\n");
-      if ( isec1[36] == 5 )
-        fprintf(grprsm, " (Forecast probability data)\n");
-      if ( isec1[36] == 6 )
-        fprintf(grprsm, " (Surface temperature data)\n");
-      if ( isec1[36] == 7 )
-        fprintf(grprsm, " (Sensitivity data)\n");
-      if ( isec1[36] == 8 )
-        fprintf(grprsm, " (ECMWF re-analysis data)\n");
-      if ( isec1[36] == 9 )
-        fprintf(grprsm, " (Singular vectors and ensemble perturbations)\n");
-      if ( isec1[36] == 10 )
-        fprintf(grprsm, " (EPS tubes)\n");
-      if ( isec1[36] == 11 )
-        fprintf(grprsm, " (Supplementary data used by analysis)\n");
-      if ( isec1[36] == 13 )
-        fprintf(grprsm, " (Wave 2D spectra direction and frequency)\n");
+    Input Parameters:
+    -----------------
 
-      fprintf(grprsm, " Class.                               %9d\n", isec1[37]);
-      fprintf(grprsm, " Type.                                %9d\n", isec1[38]);
-      fprintf(grprsm, " Stream.                              %9d\n", isec1[39]);
-      sprintf(hversion, "%4s", (char*)&isec1[40]); hversion[4] = 0;
-      fprintf(grprsm, " Version number or Experiment identifier.  %4s\n", hversion);
-      /*
-	ECMWF Local definition 1.
-	(MARS labelling or ensemble forecast data)
-      */
-      if ( isec1[36] == 1 )
-	{
-	  fprintf(grprsm, " Forecast number.                     %9d\n", isec1[41]);
-	  if ( isec1[39] != 1090 )
-	    fprintf(grprsm, " Total number of forecasts.           %9d\n", isec1[42]);
+       pval    - Floating point number to be converted.
+       kbits   - Number of bits in computer word.
+       kround  - Conversion type.
+                 0 , Closest number in GRIB format less than
+                     original number.
+                 1 , Closest number in GRIB format to the
+                     original number (equal to, greater than or
+                     less than original number).
 
-	  return;
-	}
-      /*
-	ECMWF Local definition 2.
-	(Cluster means and standard deviations)
-      */
-      if ( isec1[36] == 2 )
-	{
-	  fprintf(grprsm, " Cluster number.                      %9d\n", isec1[41]);
-	  fprintf(grprsm, " Total number of clusters.            %9d\n", isec1[42]);
-	  fprintf(grprsm, " Clustering method.                   %9d\n", isec1[43]);
-	  fprintf(grprsm, " Start time step when clustering.     %9d\n", isec1[44]);
-	  fprintf(grprsm, " End time step when clustering.       %9d\n", isec1[45]);
-	  fprintf(grprsm, " Northern latitude of domain.         %9d\n", isec1[46]);
-	  fprintf(grprsm, " Western longitude of domain.         %9d\n", isec1[47]);
-	  fprintf(grprsm, " Southern latitude of domain.         %9d\n", isec1[48]);
-	  fprintf(grprsm, " Eastern longitude of domain.         %9d\n", isec1[49]);
-	  fprintf(grprsm, " Operational forecast in cluster      %9d\n", isec1[50]);
-	  fprintf(grprsm, " Control forecast in cluster          %9d\n", isec1[51]);
-	  fprintf(grprsm, " Number of forecasts in cluster.      %9d\n", isec1[52]);
+    Output Parameters:
+    ------------------
 
-	  for (jloop = 0; jloop < isec1[52]; jloop++)
-	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[jloop+53]);
+       kexp    - 8 Bit signed exponent.
+       kmant   - 24 Bit mantissa.
 
-	  return;
-	}
-      /*
-	ECMWF Local definition 3.
-	(Satellite image data)
-      */
-      if ( isec1[36] == 3 )
-	{
-	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
-	  fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
-	  return;
-	}
-      /*
-	ECMWF Local definition 4.
-	(Ocean model data)
-      */
-      if ( isec1[36] == 4 )
-	{
-	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
-	  if ( isec1[39] != 1090 )
-	    fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
-	  fprintf(grprsm, " Coordinate structure definition.\n");
-	  fprintf(grprsm, " Fundamental spatial reference system.%9d\n", isec1[43]);
-	  fprintf(grprsm, " Fundamental time reference.          %9d\n", isec1[44]);
-	  fprintf(grprsm, " Space unit flag.                     %9d\n", isec1[45]);
-	  fprintf(grprsm, " Vertical coordinate definition.      %9d\n", isec1[46]);
-	  fprintf(grprsm, " Horizontal coordinate definition.    %9d\n", isec1[47]);
-	  fprintf(grprsm, " Time unit flag.                      %9d\n", isec1[48]);
-	  fprintf(grprsm, " Time coordinate definition.          %9d\n", isec1[49]);
-	  fprintf(grprsm, " Position definition.     \n");
-	  fprintf(grprsm, " Mixed coordinate field flag.         %9d\n", isec1[50]);
-	  fprintf(grprsm, " Coordinate 1 flag.                   %9d\n", isec1[51]);
-	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[52]);
-	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[53]);
-	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[54]);
-	  fprintf(grprsm, " Coordinate 2 flag.                   %9d\n", isec1[55]);
-	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[56]);
-	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[57]);
-	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[58]);
-	  fprintf(grprsm, " Grid Definition.\n");
-	  fprintf(grprsm, " Coordinate 3 flag (x-axis)           %9d\n", isec1[59]);
-	  fprintf(grprsm, " Coordinate 4 flag (y-axis)           %9d\n", isec1[60]);
-	  fprintf(grprsm, " Coordinate 4 of first grid point.    %9d\n", isec1[61]);
-	  fprintf(grprsm, " Coordinate 3 of first grid point.    %9d\n", isec1[62]);
-	  fprintf(grprsm, " Coordinate 4 of last grid point.     %9d\n", isec1[63]);
-	  fprintf(grprsm, " Coordinate 3 of last grid point.     %9d\n", isec1[64]);
-	  fprintf(grprsm, " i - increment.                       %9d\n", isec1[65]);
-	  fprintf(grprsm, " j - increment.                       %9d\n", isec1[66]);
-	  fprintf(grprsm, " Flag for irregular grid coordinates. %9d\n", isec1[67]);
-	  fprintf(grprsm, " Flag for normal or staggered grids.  %9d\n", isec1[68]);
-	  fprintf(grprsm, " Further information.\n");
-	  fprintf(grprsm, " Further information flag.            %9d\n", isec1[69]);
-	  fprintf(grprsm, " Auxiliary information.\n");
-	  fprintf(grprsm, " No. entries in horizontal coordinate %9d\n", isec1[70]);
-	  fprintf(grprsm, " No. entries in mixed coordinate defn.%9d\n", isec1[71]);
-	  fprintf(grprsm, " No. entries in grid coordinate list. %9d\n", isec1[72]);
-	  fprintf(grprsm, " No. entries in auxiliary array.      %9d\n", isec1[73]);
-	  /*
-	    Horizontal coordinate supplement.
-	  */
-	  fprintf(grprsm, " Horizontal coordinate supplement.\n");
-	  if ( isec1[70] == 0 )
-	    {
-	      fprintf(grprsm, "(None).\n");
-	    }
-	  else
-	    {
-	      fprintf(grprsm, "Number of items = %d\n", isec1[70]);
-	      for (jloop = 0; jloop < isec1[70]; jloop++)
-		fprintf(grprsm, "         %12d\n", isec1[74+jloop]);
-	    }
-	  /*
-	    Mixed coordinate definition.
-	  */
-	  fprintf(grprsm, " Mixed coordinate definition.\n");
-	  if ( isec1[71] == 0 )
-	    {
-	      fprintf(grprsm, "(None).\n");
-	    }
-	  else
-	    {
-	      fprintf(grprsm, "Number of items = %d\n", isec1[71]);
-	      ioffset = 74 + isec1[70];
-	      for (jloop = 0; jloop < isec1[71]; jloop++)
-		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
-	    }
-	  /*
-	    Grid coordinate list.
-	  */
-	  fprintf(grprsm, " Grid coordinate list. \n");
-	  if ( isec1[72] == 0 )
-	    {
-	      fprintf(grprsm, "(None).\n");
-	    }
-	  else
-	    {
-	      fprintf(grprsm, "Number of items = %d\n", isec1[72]);
-	      ioffset = 74 + isec1[70] + isec1[71];
-	      for (jloop = 0; jloop < isec1[72]; jloop++)
-		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
-	    }
-	  /*
-	    Auxiliary array.
-	  */
-	  fprintf(grprsm, " Auxiliary array.      \n");
-	  if ( isec1[73] == 0 )
-	    {
-	      fprintf(grprsm, "(None).\n");
-	    }
-	  else
-	    {
-	      fprintf(grprsm, "Number of items = %d\n", isec1[73]);
-	      ioffset = 74 + isec1[70] + isec1[71] + isec1[72];
-	      for (jloop = 0; jloop < isec1[73]; jloop++)
-		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
-	    }
-	  /*
-	    Post-auxiliary array.
-	  */
-	  fprintf(grprsm, " Post-auxiliary array. \n");
-	  ioffset = 74 + isec1[70] + isec1[71] + isec1[72] + isec1[73];
-	  if ( isec1[ioffset] == 0 )
-	    {
-	      fprintf(grprsm, "(None).\n");
-	    }
-	  else
-	    {
-	      fprintf(grprsm, "Number of items = %d\n", isec1[ioffset]);
-	      for (jloop = 1; jloop < isec1[ioffset]; jloop++)
-		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
-	    }
-
-	  return;
-	}
-      /*
-	ECMWF Local definition 5.
-	(Forecast probability data)
-      */
-      if ( isec1[36] == 5 )
-	{
-	  fprintf(grprsm, " Forecast probability number          %9d\n", isec1[41]);
-	  fprintf(grprsm, " Total number of forecast probabilities %7d\n", isec1[42]);
-	  fprintf(grprsm, " Threshold units decimal scale factor %9d\n", isec1[43]);
-	  fprintf(grprsm, " Threshold indicator(1=lower,2=upper,3=both) %2d\n", isec1[44]);
-	  if ( isec1[44]  !=  2 )
-	    fprintf(grprsm, " Lower threshold value                %9d\n", isec1[45]);
-	  if ( isec1[44]  !=  1 )
-	    fprintf(grprsm, " Upper threshold value                %9d\n", isec1[46]);
-	  return;
-	}
-      /*
-	ECMWF Local definition 6.
-	(Surface temperature data)
-      */
-      if ( isec1[36] == 6 )
-	{
-	  iyear = isec1[43];
-	  if ( iyear > 100 )
-	    {
-	      if ( iyear < 19000000 ) iyear = iyear + 19000000;
-	      fprintf(grprsm, " Date of SST field used               %9d\n", iyear);
-	    }
-	  else
-	    fprintf(grprsm, "Date of SST field used               Not given\n");
-	}
-      if ( isec1[44] == 0 )
-	fprintf(grprsm, " Type of SST field (= climatology)    %9d\n", isec1[44]);
-      if ( isec1[44] == 1 )
-	fprintf(grprsm, " Type of SST field (= 1/1 degree)     %9d\n", isec1[44]);
-      if ( isec1[44] == 2 )
-	fprintf(grprsm, " Type of SST field (= 2/2 degree)     %9d\n", isec1[44]);
-
-      fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
-
-      for (jloop = 1; jloop <= isec1[45]; jloop++)
-	{
-	  iyear = isec1[44+(jloop*2)];
-	  if ( iyear > 100 )
-	    {
-              if ( iyear < 19000000 ) iyear = iyear + 19000000;
-	      fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop, iyear);
-	      fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
-		     isec1[45+(jloop*2)]);
-	    }
-	  else
-	    fprintf(grprsm, "Date of SST field used               Not given\n");
-	}
-      /*
-	ECMWF Local definition 7.
-	(Sensitivity data)
-      */
-      if ( isec1[36] == 7 )
-	{
-	  if ( isec1[38]  ==  51 )
-	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[41]);
-	  if ( isec1[38]  !=  51 )
-	    fprintf(grprsm, " Iteration number                     %9d\n", isec1[41]);
-	  if ( isec1[38]  !=  52 )
-	    fprintf(grprsm, " Total number of diagnostics          %9d\n", isec1[42]);
-	  if ( isec1[38]  ==  52 )
-	    fprintf(grprsm, " No.interations in diag. minimisation %9d\n", isec1[42]);
-	  fprintf(grprsm, " Domain(0=Global,1=Europe,2=N.Hem.,3=S.Hem.) %2d\n", isec1[43]);
-	  fprintf(grprsm, " Diagnostic number                    %9d\n", isec1[44]);
-	}
-      /*
-	ECMWF Local definition 8.
-	(ECMWF re-analysis data)
-      */
-      if ( isec1[36] == 8 )
-	{
-	  if ( (isec1[39] == 1043) ||
-	       (isec1[39] == 1070) ||
-	       (isec1[39] == 1071) )
-	    {
-	      fprintf(grprsm, " Interval between reference times     %9d\n", isec1[41]);
-	      for (jloop = 43; jloop <= 54; jloop++)
-		{
-		  jiloop = jloop + 8;
-		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
-			 jiloop, isec1[jloop-1]);
-		}
-	    }
-	  else
-	    {
-	      for (jloop = 42; jloop <= 54; jloop++)
-		{
-		  jiloop = jloop + 8;
-		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
-			 jiloop, isec1[jloop-1]);
-		}
-	    }
-	  return;
-	}
-
-      if ( isec1[38] > 4  && isec1[38] < 9 )
-	{
-	  fprintf(grprsm, " Simulation number.                   %9d\n", isec1[41]);
-	  fprintf(grprsm, " Total number of simulations.         %9d\n", isec1[42]);
-	}
-      /*
-	ECMWF Local definition 9.
-	(Singular vectors and ensemble perturbations)
-      */
-      if ( isec1[36] == 9 )
-	{
-	  if ( isec1[38] == 60 )
-	    fprintf(grprsm, " Perturbed ensemble forecast number   %9d\n", isec1[41]);
-	  if ( isec1[38] == 61 )
-	    fprintf(grprsm, " Initial state perturbation number    %9d\n", isec1[41]);
-	  if ( isec1[38] == 62 )
-	    fprintf(grprsm, " Singular vector number               %9d\n", isec1[41]);
-	  if ( isec1[38] == 62 )
-	    {
-	      fprintf(grprsm, " Number of iterations                 %9d\n", isec1[42]);
-	      fprintf(grprsm, " Number of singular vectors computed  %9d\n", isec1[43]);
-	      fprintf(grprsm, " Norm used at initial time            %9d\n", isec1[44]);
-	      fprintf(grprsm, " Norm used at final time              %9d\n", isec1[45]);
-	      fprintf(grprsm, " Multiplication factor                %9d\n", isec1[46]);
-    	      fprintf(grprsm, " Latitude of north-west corner        %9d\n", isec1[47]);
-    	      fprintf(grprsm, " Longitude of north-west corner       %9d\n", isec1[48]);
-	      fprintf(grprsm, " Latitude of south-east corner        %9d\n", isec1[49]);
-	      fprintf(grprsm, " Longitude of south-east corner       %9d\n", isec1[50]);
-	      fprintf(grprsm, " Accuracy                             %9d\n", isec1[51]);
-	      fprintf(grprsm, " Number of singular vectors evolved   %9d\n", isec1[52]);
-	      fprintf(grprsm, " Ritz number one                      %9d\n", isec1[53]);
-	      fprintf(grprsm, " Ritz number two                      %9d\n", isec1[54]);
-	    }
-	}
-      /*
-	ECMWF Local definition 10.
-	(EPS tubes)
-      */
-      if ( isec1[36] == 10 )
-	{
-	  fprintf(grprsm, " Tube number                          %9d\n", isec1[41]);
-          fprintf(grprsm, " Total number of tubes                %9d\n", isec1[42]);
-          fprintf(grprsm, " Central cluster definition           %9d\n", isec1[43]);
-          fprintf(grprsm, " Parameter                            %9d\n", isec1[44]);
-          fprintf(grprsm, " Type of level                        %9d\n", isec1[45]);
-          fprintf(grprsm, " Northern latitude of domain of tubing%9d\n", isec1[46]);
-          fprintf(grprsm, " Western longitude of domain of tubing%9d\n", isec1[47]);
-          fprintf(grprsm, " Southern latitude of domain of tubing%9d\n", isec1[48]);
-          fprintf(grprsm, " Eastern longitude of domain of tubing%9d\n", isec1[49]);
-          fprintf(grprsm, " Tube number of operational forecast  %9d\n", isec1[50]);
-          fprintf(grprsm, " Tube number of control forecast      %9d\n", isec1[51]);
-          fprintf(grprsm, " Height/pressure of level             %9d\n", isec1[52]);
-          fprintf(grprsm, " Reference step                       %9d\n", isec1[53]);
-          fprintf(grprsm, " Radius of central cluster            %9d\n", isec1[54]);
-          fprintf(grprsm, " Ensemble standard deviation          %9d\n", isec1[55]);
-          fprintf(grprsm, " Dist.of tube extreme to ensemble mean%9d\n", isec1[56]);
-          fprintf(grprsm, " Number of forecasts in the tube      %9d\n", isec1[57]);
-
-          fprintf(grprsm, " List of ensemble forecast numbers:\n");
-          for (jloop = 1; jloop <=  isec1[57]; jloop++)
-	    fprintf(grprsm, "    %9d\n", isec1[57+jloop]);
-	}
-      /*
-	ECMWF Local definition 11.
-	(Supplementary data used by the analysis)
-      */
-      if ( isec1[36] == 11 )
-	{
-	  fprintf(grprsm, " Details of analysis which used the supplementary data:\n");
-	  fprintf(grprsm, "   Class                              %9d\n", isec1[41]);
-	  fprintf(grprsm, "   Type                               %9d\n", isec1[42]);
-	  fprintf(grprsm, "   Stream                             %9d\n", isec1[43]);
-	  /*
-	  sprintf(hversion, "%8d", isec1[44]);
-	  fprintf(grprsm, "   Version number/experiment identifier:   %4s\n", &hversion[4]);
-	  */
-	  iyear = isec1[45];
-	  if ( iyear > 50 )
-	    iyear = iyear + 1900;
-	  else
-	    iyear = iyear + 2000;
-
-	  fprintf(grprsm, "   Year                               %9d\n", iyear);
-	  fprintf(grprsm, "   Month                              %9d\n", isec1[46]);
-	  fprintf(grprsm, "   Day                                %9d\n", isec1[47]);
-	  fprintf(grprsm, "   Hour                               %9d\n", isec1[48]);
-	  fprintf(grprsm, "   Minute                             %9d\n", isec1[49]);
-	  fprintf(grprsm, "   Century                            %9d\n", isec1[50]);
-	  fprintf(grprsm, "   Originating centre                 %9d\n", isec1[51]);
-	  fprintf(grprsm, "   Sub-centre                         %9d\n", isec1[52]);
-	}
-      /*
-	ECMWF Local definition 12.
-      */
-      if ( isec1[36] == 12 )
-	{
-	  fprintf(grprsm, " (Mean, average, etc)\n");
-          fprintf(grprsm, " Start date of the period              %8d\n", isec1[41]);
-          fprintf(grprsm, " Start time of the period                  %4.4d\n", isec1[42]);
-          fprintf(grprsm, " Finish date of the period             %8d\n", isec1[43]);
-          fprintf(grprsm, " Finish time of the period                 %4.4d\n", isec1[44]);
-          fprintf(grprsm, " Verifying date of the period          %8d\n", isec1[45]);
-          fprintf(grprsm, " Verifying time of the period              %4.4d\n", isec1[46]);
-          fprintf(grprsm, " Code showing method                   %8d\n", isec1[47]);
-          fprintf(grprsm, " Number of different time intervals used  %5d\n", isec1[48]);
-          fprintf(grprsm, " List of different time intervals used:\n");
-          iprev  = isec1[49];
-          unsigned icount = 0;
-          for (jloop = 1; jloop <= isec1[48]; jloop++)
-	    {
-	      icurr = isec1[48+jloop];
-	      if ( icurr != iprev )
-		{
-		  if ( icount == 1 )
-		    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
-		  if ( icount == 2 )
-		    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
-		  if ( icount > 2 )
-		    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
-		  iprev  = icurr;
-		  icount = 1;
-		}
-	      else
-		icount = icount + 1;
-	    }
-	  if ( icount == 1 )
-	    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
-	  if ( icount == 2 )
-	    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
-	  if ( icount > 2 )
-	    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
-	}
-      /*
-	ECMWF Local definition 13.
-	(Wave 2D spectra direction and frequency)
-      */
-      if ( isec1[36] == 13 )
-	{
-          fprintf(grprsm, " Direction number                     %9d\n", isec1[43]);
-	  fprintf(grprsm, " Frequency number                     %9d\n", isec1[44]);
-	  fprintf(grprsm, " Total number of directions           %9d\n", isec1[45]);
-	  fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[46]);
-	  fprintf(grprsm, " Scale factor applied to directions   %9d\n", isec1[47]);
-	  fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[48]);
-	  fprintf(grprsm, " List of directions:\n");
-          for (jloop = 1; jloop <= isec1[45]; jloop++)
-            {
-	      value = (float)(isec1[48+jloop])/(float)(isec1[47]);
-	      if ( isec1[43] == jloop )
-		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
-	      else
-		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
-            }
-	  fprintf(grprsm, " List of frequencies:\n");
-          for (jloop = 1; jloop <= isec1[46]; jloop++)
-	    {
-	      value = (float)(isec1[48+isec1[45]+jloop])/(float)(isec1[48]);
-	      if ( isec1[44] == jloop )
-		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
-	      else
-		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
-
-	      if ( isec1[49+isec1[45]+isec1[46]] != 0 )
-		{
-		  fprintf(grprsm, " System number (65535 = missing)      %9d\n",
-			 isec1[49+isec1[45]+isec1[46]]);
-		  fprintf(grprsm, " Method number (65535 = missing)      %9d\n",
-			 isec1[50+isec1[45]+isec1[46]]);
-		}
-	    }
-	  /*
-	    ECMWF Local definition 14.
-	    (Brightness temperature)
-	  */
-	  if ( isec1[36] == 14 )
-	    {
-	      fprintf(grprsm, " Channel number                       %9d\n", isec1[43]);
-	      fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[44]);
-	      fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[45]);
-	      fprintf(grprsm, " List of frequencies:\n");
-              for (jloop = 1; jloop <= isec1[45]; jloop++)
-		{
-		  value = (float)(isec1[45+jloop])/(float)(isec1[44]);
-		  if ( isec1[43] == jloop )
-		    fprintf(grprsm, " %3d:%15.9f   <-- this channel\n", jloop, value);
-		  else
-		    fprintf(grprsm, " %3d:%15.9f\n", jloop, value);
-		}
-	    }
-	  /*
-	    ECMWF Local definition 15.
-	    (Ocean ensemble seasonal forecast)
-	  */
-	  if ( isec1[36] == 15 )
-	    {
-	      fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
-	      fprintf(grprsm, " System number                        %9d\n", isec1[42]);
-	      fprintf(grprsm, " Method number                        %9d\n", isec1[43]);
-	    }
-	  /*
-	    ECMWF Local definition 16.
-	    (Seasonal forecast monthly mean atmosphere data)
-	  */
-        if ( isec1[36] == 16 )
-	  {
-	    fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
-	    fprintf(grprsm, " System number                        %9d\n", isec1[43]);
-	    fprintf(grprsm, " Method number                        %9d\n", isec1[44]);
-	    fprintf(grprsm, " Verifying month                      %9d\n", isec1[45]);
-	    fprintf(grprsm, " Averaging period                     %9d\n", isec1[46]);
-	  }
-	/*
-	  ECMWF Local definition 17.
-	  (Sst or sea-ice used by analysis)
-	*/
-        if ( isec1[36] == 17 )
-	  {
-	    iyear = isec1[43];
-	    if ( iyear > 100 )
-	      {
-		if ( iyear < 19000000 ) iyear = iyear + 19000000;
-		fprintf(grprsm, " Date of sst/ice field used           %9d\n", iyear);
-	      }
-	    else
-              fprintf(grprsm, " Date of sst/ice field used           Not given\n");
-      
-	    if ( isec1[44] == 0 )
-	      fprintf(grprsm, " Type of sst/ice field (= climatology)%9d\n", isec1[44]);
-	    if ( isec1[44] == 1 )
-	      fprintf(grprsm, " Type of sst/ice field (= 1/1 degree) %9d\n", isec1[44]);
-	    if ( isec1[44] == 2 )
-	      fprintf(grprsm, " Type of sst/ice field (= 2/2 degree) %9d\n", isec1[44]);
-
-	    fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
-
-	    for (jloop = 1; jloop < isec1[45]; jloop++)
-	      {
-		iyear = isec1[44+(jloop*2)];
-		if ( iyear > 100 )
-		  {
-		    if ( iyear < 19000000 ) iyear = iyear + 19000000;
-		    fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop,
-			   iyear);
-		    fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
-			   isec1[45+(jloop*2)]);
-		  }
-		else
-		  fprintf(grprsm, "Date of sst/ice field used           Not given\n");
-	      } 
-	  }
-	}
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 3 . Print Washington ensemble product information.
-    -----------------------------------------------------------------
-  */
-  /*
-    Washington EPS products (but not reformatted Washington EPS
-    products.
-  */
-  if ( (isec1[1] == 7 && isec1[23] == 1) && (! (ISEC1_SubCenterID == 98)) )
-    {
-      /*   CALL KWPRS1 (iSEC0,iSEC1)*/
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 4 . Print local MPIM information.
-    -----------------------------------------------------------------
-  */
-  if (isec1[ 1] == 252 && isec1[36] == 1)
-    {
-      fprintf(grprsm, " MPIM local usage identifier.         %9d\n", isec1[36]);
-      fprintf(grprsm, " Type of ensemble forecast            %9d\n", isec1[37]);
-      fprintf(grprsm, " Individual ensemble member           %9d\n", isec1[38]);
-      fprintf(grprsm, " Number of forecasts in ensemble      %9d\n", isec1[39]);
-    }
-}
-
-void printQuasi(int *isec2)
-{
-  /*
-
-    Print the qusai-regular information in the Grid Description
-    Section (Section 2) of decoded GRIB data.
-
-    Input Parameters:
-
-       isec2 - Array of decoded integers from Section 2.
-
-    Comments:
-
-       Only data representation types catered for are Gaussian
-       grid, latitude/longitude grid, Spherical Harmonics,
-       Polar stereographic and Space view perspective.
-
-    Converted from EMOS routine PTQUASI.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
-
-  */
-
-  char yout[64];
-  int nextlat, latcnt;
-  int j;
-  int ntos;
-
-  /*
-    -----------------------------------------------------------------
-    Section 1. Print quasi-grid data.
-    -----------------------------------------------------------------
-  */
-  /*
-    See if scanning is north->south or south->north
-  */
-  fprintf(grprsm, "  Number of points along a parallel varies.\n");
-
-  ntos = ( fmod((double) isec2[10], 128.) < 64 );
-
-  if ( ntos )
-    fprintf(grprsm, "  Number of points.   Parallel. (North to South)\n");
-  else
-    fprintf(grprsm, "  Number of points.   Parallel. (South to North)\n");
-
-  /*  Display number of points for each latitude */
-  latcnt  = isec2[2];
-  nextlat = 0;
-  memset(yout, ' ', (size_t) 11);
-
-  for ( j = 0; j < latcnt; j++ )
-    {
-      nextlat = nextlat + 1;
-      sprintf(yout, "%4d", nextlat);
-
-      /*       Finished?  */
-      if ( nextlat > latcnt ) break;
-      if ( nextlat == latcnt )
-	{
-	  fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
-	  break;
-	}
-      /*
-	Look for neighbouring latitudes with same number of points
-      */
-      unsigned nrepeat = 0;
-
-    LABEL110:
-      /*
-	If neighbouring latitudes have same number of points
-	increase the repeat count.
-      */
-      if ( isec2[nextlat+21+1] == isec2[nextlat+21] )
-	{
-          nrepeat = nrepeat + 1;
-          nextlat = nextlat + 1;
-	  if ( nextlat < latcnt ) goto LABEL110;
-	}
-      /*
-	Display neighbouring latitudes with same number of points as
-	'nn to mm'.
-      */
-      if ( nrepeat >= 1 )
-	{
-	  strncpy(yout+4, " to", 3);
-	  sprintf(yout+7, "%5d", nextlat);
-        }
-      fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
-      memset(yout, ' ', (size_t) 11);
-    }
-}
-
-void gribPrintSec2DP(int *isec0, int *isec2, double *fsec2)
-{
-  /*
-
-    Print the information in the Grid Description
-    Section (Section 2) of decoded GRIB data.
-
-    Input Parameters:
-
-       isec0  - Array of decoded integers from Section 0
-
-       isec2  - Array of decoded integers from Section 2
-
-       fsec2  - Array of decoded floats from Section 2
-
-    Comments:
-
-       Only data representation types catered for are Gaussian
-       grid, latitude/longitude grid, Spherical Harmonics,
-       Polar stereographic and Space view perspective.
-
-
-    Converted from EMOS routine GRPRS2.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
-
-  */
-
-  int i, ibit, iedit, ierr, iout, iresol;
-
-  grsdef();
-  /*
-    -----------------------------------------------------------------
-    Section 1 . Print GRIB Edition number.
-    -----------------------------------------------------------------
-  */
-  iedit = isec0[1];
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 2 - Grid Description Section.\n");
-  fprintf(grprsm, " -------------------------------------\n");
-  /*
-    -----------------------------------------------------------------
-    Section 2 . Print spherical harmonic data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] == 50 || isec2[0] == 60 || 
-       isec2[0] == 70 || isec2[0] == 80 )
-    {
-      fprintf(grprsm, " Data represent type = spectral     (Table 6) %9d\n", isec2[0]);
-      fprintf(grprsm, " J - Pentagonal resolution parameter.         %9d\n", isec2[1]);
-      fprintf(grprsm, " K - Pentagonal resolution parameter.         %9d\n", isec2[2]);
-      fprintf(grprsm, " M - Pentagonal resolution parameter.         %9d\n", isec2[3]);
-      fprintf(grprsm, " Representation type (Table 9)                %9d\n", isec2[4]);
-      fprintf(grprsm, " Representation mode (Table 10).              %9d\n", isec2[5]);
-      for (i = 7; i <= 11; i++)
-        fprintf(grprsm, " Not used.                                    %9d\n", isec2[i-1]);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 3 . Print Gaussian grid data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] ==  4 || isec2[0] == 14 || 
-       isec2[0] == 24 || isec2[0] == 34 )
-    {
-      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
-      fprintf(grprsm, " Data represent type = gaussian     (Table 6) %9d\n", isec2[0]);
-      /*
-	Quasi-regular grids introduced in Edition 1.
-      */
-      if ( isec2[16] == 0 || iedit < 1 )
-	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
-      else
-      	printQuasi(isec2);
-
-      fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
-      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
-      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
-
-      ibit = 8;
-      iresol = isec2[5] + isec2[17] + isec2[18];
-      prtbin(iresol, ibit, &iout, &ierr);
-
-      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
-      fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
-      fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
-      /*
-	Print increment if given.
-      */
-      if ( isec2[5] == 128 )
-	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
-      else
-	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
-
-      fprintf(grprsm, " Number of parallels between pole and equator.%9d\n", isec2[9]);
-
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 4 . Print Latitude / longitude grid data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] ==  0 || isec2[0] == 10 || 
-       isec2[0] == 20 || isec2[0] == 30 )
-    {
-      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
-      fprintf(grprsm, " Data represent type = lat/long     (Table 6) %9d\n", isec2[0]);
-      /*
-	Quasi-regular lat/long grids also possible.
-      */
-      if ( isec2[16] == 0 )
-	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
-      else
-        printQuasi(isec2);
-
-      fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
-      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
-      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
-
-      ibit = 8;
-      iresol = isec2[5] + isec2[17] + isec2[18];
-      prtbin(iresol, ibit, &iout, &ierr);
-
-      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
-      fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
-      fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
-      /*
-	Print increment if given.
-      */
-      if ( isec2[8] < 0 )
-	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
-      else
-	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
-
-      if ( isec2[9] < 0 )
-	fprintf(grprsm, " j direction (North-South) increment          Not given\n");
-      else
-	fprintf(grprsm, " j direction (North-South) increment.         %9d\n", isec2[9]);
-    
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 5 . Print polar stereographic data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] == 5 )
-    {
-      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
-      fprintf(grprsm, " Data represent type = polar stereo (Table 6) %9d\n", isec2[0]);
-      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
-      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
-      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
-      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
-      ibit = 8;
-      iresol = isec2[17] + isec2[18];
-      prtbin(iresol, ibit, &iout, &ierr);
-      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
-      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
-      fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
-      fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 6 . Print Lambert conformal data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] == 3 )
-    {
-      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
-      fprintf(grprsm, " Data represent type = Lambert      (Table 6) %9d\n", isec2[0]);
-      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
-      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
-      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
-      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
-      ibit = 8;
-      iresol = isec2[17] + isec2[18] + isec2[5];
-      prtbin(iresol, ibit, &iout, &ierr);
-      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
-      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
-      fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
-      fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
-      fprintf(grprsm, " Latitude intersection 1 - Latin 1 -.         %9d\n", isec2[13]);
-      fprintf(grprsm, " Latitude intersection 2 - Latin 2 -.         %9d\n", isec2[14]);
-      fprintf(grprsm, " Latitude of Southern Pole.                   %9d\n", isec2[19]);
-      fprintf(grprsm, " Longitude of Southern Pole.                  %9d\n", isec2[20]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 7 . Print space view perspective or orthographic data.
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] == 90 )
-    {
-      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
-      fprintf(grprsm, " Data represent type = space/ortho  (Table 6) %9d\n", isec2[0]);
-      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
-      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
-      fprintf(grprsm, " Latitude of sub-satellite point.             %9d\n", isec2[3]);
-      fprintf(grprsm, " Longitude of sub-satellite point.            %9d\n", isec2[4]);
-      //iresol = isec2[17] + isec2[18];
-      fprintf(grprsm, " Diameter of the earth in x direction.        %9d\n", isec2[6]);
-      fprintf(grprsm, " Y coordinate of sub-satellite point.         %9d\n", isec2[9]);
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
-      fprintf(grprsm, " Altitude of the camera.                      %9d\n", isec2[13]);
-      fprintf(grprsm, " Y coordinate of origin of sector image.      %9d\n", isec2[14]);
-      fprintf(grprsm, " X coordinate of origin of sector image.      %9d\n", isec2[15]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 7.5 . Print ocean data
-    -----------------------------------------------------------------
-  */
-  /*
-  if ( isec2[0] == 192 && ISEC1_CenterID == 98 )
-    {
-      fprintf(grprsm, " Data represent type = ECMWF ocean  (Table 6) %9d\n", isec2[0]);
-      if ( isec2[1] ==  32767 )
-	fprintf(grprsm, " Number of points along the first axis.       Not used\n");
-      else
-	fprintf(grprsm, " Number of points along the first axis.       %9d\n", isec2[1]);
-
-      if ( isec2[2] ==  32767 )
-	fprintf(grprsm, " Number of points along the second axis.      Not used\n");
-      else
-	fprintf(grprsm, " Number of points along the second axis.      %9d\n", isec2[2]);
-
-      ibit = 8;
-      prtbin(isec2[10], ibit, &iout, &ierr);
-      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
-      goto LABEL800;
-    }
-    */
-  /*
-    -----------------------------------------------------------------
-    Section 7.6 . Print triangular data
-    -----------------------------------------------------------------
-  */
-  if ( isec2[0] == 192 /* && ISEC1_CenterID == 78 */ )
-    {
-      fprintf(grprsm, " Data represent type = triangular   (Table 6) %9d\n", isec2[0]);
-      fprintf(grprsm, " Number of factor 2 in factorisation of Ni.   %9d\n", isec2[1]);
-      fprintf(grprsm, " Number of factor 3 in factorisation of Ni.   %9d\n", isec2[2]);
-      fprintf(grprsm, " Number of diamonds (Nd).                     %9d\n", isec2[3]);
-      fprintf(grprsm, " Number of triangular subdivisions of the\n");
-      fprintf(grprsm, "           icosahedron (Ni).                  %9d\n", isec2[4]);
-      fprintf(grprsm, " Flag for orientation of diamonds (Table A).  %9d\n", isec2[5]);
-      fprintf(grprsm, " Latitude of pole point.                      %9d\n", isec2[6]);
-      fprintf(grprsm, " Longitude of pole point.                     %9d\n", isec2[7]);
-      fprintf(grprsm, " Longitude of the first diamond.              %9d\n", isec2[8]);
-      fprintf(grprsm, " Flag for storage sequence (Table B).         %9d\n", isec2[9]);
-      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
-      goto LABEL800;
-    }
-  /*
-    -----------------------------------------------------------------
-    Drop through to here => representation type not catered for.
-    -----------------------------------------------------------------
-  */
-  fprintf(grprsm, "GRPRS2 :Data representation type not catered for -%d\n", isec2[0]);
-
-  goto LABEL900;
-  /*
-    -----------------------------------------------------------------
-    Section 8 . Print vertical coordinate parameters,
-                rotated grid information,
-                stretched grid information, if any.
-    -----------------------------------------------------------------
-  */
- LABEL800:;
-  /*
-    Vertical coordinate parameters ...
-  */
-  if ( isec2[11] != 0 )
-    {
-      fprintf(grprsm, " \n");
-      fprintf(grprsm, " Vertical Coordinate Parameters.\n");
-      fprintf(grprsm, " -------------------------------\n");
-      for ( i = 10; i < isec2[11]+10; i++ )
-	fprintf(grprsm, "    %20.12f\n", fsec2[i]);
-    }
-  /*
-    Rotated and stretched grids introduced in Edition 1.
-  */
-  if ( iedit < 1 ) goto LABEL900;
-  /*
-    Rotated grid information ...
-  */
-  if ( isec2[0] == 10 || isec2[0] == 30 || 
-       isec2[0] == 14 || isec2[0] == 34 || 
-       isec2[0] == 60 || isec2[0] == 80 || 
-       isec2[0] == 30 )
-    {
-      fprintf(grprsm, " \n");
-      fprintf(grprsm, " Latitude of southern pole of rotation.       %9d\n", isec2[12]);
-      fprintf(grprsm, " Longitude of southern pole of rotation.      %9d\n", isec2[13]);
-      fprintf(grprsm, " Angle of rotation.                     %20.10f\n", fsec2[0]);
-    }
-  /*
-    Stretched grid information ...
-  */
-  if ( isec2[0] == 20 || isec2[0] == 30 || 
-       isec2[0] == 24 || isec2[0] == 34 || 
-       isec2[0] == 70 || isec2[0] == 80 )
-    {
-      fprintf(grprsm, " \n");
-      fprintf(grprsm, " Latitude of pole of stretching.              %9d\n", isec2[14]);
-      fprintf(grprsm, " Longitude of pole of stretching.             %9d\n", isec2[15]);
-      fprintf(grprsm, " Stretching factor.                     %20.10f\n", fsec2[1]);
-    }
-
- LABEL900:;
-
-  return;
-}
-
-void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
-{
-  int inum;
-  int j;
-  double *fsec2;
-
-  inum = 10 + isec2[11];
-
-  fsec2 = (double*) Malloc((size_t)inum*sizeof(double));
-  if ( fsec2 == NULL ) SysError("No Memory!");
-
-  for ( j = 0; j < inum; j++ )
-     fsec2[j] = fsec2sp[j];
-  
-  gribPrintSec2DP(isec0, isec2, fsec2);
-
-  Free(fsec2);
-}
-
-void gribPrintSec3DP(int *isec0, int *isec3, double *fsec3)
-{
-  /*
-
-    Print the information in the Bit-Map Section
-    (Section 3) of decoded GRIB data.
-
-    Input Parameters:
-
-       isec0  - Array of decoded integers from Section 0
-
-       isec3  - Array of decoded integers from Section 3
-
-       fsec3  - Array of decoded floats from Section 3
-
-
-    Converted from EMOS routine GRPRS3.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
-
-  */
-
-  UNUSED(isec0);
-
-  grsdef();
-
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 3 - Bit-map Section.\n");
-  fprintf(grprsm, " -------------------------------------\n");
-
-  if ( isec3[0] != 0 )
-    fprintf(grprsm, " Predetermined bit-map number.                %9d\n", isec3[0]);
-  else
-    fprintf(grprsm, " No predetermined bit-map.\n");
-
-  fprintf(grprsm, " Missing data value for integer data.    %14d\n", isec3[1]);
-
-  fprintf(grprsm, " Missing data value for real data. %20.6g\n", fsec3[1]);
-}
-
-void gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3sp)
-{
-  double fsec3[2];
-
-  fsec3[0] = fsec3sp[0];
-  fsec3[1] = fsec3sp[1];
-  
-  gribPrintSec3DP(isec0, isec3, fsec3);
-}
-
-void gribPrintSec4DP(int *isec0, int *isec4, double *fsec4)
-{
-  /*
-
-    Print the information in the Binary Data Section
-    (Section 4) of decoded GRIB data.
-
-    Input Parameters:
-
-       isec0  - Array of decoded integers from Section 0
-
-       isec4  - Array of decoded integers from Section 4
-
-       fsec4  - Array of decoded floats from Section 4
-
-
-    Converted from EMOS routine GRPRS4.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
-
-  */
-  int inum;
-  int j;
-
-  UNUSED(isec0);
-
-  grsdef();
-
-  /*
-    -----------------------------------------------------------------
-    Section 1 . Print integer information from isec4.
-    -----------------------------------------------------------------
-  */
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 4 - Binary Data  Section.\n");
-  fprintf(grprsm, " -------------------------------------\n");
-
-  fprintf(grprsm, " Number of data values coded/decoded.         %9d\n", isec4[0]);
-  fprintf(grprsm, " Number of bits per data value.               %9d\n", isec4[1]);
-  fprintf(grprsm, " Type of data       (0=grid pt, 128=spectral).%9d\n", isec4[2]);
-  fprintf(grprsm, " Type of packing    (0=simple, 64=complex).   %9d\n", isec4[3]);
-  fprintf(grprsm, " Type of data       (0=float, 32=integer).    %9d\n", isec4[4]);
-  fprintf(grprsm, " Additional flags   (0=none, 16=present).     %9d\n", isec4[5]);
-  fprintf(grprsm, " Reserved.                                    %9d\n", isec4[6]);
-  fprintf(grprsm, " Number of values   (0=single, 64=matrix).    %9d\n", isec4[7]);
-  fprintf(grprsm, " Secondary bit-maps (0=none, 32=present).     %9d\n", isec4[8]);
-  fprintf(grprsm, " Values width       (0=constant, 16=variable).%9d\n", isec4[9]);
-  /*
-    If complex packing ..
-  */
-  if ( isec4[3] == 64 )
-    {
-      if ( isec4[2] == 128 )
-	{
-	  fprintf(grprsm, " Byte offset of start of packed data (N).     %9d\n", isec4[15]);
-	  fprintf(grprsm, " Power (P * 1000).                            %9d\n", isec4[16]);
-	  fprintf(grprsm, " Pentagonal resolution parameter J for subset.%9d\n", isec4[17]);
-	  fprintf(grprsm, " Pentagonal resolution parameter K for subset.%9d\n", isec4[18]);
-	  fprintf(grprsm, " Pentagonal resolution parameter M for subset.%9d\n", isec4[19]);
-	}
-      else
-	{
-	  fprintf(grprsm, " Bits number of 2nd order values    (none=>0).%9d\n", isec4[10]);
-	  fprintf(grprsm, " General extend. 2-order packing (0=no,8=yes).%9d\n", isec4[11]);
-	  fprintf(grprsm, " Boustrophedonic ordering        (0=no,4=yes).%9d\n", isec4[12]);
-	  fprintf(grprsm, " Spatial differencing order          (0=none).%9d\n", isec4[13]+isec4[14]);
-        }
-    }
-  /*
-    Number of non-missing values
-  */
-  if ( isec4[20] != 0 )
-    fprintf(grprsm, " Number of non-missing values                 %9d\n", isec4[20]);
-  /*
-    Information on matrix of values , if present.
-  */
-  if ( isec4[7] == 64 )
-    {
-      fprintf(grprsm, " First dimension (rows) of each matrix.       %9d\n", isec4[49]);
-      fprintf(grprsm, " Second dimension (columns) of each matrix.   %9d\n", isec4[50]);
-      fprintf(grprsm, " First dimension coordinate values definition.%9d\n", isec4[51]);
-      fprintf(grprsm, " (Code Table 12)\n");
-      fprintf(grprsm, " NC1 - Number of coefficients for 1st dimension.%7d\n", isec4[52]);
-      fprintf(grprsm, " Second dimension coordinate values definition.%8d\n", isec4[53]);
-      fprintf(grprsm, " (Code Table 12)\n");
-      fprintf(grprsm, " NC2 - Number of coefficients for 2nd dimension.%7d\n", isec4[54]);
-      fprintf(grprsm, " 1st dimension physical signifance (Table 13). %8d\n", isec4[55]);
-      fprintf(grprsm, " 2nd dimension physical signifance (Table 13).%8d\n", isec4[56]);
-    }
-  /*
-    -----------------------------------------------------------------
-    Section 2. Print values from fsec4.
-    -----------------------------------------------------------------
-  */
-
-  inum = isec4[0];
-  if ( inum <  0 ) inum = - inum;
-  if ( inum > 20 ) inum = 20;
-  /*
-    Print first inum values.
-  */
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " First %4d data values.\n", inum);
-
-  if ( isec4[4] == 0 )
-    {
-      /*
-	Print real values ...
-      */
-      for ( j = 0; j < inum; j++ )
-	{
-	  if ( fabs(fsec4[j]) > 0 )
-	    {
-	      if ( fabs(fsec4[j]) >= 0.1 && fabs(fsec4[j]) <= 1.e8 )
-		fprintf(grprsm, " %#16.8G    \n", fsec4[j]);
-	      else
-		fprintf(grprsm, " %#20.8E\n", fsec4[j]);
-	    }
-	  else
-	    fprintf(grprsm, " %#16.0f    \n", fabs(fsec4[j]));
-	}
-    }
-  else
-    {
-      /*
-	Print integer values ...
-      */
-      fprintf(grprsm, " Print of integer values not supported\n");
-      /*
-        CALL SETPAR(IBIT,IDUM,IDUM)
-        DO 212 J=1,INUM
-           INSPT = 0
-           CALL INXBIT(IVALUE,1,INSPT,FSEC4(J),1,IBIT,IBIT,'C',IRET)
-           WRITE (*,9033) IVALUE
- 9033 FORMAT(' ',I15)
-  212   CONTINUE
-      ENDIF
-      */
-    }
-}
-
-void gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4sp)
-{
-  int inum;
-  int j;
-  double fsec4[20];
-
-  inum = isec4[0];
-  if ( inum <  0 ) inum = -inum;
-  if ( inum > 20 ) inum = 20;
-
-  for ( j = 0; j < inum; j++ ) fsec4[j] = fsec4sp[j];
-  
-  gribPrintSec4DP(isec0, isec4, fsec4);
-}
-
-void gribPrintSec4Wave(int *isec4)
-{
-  /*
-
-    Print the wave coordinate information in the Binary Data
-    Section (Section 4) of decoded GRIB data.
-
-    Input Parameters:
-
-       isec4 - Array of decoded integers from Section 4
-
-    Comments:
-
-       Wave coordinate information held in isec4 are 32-bit floats,
-       hence the PTEMP and NTEMP used for printing are 4-byte variables.
-
-
-    Converted from EMOS routine GRPRS4W.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
-
-  */
-  int    jloop;
-  int    ntemp[100];
-  float *ptemp;
-
-  grsdef();
-
-  /*
-    -----------------------------------------------------------------
-    Section 1 . Print integer information from isec4.
-    -----------------------------------------------------------------
-  */
-  fprintf(grprsm, " Coefficients defining first dimension coordinates:\n");
-  for ( jloop = 0; jloop < isec4[52]; jloop++ )
-    {
-      ntemp[jloop] = isec4[59 + jloop];
-      ptemp = (float *) &ntemp[jloop];
-      fprintf(grprsm, "%20.10f\n", *ptemp);
-    }
-  fprintf(grprsm, " Coefficients defining second dimension coordinates:\n");
-  for ( jloop = 0; jloop < isec4[54]; jloop++ )
-    {
-      ntemp[jloop] = isec4[59 + isec4[52] + jloop];
-      ptemp = (float *) &ntemp[jloop];
-      fprintf(grprsm, "%20.10f\n", *ptemp);
-    }
-}
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <string.h>
-#include <ctype.h>
-
-
-
-int gribOpen(const char *filename, const char *mode)
-{
-  int fileID = fileOpen(filename, mode);
-
-#if defined (__sun)
-  if ( fileID != FILE_UNDEFID && tolower(*mode) == 'r' )
-    {
-      fileSetBufferType(fileID, FILE_BUFTYPE_MMAP);
-    }
-#endif
-
-  return fileID;  
-}
-
-
-void gribClose(int fileID)
-{
-  fileClose(fileID);
-}
-
-
-off_t gribGetPos(int fileID)
-{
-  return fileGetPos(fileID);
-}
-
-
-int gribCheckFiletype(int fileID)
-{
-  int found = 0;
-  char buffer[4];
-
-  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
-
-  if ( memcmp(buffer, "GRIB", 4) == 0 )
-    {
-      found = 1;
-      if ( CGRIBEX_Debug ) Message("found GRIB file = %s", fileInqName(fileID));
-    }
-  else
-    {
-      long offset;
-      int ierr = gribFileSeek(fileID, &offset);
-      fileRewind(fileID);
-      if ( !ierr )
-	{
-	  found = 1;
-	  if ( CGRIBEX_Debug ) Message("found seek GRIB file = %s", fileInqName(fileID));
-	}
-    }
-
-  return found;
-}
-
-
-int gribCheckSeek(int fileID, long *offset, int *version)
-{
-  int ierr = gribFileSeek(fileID, offset);
-
-  *version = -1;
-  if ( !ierr )
-    {
-      char buffer[4];
-     if ( fileRead(fileID, buffer, 4) == 4 )
-	*version = buffer[3];
-    }
-
-  return ierr;
-}
-
-
-int gribFileSeekOld(int fileID, long *offset)
-{
-  /* position file pointer after GRIB */
-  enum { buffersize = 4096 };
-  unsigned char buffer[buffersize];
-  int retry = 4096;
-
-  *offset = 0;
-
-  void *fileptr = filePtr(fileID);
-
-  for ( size_t i = 0; i < 4; ++i)
-    {
-      int ch = filePtrGetc(fileptr);
-      if ( ch == EOF ) return (-1);
-      buffer[i] = (unsigned char)ch;
-    }
-  /*
-  fileRead(fileID, buffer, 4);
-  */
-
-  while ( retry-- )
-    {
-      size_t i;
-      for ( i = 0; i < buffersize-4; ++i )
-	{
-	  if (buffer[i  ] == 'G' &&
-	      buffer[i+1] == 'R' &&
-	      buffer[i+2] == 'I' &&
-	      buffer[i+3] == 'B')
-	    {
-	      if ( CGRIBEX_Debug )
-		Message("record offset = %d", (int) *offset);
-	      return (0);
-	    }
-	  else
-	    {
-	      int ch = filePtrGetc(fileptr); if ( ch == EOF ) return (-1); buffer[i+4] = (unsigned char)ch;
-	      (*offset)++;
-	    }
-	}
-      buffer[0] = buffer[i  ];
-      buffer[1] = buffer[i+1];
-      buffer[2] = buffer[i+2];
-      buffer[3] = buffer[i+3];
-    }
-
-  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
-
-  return 1;
-}
-
-
-int gribFileSeek(int fileID, long *offset)
-{
-  /* position file pointer after GRIB */
-  const long GRIB = 0x47524942;
-  long code = 0;
-  int ch;
-  int retry = 4096*4096;
-
-  *offset = 0;
-
-  void *fileptr = filePtr(fileID);
-
-  while ( retry-- )
-    {
-      ch = filePtrGetc(fileptr);
-      if ( ch == EOF ) return (-1);
-    
-      code = ( (code << 8) + ch ) & 0xFFFFFFFF;
-
-      if ( code == GRIB )
-	{
-	  if ( CGRIBEX_Debug )
-	    Message("record offset = %d", (int) *offset);
-	  return (0);
-	}
-
-      (*offset)++;
-    }
-
-  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
-
-  return 1;
-}
-
-
-int gribFileSeekTest(int fileID, long *offset)
-{
-  /* position file pointer after GRIB */
-  const long GRIB = 0x47524942L;
-  long code = 0;
-  int ch;
-  int i = 0;
-  enum { buffersize = 8 };
-  unsigned char buffer[buffersize];
-  unsigned long retry = 4096L*4096L;
-  int nread = 0;
-
-  *offset = 0;
-
-  void *fileptr = filePtr(fileID);
-
-  while ( retry-- )
-    {
-      if ( i >= nread )
-	{
-	  nread = (int) filePtrRead(fileptr, buffer, buffersize);
-	  if ( nread == 0 ) return (-1);
-	  i = 0;
-	}
-
-      ch = buffer[i++];
-      code = ( (code << 8) + ch ) & 0xFFFFFFFFL;
-
-      if ( code == GRIB )
-	{
-	  /* printf("end: %d %d\n", nread, i); */
-	  if ( CGRIBEX_Debug )
-	    Message("record offset = %d", (int) *offset);
-
-	  if ( i != nread ) fileSetPos(fileID, (off_t) i-nread, SEEK_CUR);
-
-	  return (0);
-	}
-
-      (*offset)++;
-    }
-
-  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
-
-  return 1;
-}
-
-static inline int
-read3ByteMSBFirst(void *fileptr)
-{
-  unsigned b1 = (unsigned)(filePtrGetc(fileptr));
-  unsigned b2 = (unsigned)(filePtrGetc(fileptr));
-  unsigned b3 = (unsigned)(filePtrGetc(fileptr));
-  return (int)((b1 << 16) + (b2 << 8) + b3);
-}
-
-int gribReadSize(int fileID)
-{
-  void *fileptr = filePtr(fileID);
-  off_t pos = fileGetPos(fileID); 
-
-  unsigned b1 = (unsigned) filePtrGetc(fileptr);
-  unsigned b2 = (unsigned) filePtrGetc(fileptr);
-  unsigned b3 = (unsigned) filePtrGetc(fileptr);
-
-  int gribsize = gribrec_len(b1, b2, b3);
-  int gribversion = filePtrGetc(fileptr);
-
-  if ( gribsize == 24 )
-    {
-      if ( gribversion != 1 && gribversion != 2 ) gribversion = 0;
-    }
-
-  if ( CGRIBEX_Debug )
-    Message("gribversion = %d", gribversion);
-
-  if ( gribversion == 0 )
-    {
-      int pdssize = 0, gdssize = 0, bmssize = 0, bdssize = 0;
-      int issize = 4, essize = 4;
-      int flag = 0;
-
-      pdssize = gribsize;
-      fileSetPos(fileID, (off_t) 3, SEEK_CUR);
-      if ( CGRIBEX_Debug ) Message("pdssize     = %d", pdssize);
-      flag = filePtrGetc(fileptr);
-      if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
-  
-      fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
-
-      if ( flag & 128 )
-	{
-	  gdssize = read3ByteMSBFirst(fileptr);
-	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
-	  if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
-	}
-
-      if ( flag & 64 )
-	{
-	  bmssize = read3ByteMSBFirst(fileptr);
-	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
-	  if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
-	}
-
-      bdssize = read3ByteMSBFirst(fileptr);
-      if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
-
-      gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
-    }
-  else if ( gribversion == 1 )
-    {
-      if ( gribsize > JP23SET ) /* Large GRIB record */
-	{
-	  int pdssize = 0, gdssize = 0, bmssize = 0, bdssize = 0;
-	  int issize = 4, essize = 4;
-	  int flag;
-
-	  pdssize = read3ByteMSBFirst(fileptr);
-	  if ( CGRIBEX_Debug ) Message("pdssize     = %d", pdssize);
-
-	  for ( int i = 0; i < 5; ++i ) flag = filePtrGetc(fileptr);
-	  if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
-  
-	  fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
-
-	  if ( flag & 128 )
-	    {
-	      gdssize = read3ByteMSBFirst(fileptr);
-	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
-	      if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
-	    }
-	  
-	  if ( flag & 64 )
-	    {
-	      bmssize = read3ByteMSBFirst(fileptr);
-	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
-	      if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
-	    }
-
-	  bdssize = read3ByteMSBFirst(fileptr);
-	  bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
-	  if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
-
-	  gribsize = issize+pdssize+gdssize+bmssize+bdssize+essize;
-	}
-    }
-  else if ( gribversion == 2 )
-    {
-      int i;
-      /* we set gribsize the following way because it doesn't matter then
-	 whether int is 4 or 8 bytes long - we don't have to care if the size
-	 really fits: if it does not, the record can not be read at all */
-      gribsize = 0;
-      for ( i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | filePtrGetc(fileptr);
-    }
-  else
-    {
-      gribsize = 0;
-      Warning("GRIB version %d unsupported!", gribversion);
-    }
-
-  if ( filePtrEOF(fileptr) ) gribsize = 0;
-
-  if ( CGRIBEX_Debug )
-    Message("gribsize    = %d", gribsize);
-
-  fileSetPos(fileID, pos, SEEK_SET);
-
-  return gribsize;
-}
-
-
-int gribGetSize(int fileID)
-{
-  long offset;
-  int ierr = gribFileSeek(fileID, &offset); /* position file pointer after GRIB */
-  if ( ierr > 0 )
-    {
-      Warning("GRIB record not found!");
-      return (0);
-    }
-
-  if      ( ierr == -1 ) return 0;
-  else if ( ierr ==  1 ) return 0;
-
-  int recSize = gribReadSize(fileID);
-
-  if ( CGRIBEX_Debug ) Message("recsize = %d", recSize);
-
-  fileSetPos(fileID, (off_t) -4, SEEK_CUR);
-
-  return recSize;
-}
-
-
-int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
-{
-  long offset;
-  int ierr = gribFileSeek(fileID, &offset); /* position file pointer after GRIB */
-  if ( ierr > 0 )
-    {
-      Warning("GRIB record not found!");
-      return (-2);
-    }
-
-  if      ( ierr == -1 ) { *buffersize = 0; return -1; }
-  else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
-
-  size_t recSize  = (size_t)gribReadSize(fileID);
-  size_t readSize = recSize;
-
-  if ( readSize > *buffersize )
-    {
-      readSize = *buffersize;
-      ierr = -3;          // Tell the caller that the buffer was insufficient.
-    }
-
-  *buffersize = recSize;  // Inform the caller about the record size.
-
-  // Write the stuff to the buffer that has already been read in gribFileSeek().
-  buffer[0] = 'G';
-  buffer[1] = 'R';
-  buffer[2] = 'I';
-  buffer[3] = 'B';
-
-  readSize -= 4;
-  // Read the rest of the record into the buffer.
-  size_t nread = fileRead(fileID, &buffer[4], readSize);
-
-  if ( nread != readSize ) ierr = 1;
-
-  return ierr;
-}
-
-
-int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
-{
-  int  nwrite = 0;
-
-  if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
-    {
-      perror(__func__);
-      nwrite = -1;
-    }
-
-  return nwrite;
-}
-
-
-int gribrec_len(unsigned b1, unsigned b2, unsigned b3)
-{
-  /*
-    If bit 7 of b1 is set, we have to rescale by factor of 120.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  int needRescaling = b1 & (1 << 7);
-  
-  int gribsize = (int)((((b1&127) << 16)+(b2<<8) + b3));
-
-  if ( needRescaling ) gribsize *= 120;
-
-  return gribsize;
-}
-
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-
-FILE *grprsm = NULL;
-double fref;
-double fmaxval;
-int nfref;
-int nfmaxval;
-int nrnd;
-int ndbg;
-int nvck;
-int nonoff;
-int noabort;
-int num2ok;
-int next2o;
-int nloc2o;
-int nsubce;
-int grib_calendar = -1;
-
-
-void gribSetCalendar(int calendar)
-{
-  grib_calendar = calendar;
-}
-
-
-void grsdef(void)
-{
-  /*
-C---->
-C**** GRSDEF - Initial (default) setting of common area variables
-C              for GRIBEX package.
-C
-C     Purpose.
-C     --------
-C
-C     Sets initial values for common area variables for all
-C     routines of GRIBEX package, if not already done.
-C
-C**   Interface.
-C     ----------
-C
-C     CALL GRSDEF
-C
-C     Input Parameters.
-C     -----------------
-C
-C     None.
-C
-C     Output Parameters.
-C     ------------------
-C
-C     None.
-C
-C     Method.
-C     -------
-C
-C     Self-explanatory.
-C
-C     Externals.
-C     ----------
-C
-C     None.
-C
-C     Reference.
-C     ----------
-C
-C     See subroutine GRIBEX.
-C
-C     Comments.
-C     ---------
-C
-C     None
-C
-C     Author.
-C     -------
-C
-C     J. Clochard, Meteo France, for ECMWF - March 1998.
-C
-C     Modifications.
-C     --------------
-C
-C     J. Clochard, Meteo France, for ECMWF - June 1999.
-C     Add variable NSUBCE.
-C     Use a static variable to determine if initialisation has already
-C     been done. NUSER removed .
-C     Reverse defaults for NEXT2O and NLOC2O, for consistency with
-C     version 13.023 of software .
-C
-  */
-  /*
-C     ----------------------------------------------------------------
-C*    Section 0 . Definition of variables.
-C     ----------------------------------------------------------------
-  */
-  char *envString;
-  char *env_stream;
-  static int lfirst = TRUE;
-  extern int CGRIBEX_Const;
-
-  if ( ! lfirst ) return;
-
-  /*
-    ----------------------------------------------------------------
-    Section 1 . Set values, conditionally.
-    ----------------------------------------------------------------
-  */
-  /*
-    Common area variables have not been set. Set them.
-    
-    User supplied reference value.
-  */
-  fref   = 0.0;
-  /*
-    Reference value supplied by user flag. Set to off.
-  */
-  nfref  = 0;
-  /*
-    User supplied maximum value.
-  */
-  fmaxval   = 0.0;
-  /*
-    Maximum value supplied by user flag. Set to off.
-  */
-  nfmaxval  = 0;
-  /*
-    Set rounding to 120 bytes on.
-  */
-  nrnd   = 1;
-  /*
-    Set GRIB calendar.
-  */
-  if ( grib_calendar == -1 )
-    {
-      grib_calendar = CALENDAR_PROLEPTIC;
-  
-      envString = getenv("GRIB_CALENDAR");
-      if ( envString )
-	{
-	  if      ( strncmp(envString, "standard", 8) == 0 )
-	    grib_calendar = CALENDAR_STANDARD;
-	  else if ( strncmp(envString, "proleptic", 9) == 0 )
-	    grib_calendar = CALENDAR_PROLEPTIC;
-	  else if ( strncmp(envString, "360days", 7) == 0 )
-	    grib_calendar = CALENDAR_360DAYS;
-	  else if ( strncmp(envString, "365days", 7) == 0 )
-	    grib_calendar = CALENDAR_365DAYS;
-	  else if ( strncmp(envString, "366days", 7) == 0 )
-	    grib_calendar = CALENDAR_366DAYS;
-	  else if ( strncmp(envString, "none", 4) == 0 )
-	    grib_calendar = CALENDAR_NONE;
-	}
-    }
-  /*
-    Set debug print off.
-  */
-  ndbg   = 0;
-  
-  envString = getenv("GRIBEX_DEBUG");
-  if ( envString != NULL )
-    {
-      if ( !strncmp(envString, "ON", 2) )
-        ndbg = 1;
-      else if( *envString == '1')
-        ndbg = 1;
-      else if( *envString == '2')
-        ndbg = 2;
-      else
-        ndbg = 0;
-    }
-  /*
-    Set GRIBEX compatibility mode.
-  */
-  envString = getenv("GRIB_GRIBEX_MODE_ON");
-  if ( envString != NULL )
-    {
-      if ( atoi(envString) == 1 ) CGRIBEX_Const = 0;
-    }
-
-  /*
-    Set GRIB value checking on.
-  */
-  nvck   = 1;
-  
-  envString = getenv("GRIBEX_CHECK");
-  if ( envString )
-    {
-      if ( !strncmp(envString, "OFF", 3) )
-        nvck = 0;
-      else
-        nvck = 1;
-    }
-  /*
-    See if output stream needs changing
-  */
-  grprsm = stdout;
-  env_stream = getenv("GRPRS_STREAM");
-  if ( env_stream )
-    {
-      if ( isdigit((int) env_stream[0]) )
-	{
-	  int unit;
-	  unit = atoi(env_stream);
-	  if ( unit < 1 || unit > 99 )
-	    Warning("Invalid number for GRPRS_STREAM: %d", unit);
-	  else if ( unit == 2 )
-	    grprsm = stderr;
-	  else if ( unit == 6 )
-	    grprsm = stdout;
-	  else
-	    {
-	      char filename[] = "unit.00";
-	      sprintf(filename, "%2.2d", unit);
-	      grprsm = fopen(filename, "w");
-	      if ( ! grprsm )
-		SysError("GRPRS_STREAM = %d", unit);
-	    }
-	}
-      else
-	{
-	  if ( env_stream[0] )
-	    {
-	      grprsm = fopen(env_stream, "w");
-	      if ( ! grprsm )
-		SysError("GRPRS_STREAM = %s", env_stream);
-	    }
-	}
-    }
-  /*
-    Set P factor switch to default, user supplies the P factor.
-  */
-  nonoff = 0;
-  /*
-    Set abort flag to NO abort
-  */
-  noabort = 1;
-  /*
-    Mark common area values set by user.
-  */
-  lfirst = FALSE;
-  /*
-    Exhaustive use of all possible second-order packing methods
-    for HOPER='K'. Set to off.
-  */
-  num2ok  = 0;
-  /*
-    Use of extended second-order packing methods for grid-point
-    encoding (HOPER='C' and 'K'). Set to on.
-  */
-  next2o  = 1;
-  /*
-    Use of non-local second-order packing methods for grid-point
-    encoding (HOPER='C' and 'K'). Set to on.
-  */
-  nloc2o  = 1;
-  /*
-    Use of (all valid) sub-centre values for ECMWF fields encoding .
-    encoding. Set to off.
-  */
-  nsubce  = 0;
-}
-
-/* pack 8-bit bytes from 64-bit words to a packed buffer */
-/* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (unsigned char) up[i]; */
-
-long packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc)
-{
-#if defined (CRAY)
-  (void) _pack(up, cp, bc, tc);
-#else
-  U_BYTEORDER;
-  unsigned char *cp0;
-  unsigned INT64 upi, *up0, *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
-  long head, trail, inner, i, j;
-  long ipack = sizeof(INT64);
-  
-  /* Bytes until first word boundary in destination buffer */
-
-  head = ( (long) cp ) & (ipack-1);
-  if ( head != 0 ) head = ipack - head;
-
-  inner = bc - head;
-
-  /* Trailing bytes which do not make a full word */
-
-  trail = inner & (ipack-1);
-
-  /* Number of bytes/words to be processed in fast loop */
-
-  inner -= trail;
-  inner /= ipack;
-
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
-  ip4 = ip0 + 4;
-  ip5 = ip0 + 5;
-  ip6 = ip0 + 6;
-  ip7 = ip0 + 7;
-
-  up0 = (unsigned INT64 *) (cp + head);
-
-  /* Here we should process any bytes until the first word boundary 
-   * of our destination buffer 
-   * That code is missing so far  because our output buffer is 
-   * word aligned by FORTRAN 
-   */
-
-  j = 0;
-
-  if ( IS_BIGENDIAN() )
-    {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  upi =             (   ip0[j]          << 56 ) 
-	                 |  ( ( ip1[j] & 0xFF ) << 48 )
-	                 |  ( ( ip2[j] & 0xFF ) << 40 )
-	                 |  ( ( ip3[j] & 0xFF ) << 32 )
-	                 |  ( ( ip4[j] & 0xFF ) << 24 ) ;
-	  up0[i] = upi   |  ( ( ip5[j] & 0xFF ) << 16 )
-	                 |  ( ( ip6[j] & 0xFF ) <<  8 )
-	                 |    ( ip7[j] & 0xFF ) ;
-	  j += ipack;
-	}
-    }
-  else
-    {
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  upi =             (   ip7[j]          << 56 ) 
-	                 |  ( ( ip6[j] & 0xFF ) << 48 )
-                         |  ( ( ip5[j] & 0xFF ) << 40 )
-                         |  ( ( ip4[j] & 0xFF ) << 32 )
-                         |  ( ( ip3[j] & 0xFF ) << 24 ) ;
-	  up0[i] = upi   |  ( ( ip2[j] & 0xFF ) << 16 )
-                         |  ( ( ip1[j] & 0xFF ) <<  8 )
-                         |    ( ip0[j] & 0xFF ) ;
-	  j += ipack;
-	}
-    }
-
-  cp0 = (unsigned char *) ( up0 + inner );
-  if ( trail > 0 )
-    {
-      up0[inner] = 0;
-      for ( i = 0 ; i < trail ; i ++ )
-	{
-	  *cp0 = (unsigned char) ip0[ipack*inner+i];
-	  cp0++;
-	}
-    }
-
-  if ( tc != -1 )
-    {
-      bc++;
-      *cp0 = (unsigned char) tc;
-    }
-#endif
-  return (bc);
-}
-
-/* unpack 8-bit bytes from a packed buffer with 64-bit words */
-/* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT64) cp[i]; */
-
-long unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc)
-{
-  U_BYTEORDER;
-  const unsigned char *cp0;
-  unsigned INT64 *up0;
-  unsigned INT64 *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
-  long head, trail, inner, i, j;
-  long offset;
-  long ipack = sizeof(INT64);
-
-  UNUSED(tc);
-
-  /* Bytes until first word boundary in source buffer */
-
-  head = ( (long) cp ) & (ipack-1);
-  if ( head != 0 ) head = ipack - head;
-  if ( head > bc ) head = bc;
-
-  inner = bc - head;
-
-  /* Trailing bytes which do not make a full word */
- 
-  trail = inner & (ipack-1);
- 
-  /* Number of bytes/words to be processed in fast loop */
-
-  inner -= trail;
-  inner /= ipack;
-
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
-  ip4 = ip0 + 4;
-  ip5 = ip0 + 5;
-  ip6 = ip0 + 6;
-  ip7 = ip0 + 7;
-
-  up0 = (unsigned INT64 *) (cp + head);
-
-  /* Process any bytes until the first word boundary 
-   * of our source buffer 
-   */
-  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT64) cp[i];
-
-  j = 0;
-
-  if ( IS_BIGENDIAN() )
-    {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  ip0[j] = (up0[i] >> 56) & 0xFF;
-	  ip1[j] = (up0[i] >> 48) & 0xFF;
-	  ip2[j] = (up0[i] >> 40) & 0xFF;
-	  ip3[j] = (up0[i] >> 32) & 0xFF;
-	  ip4[j] = (up0[i] >> 24) & 0xFF;
-	  ip5[j] = (up0[i] >> 16) & 0xFF;
-	  ip6[j] = (up0[i] >>  8) & 0xFF;
-	  ip7[j] = (up0[i])       & 0xFF;
-
-	  j += ipack;
-	}
-    }
-  else
-    {
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  ip7[j] = (up0[i] >> 56) & 0xFF;
-	  ip6[j] = (up0[i] >> 48) & 0xFF;
-	  ip5[j] = (up0[i] >> 40) & 0xFF;
-	  ip4[j] = (up0[i] >> 32) & 0xFF;
-	  ip3[j] = (up0[i] >> 24) & 0xFF;
-	  ip2[j] = (up0[i] >> 16) & 0xFF;
-	  ip1[j] = (up0[i] >>  8) & 0xFF;
-	  ip0[j] = (up0[i])       & 0xFF;
-
-	  j += ipack;
-	}
-    }
-
-  if ( trail > 0 )
-    {
-      offset = head + ipack*inner;
-      cp0 = cp + offset;
-      for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT64) cp0[i];
-    }
-  /*
-  if ( tc != -1 ) {
-    bc++;
-    *cp0 = (unsigned char) tc;
-  }
-  */
-  return (bc);
-}
-
-/* pack 8-bit bytes from 32-bit words to a packed buffer */
-/* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (char) up[i]; */
-
-#if  defined  (INT32)
-long packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc)
-{
-  U_BYTEORDER;
-  unsigned char *cp0;
-  unsigned INT32 *up0, *ip0, *ip1, *ip2, *ip3;
-  long head, trail, inner, i, j;
-  long ipack = sizeof(INT32);
-  
-  /* Bytes until first word boundary in destination buffer */
-
-  head = ( (long) cp ) & (ipack-1);
-  if ( head != 0 ) head = ipack - head;
-
-  inner = bc - head;
-
-  /* Trailing bytes which do not make a full word */
-
-  trail = inner & (ipack-1);
-
-  /* Number of bytes/words to be processed in fast loop */
-
-  inner -= trail;
-  inner /= ipack;
-
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
-
-  up0 = (unsigned INT32 *) (cp + head);
-
-  /* Here we should process any bytes until the first word boundary 
-   * of our destination buffer 
-   * That code is missing so far  because our output buffer is 
-   * word aligned by FORTRAN 
-   */
-
-  j = 0;
+    Method:
+    -------
 
-  if ( IS_BIGENDIAN() )
-    {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  up0[i] =          (   ip0[j]          << 24 ) 
-	                 |  ( ( ip1[j] & 0xFF ) << 16 )
-	                 |  ( ( ip2[j] & 0xFF ) <<  8 )
-	                 |    ( ip3[j] & 0xFF ) ;
-	  j += ipack;
-	}
-    }
-  else
-    {
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  up0[i] =          (   ip3[j]          << 24 ) 
-	                 |  ( ( ip2[j] & 0xFF ) << 16 )
-                         |  ( ( ip1[j] & 0xFF ) <<  8 )
-                         |    ( ip0[j] & 0xFF ) ;
-	  j += ipack;
-	}
-    }
+    Floating point number represented as 8 bit signed
+    exponent and 24 bit mantissa in integer values.
 
-  cp0 = (unsigned char *) ( up0 + inner );
-  if ( trail > 0 )
-    {
-      up0[inner] = 0;
-      for ( i = 0 ; i < trail ; i ++ )
-	{
-	  *cp0 = (unsigned char) ip0[ipack*inner+i];
-	  cp0++;
-	}
-    }
+    Externals.
+    ----------
 
-  if ( tc != -1 )
-    {
-      bc++;
-      *cp0 = (unsigned char) tc;
-    }
+    decfp2    - Decode from IBM floating point format.
 
-  return (bc);
-}
-#endif
+    Reference:
+    ----------
 
-/* unpack 8-bit bytes from a packed buffer with 32-bit words */
-/* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT32) cp[i]; */
+    WMO Manual on Codes re GRIB representation.
 
-#if  defined  (INT32)
-long unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc)
-{
-  U_BYTEORDER;
-  const unsigned char *cp0;
-  unsigned INT32 *up0;
-  unsigned INT32 *ip0, *ip1, *ip2, *ip3;
-  long head, trail, inner, i, j;
-  long offset;
-  long ipack = sizeof(INT32);
+    Comments:
+    ---------
 
-  UNUSED(tc);
+    Routine aborts if an invalid conversion type parameter
+    is used or if a 24 bit mantissa is not produced.
 
-  /* Bytes until first word boundary in source buffer */
+    Author:
+    -------
+     
+    John Hennessy   ECMWF   18.06.91
 
-  head = ( (long) cp ) & (ipack-1);
-  if ( head != 0 ) head = ipack - head;
-  if ( head > bc ) head = bc;
+    Modifications:
+    --------------
 
-  inner = bc - head;
+    Uwe Schulzweida   MPIfM   01/04/2001
 
-  /* Trailing bytes which do not make a full word */
- 
-  trail = inner & (ipack-1);
- 
-  /* Number of bytes/words to be processed in fast loop */
+    Convert to C from EMOS library version 130
 
-  inner -= trail;
-  inner /= ipack;
+    Uwe Schulzweida   MPIfM   02/08/2002
 
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
+     - speed up by factor 1.6 on NEC SX6
+        - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
+  */
 
-  up0 = (unsigned INT32 *) (cp + head);
+  // extern int CGRIBEX_Debug;
 
-  /* Process any bytes until the first word boundary 
-   * of our source buffer 
-   */
-  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT32) cp[i];
+  /* ----------------------------------------------------------------- */
+  /*   Section 1 . Initialise                                          */
+  /* ----------------------------------------------------------------- */
 
-  j = 0;
+  /*  Check conversion type parameter. */
 
-  if ( IS_BIGENDIAN() )
+  int iround = kround;
+  if ( iround != 0 && iround != 1 )
     {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  ip0[j] = (up0[i] >> 24) & 0xFF;
-	  ip1[j] = (up0[i] >> 16) & 0xFF;
-	  ip2[j] = (up0[i] >>  8) & 0xFF;
-	  ip3[j] = (up0[i])       & 0xFF;
+      Error("Invalid conversion type = %d", iround);
 
-	  j += ipack;
-	}
+      /*  If not aborting, arbitrarily set rounding to 'up'. */
+     iround = 1;
     }
-  else
-    {
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  ip3[j] = (up0[i] >> 24) & 0xFF;
-	  ip2[j] = (up0[i] >> 16) & 0xFF;
-	  ip1[j] = (up0[i] >>  8) & 0xFF;
-	  ip0[j] = (up0[i])       & 0xFF;
 
-	  j += ipack;
-	}
-    }
+  /* ----------------------------------------------------------------- */
+  /*   Section 2 . Convert value of zero.                              */
+  /* ----------------------------------------------------------------- */
 
-  if ( trail > 0 )
+  if ( ! (fabs(pval) > 0))
     {
-      offset = head + ipack*inner;
-      cp0 = cp + offset;
-      for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT32) cp0[i];
+      *kexp  = 0;
+      *kmant = 0;
+      // iexp   = 0;
+      // isign  = 0;
+      goto LABEL900;
     }
-  /*
-  if ( tc != -1 ) {
-    bc++;
-    *cp0 = (unsigned char) tc;
-  }
-  */
-
-  return (bc);
-}
-#endif
-#include <stdio.h>
-
-void prtbin(int kin, int knbit, int *kout, int *kerr)
-{
-  /*
-
-    Produces a decimal number with ones and zeroes
-    corresponding to the ones and zeroes of the input
-    binary number.
-    eg input number 1011 binary, output number 1011 decimal.
 
+  /* ----------------------------------------------------------------- */
+  /*   Section 3 . Convert other values.                               */
+  /* ----------------------------------------------------------------- */
+  {
+    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
+    double zref = pval;
 
-    Input Parameters:
-    
-       kin   - Integer variable containing binary number.
+    /*  Sign of value. */
 
-       knbit - Number of bits in binary number.
+    int isign = zref >= 0.0 ? 0 : 128;
+    zref = fabs(zref);
 
-    Output Parameters:
+    /*  Exponent. */
 
-       kout  - Integer variable containing decimal value
-               with ones and zeroes corresponding to those of
-	       the input binary number.
+    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
 
-       kerr  - 0, If no error.
-               1, Number of bits in binary number exceeds
-	          maximum allowed or is less than 1.
+    /* only ANSI C99 has log2 */
+    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
 
+    if ( iexp < 0   ) iexp = 0;
+    if ( iexp > 127 ) iexp = 127;
 
-    Converted from EMOS routine PRTBIN.
+    double rpowref;
+    /*
+      rpowref = zref / pow(16.0, (double)(iexp - 70));
+    */
 
-       Uwe Schulzweida   MPIfM   01/04/2001
+    rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-  */
-  int idec;
-  int ik;
-  int itemp;
-  int j;
+    /*  Mantissa. */
 
-  /*
-    Check length of binary number to ensure decimal number
-    generated will fit in the computer word - in this case will
-    it fit in a Cray 48 bit integer?
-  */
-  if ( knbit < 1 || knbit > 14 )
+    if ( iround == 0 )
     {
-      *kerr = 1;
-      printf(" prtbin : Error in binary number length - %3d bits.\n", knbit);
-      return;
-    }
-  else
-    *kerr = 0;
-  /*
-    -----------------------------------------------------------------
-    Section 1. Generate required number.
-    -----------------------------------------------------------------
-  */
-  *kout = 0;
-  ik    = kin;
-  idec  = 1;
+      /*  Closest number in GRIB format less than original number. */
+      /*  Truncate for positive numbers. */
+      /*  Round up for negative numbers. */
 
-  for ( j = 0; j < knbit; j++ )
-    {
-      itemp = ik - ( (ik/2)*2 );
-      *kout = (*kout) + itemp * idec;
-      ik    = ik / 2;
-      idec  = idec * 10;
+      if ( isign == 0 )
+	*kmant = (int)rpowref;
+      else
+	*kmant = (int)lround(rpowref + 0.5);
     }
+    else
+    {
+      /*  Closest number in GRIB format to the original number   */
+      /*  (equal to, greater than or less than original number). */
 
-  return;
-}
-
-
-void ref2ibm(double *pref, int kbits)
-{
-  /*
-
-    Purpose:
-    --------
-
-    Code and check reference value in IBM format
-
-    Input Parameters:
-    -----------------
-
-    pref       - Reference value
-    kbits      - Number of bits per computer word.
+      *kmant = (int)lround(rpowref);
+    }
 
-    Output Parameters:
-    ------------------
+    /*  Check that mantissa value does not exceed 24 bits. */
+    /*  If it does, adjust the exponent upwards and recalculate */
+    /*  the mantissa. */
+    /*  16777215 = 2**24 - 1 */
 
-    pref       - Reference value
+    if ( *kmant > 16777215 )
+    {
 
-    Method:
-    -------
+    LABEL350:
 
-    Codes in IBM format, then decides to ensure that reference 
-    value used for packing is not different from that stored
-    because of packing differences.
+      ++iexp;
 
-    Externals.
-    ----------
+      /*  Check for exponent overflow during adjustment  */
 
-    confp3    - Encode into IBM floating point format.
-    decfp2    - Decode from IBM floating point format.
+      if ( iexp > 127 )
+      {
+        Message("Exponent overflow");
+        Message("Original number = %30.20f", pval);
+        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
+                isign, iexp, *kmant);
 
-    Reference:
-    ----------
+        Error("Exponent overflow");
 
-    None.
+        /*  If not aborting, arbitrarily set value to zero  */
 
-    Comments:
-    --------
+        Message("Value arbitrarily set to zero.");
+        *kexp  = 0;
+        *kmant = 0;
+        // iexp  = 0;
+        // isign = 0;
+        goto LABEL900;
+      }
 
-    None.
+      rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-    Author:
-    -------
+      if ( iround == 0 )
+      {
+        /*  Closest number in GRIB format less than original number. */
+        /*  Truncate for positive numbers. */
+        /*  Round up for negative numbers. */
 
-    J.D.Chambers     ECMWF      17:05:94
+        if ( isign == 0 )
+          *kmant = (int)rpowref;
+        else
+          *kmant = (int)lround(rpowref + 0.5);
+      }
+      else
+      {
+        /*  Closest number in GRIB format to the original number */
+        /*  (equal to, greater or less than original number). */
 
-    Modifications:
-    --------------
+        *kmant = (int)lround(rpowref);
+      }
 
-    Uwe Schulzweida   MPIfM   01/04/2001
+      /*  Repeat calculation (with modified exponent) if still have */
+      /*  mantissa overflow. */
 
-    Convert to C from EMOS library version 130
+      if ( *kmant > 16777215 ) goto LABEL350;
+    }
 
-  */
+    /*  Add sign bit to exponent. */
 
-  static int itrnd;
-  static int kexp, kmant;
-  static double ztemp, zdumm;
-  extern int CGRIBEX_Debug;
+    *kexp = iexp + isign;
+  }
 
   /* ----------------------------------------------------------------- */
-  /*   Section 1. Convert to and from IBM format.                      */
+  /*   Section 9. Return                                               */
   /* ----------------------------------------------------------------- */
 
-  /*  Convert floating point reference value to IBM representation. */
-
-  itrnd = 1;
-  zdumm = ztemp = *pref;
-  confp3(zdumm, &kexp, &kmant, kbits, itrnd);
-
-  if ( kexp == 0 && kmant == 0 ) return;
-
-  /*  Set reference value to that actually stored in the GRIB code. */
-
-  *pref = decfp2(kexp, kmant);
-
-  /*  If the nearest number which can be represented in */
-  /*  GRIB format is greater than the reference value,  */
-  /*  find the nearest number in GRIB format lower      */
-  /*  than the reference value.                         */
-
-  if ( ztemp < *pref )
+LABEL900:
+  /*
+  if ( CGRIBEX_Debug )
     {
-      /*  Convert floating point to GRIB representation */
-      /*  using truncation to ensure that the converted */
-      /*  number is smaller than the original one.      */
-
-      itrnd = 0;
-      zdumm = *pref = ztemp;
-      confp3(zdumm, &kexp, &kmant, kbits, itrnd);
+      double zval;
 
-      /*  Set reference value to that stored in the GRIB code. */
+      Message("Conversion type parameter = %4d", kround);
+      Message("Original number = %30.20f", pval);
 
-      *pref = decfp2(kexp, kmant);
+      zval = decfp2(*kexp, *kmant);
 
-      if ( ztemp < *pref )
-	{
-	  if ( CGRIBEX_Debug )
-	    {
-	      Message("Reference value error.");
-	      Message("Notify Met.Applications Section.");
-	      Message("ZTEMP = ", ztemp);
-	      Message("PREF = ", pref);
-	    }
-	  *pref = ztemp;
-	}
+      Message("Converted to      %30.20f", zval);
+      Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
     }
-
+  */
   return;
-} /* ref2ibm */
+} /* confp3 */
 #include <math.h>
-#include <string.h>
 
 
-int correct_bdslen(int bdslen, long recsize, long gribpos)
+double decfp2(int kexp, int kmant)
 {
   /*
-    If a very large product, the section 4 length field holds
-    the number of bytes in the product after section 4 upto
-    the end of the padding bytes.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  if ( recsize > JP23SET ) bdslen = (int)(recsize - gribpos - bdslen);
-  return (bdslen);
-}
-
-
-int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
-		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize)
-{
-  unsigned char *pds, *gds, *bms, *bds;
-  unsigned char *bufpointer, *is, *section;
-  int gribversion, grib1offset;
-  long gribsize = 0, recsize;
-  int bdslen;
-
-  *gribrecsize = 0;
-  *pdsp = NULL;
-  *gdsp = NULL;
-  *bmsp = NULL;
-  *bdsp = NULL;
-
-  section = gribbuffer;
-  is = gribbuffer;
-  if ( ! GRIB_START(section) )
-    {
-      fprintf(stderr, "Wrong GRIB indicator section: found >%c%c%c%c<\n",
-	      section[0], section[1], section[2], section[3]);
-      return (-1);
-    }
-
-  recsize = gribrec_len(section[4], section[5], section[6]);
-
-  gribversion = GRIB_EDITION(section);
-  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
-
-  if ( gribversion == 1 )
-    grib1offset = 4;
-  else
-    grib1offset = 0;
-
-  pds = is + 4 + grib1offset;
-  bufpointer = pds + PDS_Len;
-  gribsize += 4 + grib1offset + PDS_Len;
-
-  if ( PDS_HAS_GDS )
-    {
-      gds = bufpointer;
-      bufpointer += GDS_Len;
-      gribsize += GDS_Len;
-    }
-  else
-    {
-      gds = NULL;
-    }
-
-  if ( PDS_HAS_BMS )
-    {
-      bms = bufpointer;
-      bufpointer += BMS_Len;
-      gribsize += BMS_Len;
-    }
-  else
-    {
-      bms = NULL;
-    }
-
-  bds = bufpointer;
-  bdslen = BDS_Len;
-  bdslen = correct_bdslen(bdslen, recsize, gribsize);
-  bufpointer += bdslen;
-  gribsize += bdslen;
-  gribsize += 4;
-
-  *pdsp = pds;
-  *gdsp = gds;
-  *bmsp = bms;
-  *bdsp = bds;
-
-  *gribrecsize = gribsize;
-
-  if ( gribbufsize < gribsize )
-    {
-      fprintf(stderr, "Length of GRIB message is inconsistent (grib_buffer_size=%ld < grib_record_size=%ld)!\n", gribbufsize, gribsize);
-      return (1);
-    }
 
-  /* end section - "7777" in ascii */
-  if ( !GRIB_FIN(bufpointer) )
-    {
-      fprintf(stderr, "Missing GRIB end section: found >%c%c%c%c<\n",
-	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
-      return (-2);
-    }
+    Purpose:
+    --------
 
-  return (0);
-}
+    Convert GRIB representation of a floating point
+    number to machine representation.
 
+    Input Parameters:
+    -----------------
 
-int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
-		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
-		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp)
-{
-  unsigned char *section;
-  long sec_len;
-  int sec_num;
-  int gribversion;
-  int i, msec;
-  long gribsize;
-  long grib_len = 0;
+    kexp    - 8 Bit signed exponent.
+    kmant   - 24 Bit mantissa.
 
-  UNUSED(gribbufsize);
+    Output Parameters:
+    ------------------
 
-  *idsp = NULL;
-  *lusp = NULL;
-  *gdsp = NULL;
-  *pdsp = NULL;
-  *drsp = NULL;
-  *bmsp = NULL;
-  *bdsp = NULL;
+    Return value   - Floating point number represented
+                     by kexp and kmant.
 
-  section = gribbuffer;
-  sec_len = 16;
+    Method:
+    -------
 
-  if ( !GRIB_START(section) )
-    {
-      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
-	      section[0], section[1], section[2], section[3]);
-      return (-1);
-    }
+    Floating point number represented as 8 bit exponent
+    and 24 bit mantissa in integer values converted to
+    machine floating point format.
 
-  gribversion = GRIB_EDITION(section);
-  if ( gribversion != 2 )
-    {
-      fprintf(stderr, "wrong GRIB version %d\n", gribversion);
-      return (-1);      
-    }
+    Externals:
+    ----------
 
-  gribsize = 0;
-  for ( i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | section[8+i];
+    None.
 
-  grib_len += sec_len;
-  section  += sec_len;
+    Reference:
+    ----------
 
-  /* section 1 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "ids %d %ld\n", sec_num, sec_len);
+    WMO Manual on Codes re GRIB representation.
 
-  if ( sec_num != 1 )
-    {
-      fprintf(stderr, "Unexpected section1 number %d\n", sec_num);
-      return (-1);
-    }
+    Comments:
+    ---------
 
-  *idsp = section;
+    Rewritten from DECFP, to conform to programming standards.
+    Sign bit on 0 value now ignored, if present.
+    If using 32 bit reals, check power of 16 is not so small as to
+    cause overflows (underflows!); this causes warning to be given
+    on Fujitsus.
 
-  grib_len += sec_len;
-  section  += sec_len;
+    Author:
+    -------
 
-  /* section 2 and 3 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "lus %d %ld\n", sec_num, sec_len);
+    John Hennessy   ECMWF   18.06.91
 
-  if ( sec_num == 2 )
-    {
-      *lusp = section;
+    Modifications:
+    --------------
 
-      grib_len += sec_len;
-      section  += sec_len;
+    Uwe Schulzweida   MPIfM   01/04/2001
 
-      /* section 3 */
-      sec_len = GRIB2_SECLEN(section);
-      //sec_num = GRIB2_SECNUM(section);
-      //fprintf(stderr, "gds %d %ld\n", sec_num, sec_len);
+     - Convert to C from EMOS library version 130
 
-      *gdsp = section;
-    }
-  else if ( sec_num == 3 )
-    {
-      *gdsp = section;
-    }
-  else
-    {
-      fprintf(stderr, "Unexpected section3 number %d\n", sec_num);
-      return (-1);
-    }
+    Uwe Schulzweida   MPIfM   02/08/2002
 
-  grib_len += sec_len;
-  section  += sec_len;
+     - speed up by factor 2 on NEC SX6
+        - replace pow(2.0, -24.0) by constant POW_2_M24
+        - replace pow(16.0, (double)(iexp - 64)) by pow16m64tab[iexp]
+  */
 
-  /* section 4 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "pds %d %ld\n", sec_num, sec_len);
+  /* ----------------------------------------------------------------- */
+  /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
+  /* ----------------------------------------------------------------- */
 
-  if ( sec_num != 4 )
-    {
-      fprintf(stderr, "Unexpected section4 number %d\n", sec_num);
-      return (-1);
-    }
+  if ( (kexp == 128) || (kexp == 0) || (kexp == 255) ) return 0.0;
 
-  *pdsp = section;
+  /* ----------------------------------------------------------------- */
+  /*   Section 2 . Convert other values.                               */
+  /* ----------------------------------------------------------------- */
 
-  grib_len += sec_len;
-  section  += sec_len;
+  /*  Sign of value. */
 
-  /* section 5 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "drs %d %ld\n", sec_num, sec_len);
+  int iexp = kexp,
+    isign = (iexp < 128) * 2 - 1;
 
-  if ( sec_num != 5 )
-    {
-      fprintf(stderr, "Unexpected section5 number %d\n", sec_num);
-      return (-1);
-    }
+  iexp -= iexp < 128 ? 0 : 128;
 
-  *drsp = section;
+  /*  Decode value. */
 
-  grib_len += sec_len;
-  section  += sec_len;
+  /* pval = isign * pow(2.0, -24.0) * kmant * pow(16.0, (double)(iexp - 64)); */
 
-  /* section 6 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "bms %d %ld\n", sec_num, sec_len);
+  iexp -= 64;
 
-  if ( sec_num != 6 )
-    {
-      fprintf(stderr, "Unexpected section6 number %d\n", sec_num);
-      return (-1);
-    }
+  double pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
 
-  *bmsp = section;
+  /* ----------------------------------------------------------------- */
+  /*   Section 9. Return to calling routine.                           */
+  /* ----------------------------------------------------------------- */
 
-  grib_len += sec_len;
-  section  += sec_len;
+  return pval;
+} /* decfp2 */
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
 
-  /* section 7 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "bds %d %ld\n", sec_num, sec_len);
 
-  if ( sec_num != 7 )
-    {
-      fprintf(stderr, "Unexpected section7 number %d\n", sec_num);
-      return (-1);
-    }
 
-  *bdsp = section;
+int gribRefDate(int *isec1)
+{
+  int century = ISEC1_Century;
+  if ( century < 0 ) century = -century;
+  century -= 1;
 
-  grib_len += sec_len;
-  section  += sec_len;
+  int ryear   = ISEC1_Year;
 
-  /* skip multi GRIB sections */
-  msec = 1;
-  while ( !GRIB_FIN(section) )
+  /* if ( century != 0 ) */
     {
-      sec_len = GRIB2_SECLEN(section);
-      sec_num = GRIB2_SECNUM(section);
+      if ( ryear == 100 )
+	{
+	  ryear = 0;
+	  century += 1;
+	}
 
-      if ( sec_num < 1 || sec_num > 7 ) break;
+      if ( ryear != 255 )
+	{
+	  ryear = century*100 + ryear;
+	  if ( ISEC1_Century < 0 ) ryear = -ryear;
+	}
+      else
+	ryear = 1;
+    }
 
-      if ( sec_num == 7 )
-	fprintf(stderr, "Skipped unsupported multi GRIB section %d!\n", ++msec);
+  int rmonth  = ISEC1_Month;
+  int rday    = ISEC1_Day;
 
-      if ( (grib_len + sec_len) > gribsize ) break;
+  int date = cdiEncodeDate(ryear, rmonth, rday);
 
-      grib_len += sec_len;
-      section  += sec_len;
-    }
+  return date ;
+}
 
-  /* end section - "7777" in ASCII */
-  if ( !GRIB_FIN(section) )
-    {
-      fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
-	      section[0], section[1], section[2], section[3]);
-      return (-2);
-    }
 
-  return (0);
+int gribRefTime(int *isec1)
+{
+  int rhour   = ISEC1_Hour;
+  int rminute = ISEC1_Minute;
+
+  int time = cdiEncodeTime(rhour, rminute, 0);
+
+  return time;
 }
 
 
-int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
-			int *intnum, float *fltnum, off_t *bignum)
+bool gribTimeIsFC(int *isec1)
 {
-  unsigned char *pds, *gds, *bms, *bds;
-  unsigned char *bufpointer, *is, *section;
-  int gribversion, grib1offset;
-  long gribsize = 0;
-  off_t dpos, bpos = 0;
-  int bdslen;
-  float bsf;
+  bool isFC = false;
 
-  section = gribbuffer;
-  is = gribbuffer;
-  if ( ! GRIB_START(section) )
+  int time_period =  (ISEC1_TimeRange == 10) ? (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2 : ISEC1_TimePeriod1;
+
+  if ( time_period > 0 && ISEC1_Day > 0 )
     {
-      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
-	      section[0], section[1], section[2], section[3]);
-      return (-1);
+      if ( ISEC1_TimeRange == 0 || ISEC1_TimeRange == 10 ) isFC = true;
     }
 
-  gribversion = GRIB_EDITION(section);
-  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
+  return isFC;
+}
 
-  if ( gribversion == 1 )
-    grib1offset = 4;
-  else
-    grib1offset = 0;
 
-  pds = is + 4 + grib1offset;
-  bufpointer = pds + PDS_Len;
-  gribsize += 4 + grib1offset + PDS_Len;
+void gribDateTime(int *isec1, int *date, int *time)
+{
+  static bool lprint = true;
+  int julday, secofday;
+  int64_t addsec = 0;
+  int64_t time_period = 0;
+  extern int grib_calendar;
 
-  if ( PDS_HAS_GDS )
+  int century = ISEC1_Century;
+  int ryear   = ISEC1_Year;
+
+  if ( century == -255 && ryear == 127 )
     {
-      gds = bufpointer;
-      bufpointer += GDS_Len;
-      gribsize += GDS_Len;
+      century = 0;
+      ryear = 0;
     }
   else
     {
-      gds = NULL;
-    }
-
-  if ( PDS_HAS_BMS )
-    {
-      bms = bufpointer;
-      bufpointer += BMS_Len;
+      if ( century < 0 ) century = -century;
+      century -= 1;
 
-      bpos = recpos + gribsize + 6;
+      /* if ( century != 0 ) */
+      {
+        if ( ryear == 100 )
+          {
+            ryear = 0;
+            century += 1;
+          }
 
-      gribsize += BMS_Len;
-    }
-  else
-    {
-      bms = NULL;
+        if ( ryear != 255 )
+          {
+            ryear = century*100 + ryear;
+            if ( ISEC1_Century < 0 ) ryear = -ryear;
+          }
+        else
+          ryear = 1;
+      }
     }
 
-  bds = bufpointer;
+  int rmonth  = ISEC1_Month;
+  int rday    = ISEC1_Day;
 
-  dpos = recpos + gribsize + 11;
+  int rhour   = ISEC1_Hour;
+  int rminute = ISEC1_Minute;
+  int second  = 0;
 
-  bdslen = BDS_Len;
-  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
-  bufpointer += bdslen;
-  gribsize += bdslen;
-  gribsize += 4;
+  /* printf("ref %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute); */
 
-  if ( gribsize > recsize )
-    {
-      fprintf(stderr, "GRIB buffer size %ld too small! Min size = %ld\n", recsize, gribsize);
-      return (1);
-    }
+  if ( ISEC1_TimeRange == 10 )
+    time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
+  else if ( ISEC1_TimeRange >=2 && ISEC1_TimeRange <= 5 )
+    time_period = ISEC1_TimePeriod2;
+  else if ( ISEC1_TimeRange == 0 )
+    time_period = ISEC1_TimePeriod1;
 
-  /* end section - "7777" in ascii */
-  if ( !GRIB_FIN(bufpointer) )
+  if ( time_period > 0 && rday > 0 )
     {
-      fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
-	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
-    }
+      encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, second, &julday, &secofday);
 
-  {
-    int bs = BDS_BinScale;
-    if ( bs > 32767 ) bs = 32768-bs;
-    bsf = ldexpf(1.0f, bs);
-  }
+      addsec = 0;
+      switch ( ISEC1_TimeUnit )
+	{
+	case ISEC1_TABLE4_MINUTE:    addsec =    60 * time_period; break;
+	case ISEC1_TABLE4_QUARTER:   addsec =   900 * time_period; break;
+	case ISEC1_TABLE4_30MINUTES: addsec =  1800 * time_period; break;
+	case ISEC1_TABLE4_HOUR:      addsec =  3600 * time_period; break;
+	case ISEC1_TABLE4_3HOURS:    addsec = 10800 * time_period; break;
+	case ISEC1_TABLE4_6HOURS:    addsec = 21600 * time_period; break;
+	case ISEC1_TABLE4_12HOURS:   addsec = 43200 * time_period; break;
+	case ISEC1_TABLE4_DAY:       addsec = 86400 * time_period; break;
+	default:
+	  if ( lprint )
+	    {
+	      gprintf(__func__, "Time unit %d unsupported", ISEC1_TimeUnit);
+	      lprint = false;
+	    }
+	  break;
+	}
 
-  bignum[0] = dpos;
-  bignum[1] = bms ? bpos : -999;
-  intnum[0] = BDS_NumBits;
+      julday_add_seconds(addsec, &julday, &secofday);
 
-  /*  fltnum[0] = 1.0; */
-  fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
-  fltnum[1] = bsf;
-  fltnum[2] = (float)BDS_RefValue;
+      decode_caldaysec(grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &second);
+    }
   /*
-  printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
-  printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
+  printf("new %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute);
   */
-  return (0);
+  *date = cdiEncodeDate(ryear, rmonth, rday);
+  *time = cdiEncodeTime(rhour, rminute, 0);
+
+  return;
 }
 
 
-void grib1PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+void gprintf(const char *caller, const char *fmt, ...)
 {
-  static int header = 1;
-  int GridType, level, nerr;
-  unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  double cr = 1;
-  int bdslen;
-  int llarge = 0;
+  va_list args;
 
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : Off Position   Size : V PDS  GDS    BMS    BDS : Code Level :  LType GType: CR LL\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
+  if ( grprsm == NULL ) Error("GRIBEX initialization missing!");
+	
+  va_start(args, fmt);
 
-  is = gribbuffer;
+   fprintf(grprsm, "%-18s : ", caller);
+  vfprintf(grprsm, fmt, args);
+   fprintf(grprsm, "\n");
 
-  if ( gribrec_len(is[4], is[5], is[6]) > JP23SET ) llarge = 1;
+  va_end(args);
+}
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+
+void
+gribExDP(int *isec0, int *isec1, int *isec2, double *fsec2, int *isec3,
+	 double *fsec3, int *isec4, double *fsec4, int klenp, int *kgrib,
+	 int kleng, int *kword, const char *hoper, int *kret)
+{
+  int yfunc = *hoper;
+
+  if ( yfunc == 'C' )
     {
-      fprintf(stdout, "%5d :%4ld %8ld %6ld : GRIB message error\n", nrec, offset, recpos, recsize);
-      return;
+      grib_encode_double(isec0, isec1, isec2, fsec2, isec3,
+			 fsec3, isec4, fsec4, klenp, kgrib,
+			 kleng, kword, yfunc, kret);
+    }
+  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
+    {
+      grib_decode_double(isec0, isec1, isec2, fsec2, isec3,
+			 fsec3, isec4, fsec4, klenp, kgrib,
+			 kleng, kword, yfunc, kret);
+    }
+  else if ( yfunc == 'V' )
+    {
+      fprintf(stderr, "  cgribex: Version is %s\n", cgribexLibraryVersion());
     }
-
-  if ( gds == NULL )
-    GridType = -1;
   else
-    GridType = GDS_GridType;
+    {
+      Error("oper %c unsupported!", yfunc);
+      *kret=-9;
+    }
+}
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else if ( PDS_LevelType == 109 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
 
-  bdslen = BDS_Len;
-  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
+void
+gribExSP(int *isec0, int *isec1, int *isec2, float *fsec2, int *isec3,
+	 float *fsec3, int *isec4, float *fsec4, int klenp, int *kgrib,
+	 int kleng, int *kword, const char *hoper, int *kret)
+{
+  int yfunc = *hoper;
 
-  if ( ((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130) )
+  if ( yfunc == 'C' )
+    {
+      grib_encode_float(isec0, isec1, isec2, fsec2, isec3,
+			fsec3, isec4, fsec4, klenp, kgrib,
+			kleng, kword, yfunc, kret);
+    }
+  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
+    {
+      grib_decode_float(isec0, isec1, isec2, fsec2, isec3,
+			fsec3, isec4, fsec4, klenp, kgrib,
+			kleng, kword, yfunc, kret);
+    }
+  else if ( yfunc == 'V' )
+    {
+      fprintf(stderr, " cgribex: Version is %s\n", cgribexLibraryVersion());
+    }
+  else
     {
-      int s1, s2;
-      s1 = gribrec_len(bds[14], bds[15], bds[16]);
-      s2 = gribrec_len(gribbuffer[4], gribbuffer[5], gribbuffer[6]);
-      cr = ((double)s1)/s2;
+      Error("oper %c unsupported!", yfunc);
+      *kret=-9;
     }
+}
 
-  fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d%4d%5d %6d %6d : %3d %6d : %5d %5d %6.4g  %c",
-	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
-	  PDS_Len, GDS_Len, BMS_Len, bdslen,
-	  PDS_Parameter, level, PDS_LevelType, GridType, cr, llarge?'T':'F');
+int CGRIBEX_Fix_ZSE  = 0;    /* 1: Fix ZeroShiftError of simple packed spherical harmonics */
+int CGRIBEX_Const    = 0;    /* 1: Don't pack constant fields on regular grids */
+int CGRIBEX_Debug    = 0;    /* 1: Debugging */
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
+void gribSetDebug(int debug)
+{
+  CGRIBEX_Debug = debug;
+
+  if ( CGRIBEX_Debug )
+    Message("debug level %d", debug);
 }
 
 
-void grib2PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+void gribFixZSE(int flag)
 {
-  static int header = 1;
-  int nerr;
-  unsigned char *is  = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  unsigned char *ids = NULL, *lus = NULL, *drs = NULL;
-  long ids_len = 0, lus_len = 0, gds_len = 0, pds_len = 0, drs_len = 0, bms_len = 0, bds_len = 0;
-  int gridtype, paramnum, level1type /*, level2type*/;
-  int level1 /*, level1sf*/;
-  /* int level2, level2sf; */
-  double cr = 1;
+  CGRIBEX_Fix_ZSE = flag;
 
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : Off Position   Size : V IDS LUS GDS PDS  DRS    BMS    BDS : Code Level :  LType GType: CR\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
+  if ( CGRIBEX_Debug )
+    Message("Fix ZeroShiftError set to %d", flag);
+}
 
-  is = gribbuffer;
 
-  nerr = grib2Sections(gribbuffer, recsize, &ids, &lus, &gds, &pds, &drs, &bms, &bds);
-  if ( nerr )
-    {
-      fprintf(stdout, "%5d :%4ld %8ld %6ld : error\n", nrec, offset, recpos, recsize);
-      return;
-    }
+void gribSetConst(int flag)
+{
+  CGRIBEX_Const = flag;
 
-  if ( ids ) ids_len = GRIB2_SECLEN(ids);
-  if ( lus ) lus_len = GRIB2_SECLEN(lus);
-  if ( gds ) gds_len = GRIB2_SECLEN(gds);
-  if ( pds ) pds_len = GRIB2_SECLEN(pds);
-  if ( drs ) drs_len = GRIB2_SECLEN(drs);
-  if ( bms ) bms_len = GRIB2_SECLEN(bms);
-  if ( bds ) bds_len = GRIB2_SECLEN(bds);
+  if ( CGRIBEX_Debug )
+    Message("Const set to %d", flag);
+}
 
-  /*
-  if ( (BDS_Flag >> 4)&1 && BDS_Z == 128 )
-    {
-      int s1, s2;
-      s1 = ((int) ((bds[14]<<16)+(bds[15]<<8)+bds[16]));
-      s2 = ((int) ((gribbuffer[4]<<16)+(gribbuffer[5]<<8)+gribbuffer[6]));
-      cr = ((double)s1)/s2;
-    }
-  */
-  gridtype   = GET_UINT2(gds[12],gds[13]);
-  paramnum   = GET_UINT1(pds[10]);
-  level1type = GET_UINT1(pds[22]);
-  /* level1sf   = GET_UINT1(pds[23]); */
-  level1     = GET_UINT4(pds[24],pds[25],pds[26],pds[27]);
-  /* level2type = GET_UINT1(pds[28]); */
-  /* level2sf   = GET_UINT1(pds[29]); */
-  /* level2     = GET_UINT4(pds[30],pds[31],pds[32],pds[33]); */
-  /*
-  printf("level %d %d %d %d %d %d %d\n", level1type, level1sf, level1, level1*level1sf, level2sf, level2, level2*level2sf);
-  */
-  fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d %3ld %3ld %3ld %3ld %4ld %6ld %6ld : %3d%7d : %5d %5d %6.4g\n",
-	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
-	  ids_len, lus_len, gds_len, pds_len, drs_len, bms_len, bds_len,
-	  paramnum, level1, level1type, gridtype, cr);
+
+void gribSetRound(int round)
+{
+  UNUSED(round);
 }
 
 
-void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+void gribSetRefDP(double refval)
 {
-  int gribversion;
+  UNUSED(refval);
+}
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintALL(nrec, offset, recpos, recsize, gribbuffer);
-  else if ( gribversion == 2 )
-    grib2PrintALL(nrec, offset, recpos, recsize, gribbuffer);
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, offset, recpos, recsize, gribversion); 
-    }
+void gribSetRefSP(float refval)
+{
+  gribSetRefDP((double) refval);
 }
 
 
-void grib1PrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+void gribSetValueCheck(int vcheck)
 {
-  static int header = 1;
-  unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int century, subcenter, decimalscale, nerr;
-  int fc_num = 0;
-  int year = 0, date;
+  UNUSED(vcheck);
+}
+#include <string.h>
+#include <math.h>
 
-  UNUSED(recpos);
 
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : PDS Tab Cen Sub Ver Grid Code LTyp Level1 Level2    Date  Time P1 P2 TU TR NAVE Scale FCnum CT\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
 
-  is = gribbuffer;
+void gribPrintSec0(int *isec0)
+{
+  /*
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
+    Print the information in the Indicator
+    Section (Section 0) of decoded GRIB data.
 
-  switch(GRIB_EDITION(is))
-    {   
-    case 0:
-      year                = GET_UINT1(pds[12]);
-      century             = 1;
-      subcenter           = 0;
-      decimalscale        = 0;
-      break;
-    case 1:
-      year                = PDS_Year;
-      century             = PDS_Century;
-      subcenter           = PDS_Subcenter;
-      decimalscale        = PDS_DecimalScale;
-      break;
-    default:
-      fprintf(stderr, "Grib version %d not supported!", GRIB_EDITION(is));
-      exit(EXIT_FAILURE);
-    }
+    Input Parameters:
 
-  if ( PDS_Len > 28 )
-    if ( PDS_CenterID    == 98 || PDS_Subcenter == 98 ||
-	(PDS_CenterID    ==  7 && PDS_Subcenter == 98) )
-      if ( pds[40] == 1 )
-	fc_num = GET_UINT1(pds[49]);
+       isec0 - Array of decoded integers from Section 0
 
-  if ( year < 0 )
-    {
-      date = (-year)*10000+PDS_Month*100+PDS_Day;
-      century = -century;
-    }
-  else
-    {
-      date =    year*10000+PDS_Month*100+PDS_Day;
-    }
-      
-  fprintf(stdout, "%5d :%4d%4d%4d%4d%4d %4d %4d%4d%7d%7d %8d%6d%3d%3d%3d%3d%5d%6d%5d%4d", nrec,
-	  PDS_Len,  PDS_CodeTable,   PDS_CenterID, subcenter, PDS_ModelID,
-	  PDS_GridDefinition, PDS_Parameter, PDS_LevelType, PDS_Level1, PDS_Level2,
-	  date, PDS_Time, PDS_TimePeriod1, PDS_TimePeriod2, PDS_TimeUnit, PDS_TimeRange,
-	  PDS_AvgNum, decimalscale, fc_num, century);
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+    Converted from EMOS routine GRPRS0.
 
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+  */
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  grsdef();
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintPDS(nrec, recpos, recsize, gribbuffer);
-  /*
-  else if ( gribversion == 2 )
-    grib2PrintPDS(nrec, recpos, recsize, gribbuffer);
-  */
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
-    }
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 0 - Indicator Section.       \n");
+  fprintf(grprsm, " -------------------------------------\n");
+  fprintf(grprsm, " Length of GRIB message (octets).     %9d\n", ISEC0_GRIB_Len);
+  fprintf(grprsm, " GRIB Edition Number.                 %9d\n", ISEC0_GRIB_Version);
 }
 
-
-void grib1PrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+void gribPrintSec1(int *isec0, int *isec1)
 {
-  static int header = 1;
-  int nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  /*
 
-  UNUSED(recpos);
+    Print the information in the Product Definition
+    Section (Section 1) of decoded GRIB data.
 
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : GDS  NV PVPL Typ : xsize ysize   Lat1   Lon1   Lat2   Lon2    dx    dy\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
+    Input Parameters:
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
+       isec0 - Array of decoded integers from Section 0
 
-  fprintf(stdout, "%5d :", nrec);
+       isec1 - Array of decoded integers from Section 1
 
-  if ( gds )
-    fprintf(stdout, "%4d%4d%4d %4d :%6d%6d%7d%7d%7d%7d%6d%6d",
-	    GDS_Len,  GDS_NV,   GDS_PVPL, GDS_GridType,
-	    GDS_NumLon,   GDS_NumLat,
-	    GDS_FirstLat, GDS_FirstLon,
-	    GDS_LastLat,  GDS_LastLon,
-	    GDS_LonIncr,  GDS_LatIncr);
-  else
-    fprintf(stdout, " Grid Description Section not defined");
+    Comments:
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+       When decoding data from Experimental Edition or Edition 0,
+       routine GRIBEX adds the additional fields available in
+       Edition 1.
 
 
-void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+    Converted from EMOS routine GRPRS1.
+
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  */
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
+  int iprev, icurr, ioffset;
+  int ibit, ierr, iout, iyear;
+  int jloop, jiloop;
+  float value;
+
+  char hversion[9];
   /*
-  else if ( gribversion == 2 )
-    grib2PrintGDS(nrec, recpos, recsize, gribbuffer);
+  char hfirst[121], hsecond[121], hthird[121], hfourth[121];
   */
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
-    }
-}
 
+  grsdef();
 
-void grib1PrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  static int header = 1;
-  int level, nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  /*
+    -----------------------------------------------------------------
+    Section 0 . Print required information.
+    -----------------------------------------------------------------
+  */
 
-  UNUSED(recpos);
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 1 - Product Definition Section.\n");
+  fprintf(grprsm, " ---------------------------------------\n");
 
-  if ( header )
+  fprintf(grprsm, " Code Table 2 Version Number.         %9d\n", isec1[0]);
+  fprintf(grprsm, " Originating centre identifier.       %9d\n", isec1[1]);
+  fprintf(grprsm, " Model identification.                %9d\n", isec1[2]);
+  fprintf(grprsm, " Grid definition.                     %9d\n", isec1[3]);
+
+  ibit = 8;
+  prtbin(isec1[4], ibit, &iout, &ierr);
+  fprintf(grprsm, " Flag (Code Table 1)                   %8.8d\n", iout);
+  fprintf(grprsm, " Parameter identifier (Code Table 2). %9d\n", isec1[5]);
+
+  /*
+      IERR = CHKTAB2(ISEC1,HFIRST,HSECOND,HTHIRD,HFOURTH)
+      IF( IERR .EQ. 0 ) THEN
+       DO JLOOP = 121, 1, -1
+          IF( HSECOND(JLOOP:JLOOP).NE.' ' ) THEN
+            IOFFSET = JLOOP
+            GOTO 110
+          ENDIF
+        ENDDO
+        GOTO 120
+ 110    CONTINUE
+        WRITE(*,'(2H ",A,1H")') HSECOND(1:IOFFSET)
+ 120    CONTINUE
+      ENDIF
+  */
+
+  if ( isec1[5] != 127 )
     {
-      fprintf(stdout, 
-      "  Rec : Code Level     BMS    Size\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
+      fprintf(grprsm, " Type of level (Code Table 3).        %9d\n", isec1[6]);
+      fprintf(grprsm, " Value 1 of level (Code Table 3).     %9d\n", isec1[7]);
+      fprintf(grprsm, " Value 2 of level (Code Table 3).     %9d\n", isec1[8]);
     }
-
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+  else
     {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
+      fprintf(grprsm, " Satellite identifier.                %9d\n", isec1[6]);
+      fprintf(grprsm, " Spectral band.                       %9d\n", isec1[7]);
     }
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
+  iyear = isec1[9];
+  if ( iyear != 255 )
+    {
+      int date, time;
+      /* iyear  = ((isec1[20]-1)*100 + isec1[9]); */
+      gribDateTime(isec1, &date, &time);
+      iyear = date/10000;
+      fprintf(grprsm, " Year of reference time of data.      %9d  (%4d)\n", isec1[9], iyear);
+    }
   else
-    level = PDS_Level1;
-
-  fprintf(stdout, "%5d :", nrec);
+    {
+      fprintf(grprsm, " Year of reference time of data MISSING  (=255)\n");
+    }
 
-  if ( bms )
-    fprintf(stdout, "%4d%7d %7d %7d",
-	    PDS_Parameter, level,
-	    BMS_Len, BMS_BitmapSize);
+  fprintf(grprsm, " Month of reference time of data.     %9d\n", isec1[10]);
+  fprintf(grprsm, " Day of reference time of data.       %9d\n", isec1[11]);
+  fprintf(grprsm, " Hour of reference time of data.      %9d\n", isec1[12]);
+  fprintf(grprsm, " Minute of reference time of data.    %9d\n", isec1[13]);
+  fprintf(grprsm, " Time unit (Code Table 4).            %9d\n", isec1[14]);
+  fprintf(grprsm, " Time range one.                      %9d\n", isec1[15]);
+  fprintf(grprsm, " Time range two.                      %9d\n", isec1[16]);
+  fprintf(grprsm, " Time range indicator (Code Table 5)  %9d\n", isec1[17]);
+  fprintf(grprsm, " Number averaged.                     %9d\n", isec1[18]);
+  fprintf(grprsm, " Number missing from average.         %9d\n", isec1[19]);
+  /*
+     All ECMWF data in GRIB Editions before Edition 1 is decoded
+     as 20th century data. Other centres are decoded as missing.
+  */
+  if ( isec0[1] < 1 && isec1[1] != 98 )
+    fprintf(grprsm, " Century of reference time of data.   Not given\n");
   else
-    fprintf(stdout, "%4d%7d Bit Map Section not defined", PDS_Parameter, level);
+    fprintf(grprsm, " Century of reference time of data.   %9d\n", isec1[20]);
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+  /*   Print sub-centre  */
+  fprintf(grprsm, " Sub-centre identifier.               %9d\n", ISEC1_SubCenterID);
 
+  /*   Decimal scale factor  */
+  fprintf(grprsm, " Units decimal scaling factor.        %9d\n", isec1[22]);
 
-void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print local DWD information.
+    -----------------------------------------------------------------
+  */
+  if ( (ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250) &&
+       (isec1[36] == 253     || isec1[36] == 254) )
+    {
+      fprintf(grprsm, " DWD local usage identifier.          %9d\n", isec1[36]);
+      if ( isec1[36] == 253 )
+	fprintf(grprsm, " (Database labelling and ensemble forecast)\n");
+      if ( isec1[36] == 254 )
+	fprintf(grprsm, " (Database labelling)\n");
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+      fprintf(grprsm, " Year of database entry                     %3d  (%4d)\n", isec1[43], 1900+isec1[43]);
+      fprintf(grprsm, " Month of database entry                    %3d\n", isec1[44]);
+      fprintf(grprsm, " Day of database entry                      %3d\n", isec1[45]);
+      fprintf(grprsm, " Hour of database entry                     %3d\n", isec1[46]);
+      fprintf(grprsm, " Minute of database entry                   %3d\n", isec1[47]);
+      fprintf(grprsm, " DWD experiment number                %9d\n",isec1[48]);
+      fprintf(grprsm, " DWD run type                         %9d\n",isec1[49]);
+      if ( isec1[36] == 253 ) 
+	{
+	  fprintf(grprsm, " User id                              %9d\n",isec1[50]);
+	  fprintf(grprsm, " Experiment identifier                %9d\n",isec1[51]);
+	  fprintf(grprsm, " Ensemble identification type         %9d\n",isec1[52]);
+	  fprintf(grprsm, " Number of ensemble members           %9d\n",isec1[53]);
+	  fprintf(grprsm, " Actual number of ensemble member     %9d\n",isec1[54]);
+	  fprintf(grprsm, " Model version                            %2d.%2.2d\n",isec1[55],isec1[56]);
+	}
+    }
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
   /*
-  else if ( gribversion == 2 )
-    grib2PrintBMS(nrec, recpos, recsize, gribbuffer);
+    -----------------------------------------------------------------
+    Section 2 . Print local ECMWF information.
+    -----------------------------------------------------------------
   */
-  else
+  /*
+    Regular MARS labelling, or reformatted Washington EPS products.
+  */
+  if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
+       (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
+       (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
     {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
-    }
-}
+      /*   Parameters common to all definitions.  */
+
+      fprintf(grprsm, " ECMWF local usage identifier.        %9d\n", isec1[36]);
+      if ( isec1[36] == 1 )
+	fprintf(grprsm, " (Mars labelling or ensemble forecast)\n");
+      if ( isec1[36] == 2 )
+        fprintf(grprsm, " (Cluster means and standard deviations)\n");
+      if ( isec1[36] == 3 )
+        fprintf(grprsm, " (Satellite image data)\n");
+      if ( isec1[36] == 4 )
+        fprintf(grprsm, " (Ocean model data)\n");
+      if ( isec1[36] == 5 )
+        fprintf(grprsm, " (Forecast probability data)\n");
+      if ( isec1[36] == 6 )
+        fprintf(grprsm, " (Surface temperature data)\n");
+      if ( isec1[36] == 7 )
+        fprintf(grprsm, " (Sensitivity data)\n");
+      if ( isec1[36] == 8 )
+        fprintf(grprsm, " (ECMWF re-analysis data)\n");
+      if ( isec1[36] == 9 )
+        fprintf(grprsm, " (Singular vectors and ensemble perturbations)\n");
+      if ( isec1[36] == 10 )
+        fprintf(grprsm, " (EPS tubes)\n");
+      if ( isec1[36] == 11 )
+        fprintf(grprsm, " (Supplementary data used by analysis)\n");
+      if ( isec1[36] == 13 )
+        fprintf(grprsm, " (Wave 2D spectra direction and frequency)\n");
+
+      fprintf(grprsm, " Class.                               %9d\n", isec1[37]);
+      fprintf(grprsm, " Type.                                %9d\n", isec1[38]);
+      fprintf(grprsm, " Stream.                              %9d\n", isec1[39]);
+      sprintf(hversion, "%4s", (char*)&isec1[40]); hversion[4] = 0;
+      fprintf(grprsm, " Version number or Experiment identifier.  %4s\n", hversion);
+      /*
+	ECMWF Local definition 1.
+	(MARS labelling or ensemble forecast data)
+      */
+      if ( isec1[36] == 1 )
+	{
+	  fprintf(grprsm, " Forecast number.                     %9d\n", isec1[41]);
+	  if ( isec1[39] != 1090 )
+	    fprintf(grprsm, " Total number of forecasts.           %9d\n", isec1[42]);
+
+	  return;
+	}
+      /*
+	ECMWF Local definition 2.
+	(Cluster means and standard deviations)
+      */
+      if ( isec1[36] == 2 )
+	{
+	  fprintf(grprsm, " Cluster number.                      %9d\n", isec1[41]);
+	  fprintf(grprsm, " Total number of clusters.            %9d\n", isec1[42]);
+	  fprintf(grprsm, " Clustering method.                   %9d\n", isec1[43]);
+	  fprintf(grprsm, " Start time step when clustering.     %9d\n", isec1[44]);
+	  fprintf(grprsm, " End time step when clustering.       %9d\n", isec1[45]);
+	  fprintf(grprsm, " Northern latitude of domain.         %9d\n", isec1[46]);
+	  fprintf(grprsm, " Western longitude of domain.         %9d\n", isec1[47]);
+	  fprintf(grprsm, " Southern latitude of domain.         %9d\n", isec1[48]);
+	  fprintf(grprsm, " Eastern longitude of domain.         %9d\n", isec1[49]);
+	  fprintf(grprsm, " Operational forecast in cluster      %9d\n", isec1[50]);
+	  fprintf(grprsm, " Control forecast in cluster          %9d\n", isec1[51]);
+	  fprintf(grprsm, " Number of forecasts in cluster.      %9d\n", isec1[52]);
 
+	  for (jloop = 0; jloop < isec1[52]; jloop++)
+	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[jloop+53]);
+
+	  return;
+	}
+      /*
+	ECMWF Local definition 3.
+	(Satellite image data)
+      */
+      if ( isec1[36] == 3 )
+	{
+	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
+	  fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
+	  return;
+	}
+      /*
+	ECMWF Local definition 4.
+	(Ocean model data)
+      */
+      if ( isec1[36] == 4 )
+	{
+	  fprintf(grprsm, " Satellite spectral band.             %9d\n", isec1[41]);
+	  if ( isec1[39] != 1090 )
+	    fprintf(grprsm, " Function code.                       %9d\n", isec1[42]);
+	  fprintf(grprsm, " Coordinate structure definition.\n");
+	  fprintf(grprsm, " Fundamental spatial reference system.%9d\n", isec1[43]);
+	  fprintf(grprsm, " Fundamental time reference.          %9d\n", isec1[44]);
+	  fprintf(grprsm, " Space unit flag.                     %9d\n", isec1[45]);
+	  fprintf(grprsm, " Vertical coordinate definition.      %9d\n", isec1[46]);
+	  fprintf(grprsm, " Horizontal coordinate definition.    %9d\n", isec1[47]);
+	  fprintf(grprsm, " Time unit flag.                      %9d\n", isec1[48]);
+	  fprintf(grprsm, " Time coordinate definition.          %9d\n", isec1[49]);
+	  fprintf(grprsm, " Position definition.     \n");
+	  fprintf(grprsm, " Mixed coordinate field flag.         %9d\n", isec1[50]);
+	  fprintf(grprsm, " Coordinate 1 flag.                   %9d\n", isec1[51]);
+	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[52]);
+	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[53]);
+	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[54]);
+	  fprintf(grprsm, " Coordinate 2 flag.                   %9d\n", isec1[55]);
+	  fprintf(grprsm, " Averaging flag.                      %9d\n", isec1[56]);
+	  fprintf(grprsm, " Position of level 1.                 %9d\n", isec1[57]);
+	  fprintf(grprsm, " Position of level 2.                 %9d\n", isec1[58]);
+	  fprintf(grprsm, " Grid Definition.\n");
+	  fprintf(grprsm, " Coordinate 3 flag (x-axis)           %9d\n", isec1[59]);
+	  fprintf(grprsm, " Coordinate 4 flag (y-axis)           %9d\n", isec1[60]);
+	  fprintf(grprsm, " Coordinate 4 of first grid point.    %9d\n", isec1[61]);
+	  fprintf(grprsm, " Coordinate 3 of first grid point.    %9d\n", isec1[62]);
+	  fprintf(grprsm, " Coordinate 4 of last grid point.     %9d\n", isec1[63]);
+	  fprintf(grprsm, " Coordinate 3 of last grid point.     %9d\n", isec1[64]);
+	  fprintf(grprsm, " i - increment.                       %9d\n", isec1[65]);
+	  fprintf(grprsm, " j - increment.                       %9d\n", isec1[66]);
+	  fprintf(grprsm, " Flag for irregular grid coordinates. %9d\n", isec1[67]);
+	  fprintf(grprsm, " Flag for normal or staggered grids.  %9d\n", isec1[68]);
+	  fprintf(grprsm, " Further information.\n");
+	  fprintf(grprsm, " Further information flag.            %9d\n", isec1[69]);
+	  fprintf(grprsm, " Auxiliary information.\n");
+	  fprintf(grprsm, " No. entries in horizontal coordinate %9d\n", isec1[70]);
+	  fprintf(grprsm, " No. entries in mixed coordinate defn.%9d\n", isec1[71]);
+	  fprintf(grprsm, " No. entries in grid coordinate list. %9d\n", isec1[72]);
+	  fprintf(grprsm, " No. entries in auxiliary array.      %9d\n", isec1[73]);
+	  /*
+	    Horizontal coordinate supplement.
+	  */
+	  fprintf(grprsm, " Horizontal coordinate supplement.\n");
+	  if ( isec1[70] == 0 )
+	    {
+	      fprintf(grprsm, "(None).\n");
+	    }
+	  else
+	    {
+	      fprintf(grprsm, "Number of items = %d\n", isec1[70]);
+	      for (jloop = 0; jloop < isec1[70]; jloop++)
+		fprintf(grprsm, "         %12d\n", isec1[74+jloop]);
+	    }
+	  /*
+	    Mixed coordinate definition.
+	  */
+	  fprintf(grprsm, " Mixed coordinate definition.\n");
+	  if ( isec1[71] == 0 )
+	    {
+	      fprintf(grprsm, "(None).\n");
+	    }
+	  else
+	    {
+	      fprintf(grprsm, "Number of items = %d\n", isec1[71]);
+	      ioffset = 74 + isec1[70];
+	      for (jloop = 0; jloop < isec1[71]; jloop++)
+		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
+	    }
+	  /*
+	    Grid coordinate list.
+	  */
+	  fprintf(grprsm, " Grid coordinate list. \n");
+	  if ( isec1[72] == 0 )
+	    {
+	      fprintf(grprsm, "(None).\n");
+	    }
+	  else
+	    {
+	      fprintf(grprsm, "Number of items = %d\n", isec1[72]);
+	      ioffset = 74 + isec1[70] + isec1[71];
+	      for (jloop = 0; jloop < isec1[72]; jloop++)
+		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
+	    }
+	  /*
+	    Auxiliary array.
+	  */
+	  fprintf(grprsm, " Auxiliary array.      \n");
+	  if ( isec1[73] == 0 )
+	    {
+	      fprintf(grprsm, "(None).\n");
+	    }
+	  else
+	    {
+	      fprintf(grprsm, "Number of items = %d\n", isec1[73]);
+	      ioffset = 74 + isec1[70] + isec1[71] + isec1[72];
+	      for (jloop = 0; jloop < isec1[73]; jloop++)
+		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
+	    }
+	  /*
+	    Post-auxiliary array.
+	  */
+	  fprintf(grprsm, " Post-auxiliary array. \n");
+	  ioffset = 74 + isec1[70] + isec1[71] + isec1[72] + isec1[73];
+	  if ( isec1[ioffset] == 0 )
+	    {
+	      fprintf(grprsm, "(None).\n");
+	    }
+	  else
+	    {
+	      fprintf(grprsm, "Number of items = %d\n", isec1[ioffset]);
+	      for (jloop = 1; jloop < isec1[ioffset]; jloop++)
+		fprintf(grprsm, "         %12d\n", isec1[ioffset+jloop]);
+	    }
 
-void grib1PrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  static int header = 1;
-  int level, nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  double cr = 1;
-  double refval, scale;
+	  return;
+	}
+      /*
+	ECMWF Local definition 5.
+	(Forecast probability data)
+      */
+      if ( isec1[36] == 5 )
+	{
+	  fprintf(grprsm, " Forecast probability number          %9d\n", isec1[41]);
+	  fprintf(grprsm, " Total number of forecast probabilities %7d\n", isec1[42]);
+	  fprintf(grprsm, " Threshold units decimal scale factor %9d\n", isec1[43]);
+	  fprintf(grprsm, " Threshold indicator(1=lower,2=upper,3=both) %2d\n", isec1[44]);
+	  if ( isec1[44]  !=  2 )
+	    fprintf(grprsm, " Lower threshold value                %9d\n", isec1[45]);
+	  if ( isec1[44]  !=  1 )
+	    fprintf(grprsm, " Upper threshold value                %9d\n", isec1[46]);
+	  return;
+	}
+      /*
+	ECMWF Local definition 6.
+	(Surface temperature data)
+      */
+      if ( isec1[36] == 6 )
+	{
+	  iyear = isec1[43];
+	  if ( iyear > 100 )
+	    {
+	      if ( iyear < 19000000 ) iyear = iyear + 19000000;
+	      fprintf(grprsm, " Date of SST field used               %9d\n", iyear);
+	    }
+	  else
+	    fprintf(grprsm, "Date of SST field used               Not given\n");
+	}
+      if ( isec1[44] == 0 )
+	fprintf(grprsm, " Type of SST field (= climatology)    %9d\n", isec1[44]);
+      if ( isec1[44] == 1 )
+	fprintf(grprsm, " Type of SST field (= 1/1 degree)     %9d\n", isec1[44]);
+      if ( isec1[44] == 2 )
+	fprintf(grprsm, " Type of SST field (= 2/2 degree)     %9d\n", isec1[44]);
 
-  UNUSED(recpos);
+      fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
 
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : Code Level     BDS Flag     Scale   RefValue Bits  CR\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
+      for (jloop = 1; jloop <= isec1[45]; jloop++)
+	{
+	  iyear = isec1[44+(jloop*2)];
+	  if ( iyear > 100 )
+	    {
+              if ( iyear < 19000000 ) iyear = iyear + 19000000;
+	      fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop, iyear);
+	      fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
+		     isec1[45+(jloop*2)]);
+	    }
+	  else
+	    fprintf(grprsm, "Date of SST field used               Not given\n");
+	}
+      /*
+	ECMWF Local definition 7.
+	(Sensitivity data)
+      */
+      if ( isec1[36] == 7 )
+	{
+	  if ( isec1[38]  ==  51 )
+	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[41]);
+	  if ( isec1[38]  !=  51 )
+	    fprintf(grprsm, " Iteration number                     %9d\n", isec1[41]);
+	  if ( isec1[38]  !=  52 )
+	    fprintf(grprsm, " Total number of diagnostics          %9d\n", isec1[42]);
+	  if ( isec1[38]  ==  52 )
+	    fprintf(grprsm, " No.interations in diag. minimisation %9d\n", isec1[42]);
+	  fprintf(grprsm, " Domain(0=Global,1=Europe,2=N.Hem.,3=S.Hem.) %2d\n", isec1[43]);
+	  fprintf(grprsm, " Diagnostic number                    %9d\n", isec1[44]);
+	}
+      /*
+	ECMWF Local definition 8.
+	(ECMWF re-analysis data)
+      */
+      if ( isec1[36] == 8 )
+	{
+	  if ( (isec1[39] == 1043) ||
+	       (isec1[39] == 1070) ||
+	       (isec1[39] == 1071) )
+	    {
+	      fprintf(grprsm, " Interval between reference times     %9d\n", isec1[41]);
+	      for (jloop = 43; jloop <= 54; jloop++)
+		{
+		  jiloop = jloop + 8;
+		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
+			 jiloop, isec1[jloop-1]);
+		}
+	    }
+	  else
+	    {
+	      for (jloop = 42; jloop <= 54; jloop++)
+		{
+		  jiloop = jloop + 8;
+		  fprintf(grprsm, " ERA section 1 octet %2d.              %9d\n",
+			 jiloop, isec1[jloop-1]);
+		}
+	    }
+	  return;
+	}
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
+      if ( isec1[38] > 4  && isec1[38] < 9 )
+	{
+	  fprintf(grprsm, " Simulation number.                   %9d\n", isec1[41]);
+	  fprintf(grprsm, " Total number of simulations.         %9d\n", isec1[42]);
+	}
+      /*
+	ECMWF Local definition 9.
+	(Singular vectors and ensemble perturbations)
+      */
+      if ( isec1[36] == 9 )
+	{
+	  if ( isec1[38] == 60 )
+	    fprintf(grprsm, " Perturbed ensemble forecast number   %9d\n", isec1[41]);
+	  if ( isec1[38] == 61 )
+	    fprintf(grprsm, " Initial state perturbation number    %9d\n", isec1[41]);
+	  if ( isec1[38] == 62 )
+	    fprintf(grprsm, " Singular vector number               %9d\n", isec1[41]);
+	  if ( isec1[38] == 62 )
+	    {
+	      fprintf(grprsm, " Number of iterations                 %9d\n", isec1[42]);
+	      fprintf(grprsm, " Number of singular vectors computed  %9d\n", isec1[43]);
+	      fprintf(grprsm, " Norm used at initial time            %9d\n", isec1[44]);
+	      fprintf(grprsm, " Norm used at final time              %9d\n", isec1[45]);
+	      fprintf(grprsm, " Multiplication factor                %9d\n", isec1[46]);
+    	      fprintf(grprsm, " Latitude of north-west corner        %9d\n", isec1[47]);
+    	      fprintf(grprsm, " Longitude of north-west corner       %9d\n", isec1[48]);
+	      fprintf(grprsm, " Latitude of south-east corner        %9d\n", isec1[49]);
+	      fprintf(grprsm, " Longitude of south-east corner       %9d\n", isec1[50]);
+	      fprintf(grprsm, " Accuracy                             %9d\n", isec1[51]);
+	      fprintf(grprsm, " Number of singular vectors evolved   %9d\n", isec1[52]);
+	      fprintf(grprsm, " Ritz number one                      %9d\n", isec1[53]);
+	      fprintf(grprsm, " Ritz number two                      %9d\n", isec1[54]);
+	    }
+	}
+      /*
+	ECMWF Local definition 10.
+	(EPS tubes)
+      */
+      if ( isec1[36] == 10 )
+	{
+	  fprintf(grprsm, " Tube number                          %9d\n", isec1[41]);
+          fprintf(grprsm, " Total number of tubes                %9d\n", isec1[42]);
+          fprintf(grprsm, " Central cluster definition           %9d\n", isec1[43]);
+          fprintf(grprsm, " Parameter                            %9d\n", isec1[44]);
+          fprintf(grprsm, " Type of level                        %9d\n", isec1[45]);
+          fprintf(grprsm, " Northern latitude of domain of tubing%9d\n", isec1[46]);
+          fprintf(grprsm, " Western longitude of domain of tubing%9d\n", isec1[47]);
+          fprintf(grprsm, " Southern latitude of domain of tubing%9d\n", isec1[48]);
+          fprintf(grprsm, " Eastern longitude of domain of tubing%9d\n", isec1[49]);
+          fprintf(grprsm, " Tube number of operational forecast  %9d\n", isec1[50]);
+          fprintf(grprsm, " Tube number of control forecast      %9d\n", isec1[51]);
+          fprintf(grprsm, " Height/pressure of level             %9d\n", isec1[52]);
+          fprintf(grprsm, " Reference step                       %9d\n", isec1[53]);
+          fprintf(grprsm, " Radius of central cluster            %9d\n", isec1[54]);
+          fprintf(grprsm, " Ensemble standard deviation          %9d\n", isec1[55]);
+          fprintf(grprsm, " Dist.of tube extreme to ensemble mean%9d\n", isec1[56]);
+          fprintf(grprsm, " Number of forecasts in the tube      %9d\n", isec1[57]);
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
+          fprintf(grprsm, " List of ensemble forecast numbers:\n");
+          for (jloop = 1; jloop <=  isec1[57]; jloop++)
+	    fprintf(grprsm, "    %9d\n", isec1[57+jloop]);
+	}
+      /*
+	ECMWF Local definition 11.
+	(Supplementary data used by the analysis)
+      */
+      if ( isec1[36] == 11 )
+	{
+	  fprintf(grprsm, " Details of analysis which used the supplementary data:\n");
+	  fprintf(grprsm, "   Class                              %9d\n", isec1[41]);
+	  fprintf(grprsm, "   Type                               %9d\n", isec1[42]);
+	  fprintf(grprsm, "   Stream                             %9d\n", isec1[43]);
+	  /*
+	  sprintf(hversion, "%8d", isec1[44]);
+	  fprintf(grprsm, "   Version number/experiment identifier:   %4s\n", &hversion[4]);
+	  */
+	  iyear = isec1[45];
+	  if ( iyear > 50 )
+	    iyear = iyear + 1900;
+	  else
+	    iyear = iyear + 2000;
 
-  if ( ((BDS_Flag >> 4)&1) && BDS_Z == 128 )
-    {
-      int s1, s2;
-      s1 = ((int) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
-      s2 = ((int) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
-      cr = ((double)s1)/s2;
-    }
+	  fprintf(grprsm, "   Year                               %9d\n", iyear);
+	  fprintf(grprsm, "   Month                              %9d\n", isec1[46]);
+	  fprintf(grprsm, "   Day                                %9d\n", isec1[47]);
+	  fprintf(grprsm, "   Hour                               %9d\n", isec1[48]);
+	  fprintf(grprsm, "   Minute                             %9d\n", isec1[49]);
+	  fprintf(grprsm, "   Century                            %9d\n", isec1[50]);
+	  fprintf(grprsm, "   Originating centre                 %9d\n", isec1[51]);
+	  fprintf(grprsm, "   Sub-centre                         %9d\n", isec1[52]);
+	}
+      /*
+	ECMWF Local definition 12.
+      */
+      if ( isec1[36] == 12 )
+	{
+	  fprintf(grprsm, " (Mean, average, etc)\n");
+          fprintf(grprsm, " Start date of the period              %8d\n", isec1[41]);
+          fprintf(grprsm, " Start time of the period                  %4.4d\n", isec1[42]);
+          fprintf(grprsm, " Finish date of the period             %8d\n", isec1[43]);
+          fprintf(grprsm, " Finish time of the period                 %4.4d\n", isec1[44]);
+          fprintf(grprsm, " Verifying date of the period          %8d\n", isec1[45]);
+          fprintf(grprsm, " Verifying time of the period              %4.4d\n", isec1[46]);
+          fprintf(grprsm, " Code showing method                   %8d\n", isec1[47]);
+          fprintf(grprsm, " Number of different time intervals used  %5d\n", isec1[48]);
+          fprintf(grprsm, " List of different time intervals used:\n");
+          iprev  = isec1[49];
+          unsigned icount = 0;
+          for (jloop = 1; jloop <= isec1[48]; jloop++)
+	    {
+	      icurr = isec1[48+jloop];
+	      if ( icurr != iprev )
+		{
+		  if ( icount == 1 )
+		    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
+		  if ( icount == 2 )
+		    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
+		  if ( icount > 2 )
+		    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
+		  iprev  = icurr;
+		  icount = 1;
+		}
+	      else
+		icount = icount + 1;
+	    }
+	  if ( icount == 1 )
+	    fprintf(grprsm, "  - interval %5.4d used       once\n", iprev);
+	  if ( icount == 2 )
+	    fprintf(grprsm, "  - interval %5.4d used       twice\n", iprev);
+	  if ( icount > 2 )
+	    fprintf(grprsm, "  - interval %5.4d used %5u times\n",  iprev, icount);
+	}
+      /*
+	ECMWF Local definition 13.
+	(Wave 2D spectra direction and frequency)
+      */
+      if ( isec1[36] == 13 )
+	{
+          fprintf(grprsm, " Direction number                     %9d\n", isec1[43]);
+	  fprintf(grprsm, " Frequency number                     %9d\n", isec1[44]);
+	  fprintf(grprsm, " Total number of directions           %9d\n", isec1[45]);
+	  fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[46]);
+	  fprintf(grprsm, " Scale factor applied to directions   %9d\n", isec1[47]);
+	  fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[48]);
+	  fprintf(grprsm, " List of directions:\n");
+          for (jloop = 1; jloop <= isec1[45]; jloop++)
+            {
+	      value = (float)(isec1[48+jloop])/(float)(isec1[47]);
+	      if ( isec1[43] == jloop )
+		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
+	      else
+		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
+            }
+	  fprintf(grprsm, " List of frequencies:\n");
+          for (jloop = 1; jloop <= isec1[46]; jloop++)
+	    {
+	      value = (float)(isec1[48+isec1[45]+jloop])/(float)(isec1[48]);
+	      if ( isec1[44] == jloop )
+		fprintf(grprsm, " %2.2d:%15.7f   <-- this field value\n",  jloop, value);
+	      else
+		fprintf(grprsm, "%2.2d:%15.7f\n",  jloop, value);
 
-  refval = BDS_RefValue;
+	      if ( isec1[49+isec1[45]+isec1[46]] != 0 )
+		{
+		  fprintf(grprsm, " System number (65535 = missing)      %9d\n",
+			 isec1[49+isec1[45]+isec1[46]]);
+		  fprintf(grprsm, " Method number (65535 = missing)      %9d\n",
+			 isec1[50+isec1[45]+isec1[46]]);
+		}
+	    }
+	  /*
+	    ECMWF Local definition 14.
+	    (Brightness temperature)
+	  */
+	  if ( isec1[36] == 14 )
+	    {
+	      fprintf(grprsm, " Channel number                       %9d\n", isec1[43]);
+	      fprintf(grprsm, " Scale factor applied to frequencies  %9d\n", isec1[44]);
+	      fprintf(grprsm, " Total number of frequencies          %9d\n", isec1[45]);
+	      fprintf(grprsm, " List of frequencies:\n");
+              for (jloop = 1; jloop <= isec1[45]; jloop++)
+		{
+		  value = (float)(isec1[45+jloop])/(float)(isec1[44]);
+		  if ( isec1[43] == jloop )
+		    fprintf(grprsm, " %3d:%15.9f   <-- this channel\n", jloop, value);
+		  else
+		    fprintf(grprsm, " %3d:%15.9f\n", jloop, value);
+		}
+	    }
+	  /*
+	    ECMWF Local definition 15.
+	    (Ocean ensemble seasonal forecast)
+	  */
+	  if ( isec1[36] == 15 )
+	    {
+	      fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
+	      fprintf(grprsm, " System number                        %9d\n", isec1[42]);
+	      fprintf(grprsm, " Method number                        %9d\n", isec1[43]);
+	    }
+	  /*
+	    ECMWF Local definition 16.
+	    (Seasonal forecast monthly mean atmosphere data)
+	  */
+        if ( isec1[36] == 16 )
+	  {
+	    fprintf(grprsm, " Ensemble member number               %9d\n", isec1[41]);
+	    fprintf(grprsm, " System number                        %9d\n", isec1[43]);
+	    fprintf(grprsm, " Method number                        %9d\n", isec1[44]);
+	    fprintf(grprsm, " Verifying month                      %9d\n", isec1[45]);
+	    fprintf(grprsm, " Averaging period                     %9d\n", isec1[46]);
+	  }
+	/*
+	  ECMWF Local definition 17.
+	  (Sst or sea-ice used by analysis)
+	*/
+        if ( isec1[36] == 17 )
+	  {
+	    iyear = isec1[43];
+	    if ( iyear > 100 )
+	      {
+		if ( iyear < 19000000 ) iyear = iyear + 19000000;
+		fprintf(grprsm, " Date of sst/ice field used           %9d\n", iyear);
+	      }
+	    else
+              fprintf(grprsm, " Date of sst/ice field used           Not given\n");
+      
+	    if ( isec1[44] == 0 )
+	      fprintf(grprsm, " Type of sst/ice field (= climatology)%9d\n", isec1[44]);
+	    if ( isec1[44] == 1 )
+	      fprintf(grprsm, " Type of sst/ice field (= 1/1 degree) %9d\n", isec1[44]);
+	    if ( isec1[44] == 2 )
+	      fprintf(grprsm, " Type of sst/ice field (= 2/2 degree) %9d\n", isec1[44]);
 
-  if ( BDS_BinScale < 0 )
-    scale = 1.0/pow(2.0, (double) -BDS_BinScale);
-  else
-    scale = pow(2.0, (double) BDS_BinScale);
+	    fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
 
-  if ( PDS_DecimalScale )
-    {
-      double decscale;
-      decscale = pow(10.0, (double)-PDS_DecimalScale);
-      refval *= decscale;
-      scale  *= decscale;
+	    for (jloop = 1; jloop < isec1[45]; jloop++)
+	      {
+		iyear = isec1[44+(jloop*2)];
+		if ( iyear > 100 )
+		  {
+		    if ( iyear < 19000000 ) iyear = iyear + 19000000;
+		    fprintf(grprsm, " Date of ICE field%3d                 %9d\n", jloop,
+			   iyear);
+		    fprintf(grprsm, " Satellite number (ICE field%3d)      %9d\n", jloop,
+			   isec1[45+(jloop*2)]);
+		  }
+		else
+		  fprintf(grprsm, "Date of sst/ice field used           Not given\n");
+	      } 
+	  }
+	}
     }
-
-  fprintf(stdout, "%5d :", nrec);
-
-  if ( bds )
-    fprintf(stdout, "%4d%7d %7d %4d %8.5g %11.5g%4d %6.4g",
-	    PDS_Parameter, level,
-	    BDS_Len, BDS_Flag, scale, refval, BDS_NumBits, cr);
-  else
-    fprintf(stdout, " Binary Data Section not defined");
-
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
-
-
-void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
-
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
-
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
   /*
-  else if ( gribversion == 2 )
-    grib2PrintBDS(nrec, recpos, recsize, gribbuffer);
+    -----------------------------------------------------------------
+    Section 3 . Print Washington ensemble product information.
+    -----------------------------------------------------------------
   */
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
-    }
-}
-
-
-void gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int level, nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  double cr = 1;
-
-  UNUSED(recpos);
-
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
-
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
-      return;
-    }
-
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
-
-  if ( ((BDS_Flag >> 4)&1) && BDS_Z == 128 )
+  /*
+    Washington EPS products (but not reformatted Washington EPS
+    products.
+  */
+  if ( (isec1[1] == 7 && isec1[23] == 1) && (! (ISEC1_SubCenterID == 98)) )
     {
-      int s1, s2;
-      s1 = ((int) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
-      s2 = ((int) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
-      cr = ((double)s1)/s2;
+      /*   CALL KWPRS1 (iSEC0,iSEC1)*/
     }
-
-  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
+  /*
+    -----------------------------------------------------------------
+    Section 4 . Print local MPIM information.
+    -----------------------------------------------------------------
+  */
+  if (isec1[ 1] == 252 && isec1[36] == 1)
     {
-      fprintf(stdout, "GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
+      fprintf(grprsm, " MPIM local usage identifier.         %9d\n", isec1[36]);
+      fprintf(grprsm, " Type of ensemble forecast            %9d\n", isec1[37]);
+      fprintf(grprsm, " Individual ensemble member           %9d\n", isec1[38]);
+      fprintf(grprsm, " Number of forecasts in ensemble      %9d\n", isec1[39]);
     }
 }
 
-
-static
-void repair1(unsigned char *gbuf, long gbufsize)
+void printQuasi(int *isec2)
 {
-  int nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  /* int recLen; */
-  unsigned char *source;
-  size_t sourceLen;
-  int bds_len, bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress */;
-  int bds_head = 11;
-  int bds_ext = 0, bds_ubits;
-  int datstart = 0;
-  /* int llarge = FALSE; */
-
-  long gribrecsize;
-  nerr = grib1Sections(gbuf, gbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "GRIB message error\n");
-      return;
-    }
-
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return;
-    }
+  /*
 
-  /* recLen = gribrec_len(gbuf[4], gbuf[5], gbuf[6]); */
-  /* if ( recLen > JP23SET ) llarge = TRUE; */
+    Print the qusai-regular information in the Grid Description
+    Section (Section 2) of decoded GRIB data.
 
-  bds_len   = BDS_Len;
-  bds_nbits = BDS_NumBits;
-  bds_flag  = BDS_Flag;
-  bds_ubits = bds_flag & 15;
-  lspherc   =  bds_flag >> 7;
-  lcomplex  = (bds_flag >> 6)&1;
-  /* lcompress = (bds_flag >> 4)&1; */
+    Input Parameters:
 
-  if ( lspherc )
-    {
-      if ( lcomplex  )
-	{
-	  int jup, ioff;
-	  jup  = bds[15];
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
-	}
-      else
-	{
-	  bds_ext = 4;
-	}
-    }
+       isec2 - Array of decoded integers from Section 2.
 
-  datstart = bds_head + bds_ext;
+    Comments:
 
-  source = bds + datstart;
+       Only data representation types catered for are Gaussian
+       grid, latitude/longitude grid, Spherical Harmonics,
+       Polar stereographic and Space view perspective.
 
-  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
+    Converted from EMOS routine PTQUASI.
 
-  if ( bds_nbits == 24 )
-    {
-      unsigned char *pbuf = (unsigned char*) Malloc(sourceLen);;
-      size_t nelem = sourceLen/3;
-      for ( size_t i = 0; i < nelem; i++ )
-	{
-	  pbuf[3*i  ] = source[        i];
-	  pbuf[3*i+1] = source[  nelem+i];
-	  pbuf[3*i+2] = source[2*nelem+i];
-	}
-      memcpy(source, pbuf, sourceLen);
-      Free(pbuf);
-    }
-}
+       Uwe Schulzweida   MPIfM   01/04/2001
 
+  */
 
-void gribRepair1(int nrec, long recsize, unsigned char *gribbuffer)
-{
-  int level, nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  double cr = 1;
+  char yout[64];
+  int nextlat, latcnt;
+  int j;
+  int ntos;
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
+  /*
+    -----------------------------------------------------------------
+    Section 1. Print quasi-grid data.
+    -----------------------------------------------------------------
+  */
+  /*
+    See if scanning is north->south or south->north
+  */
+  fprintf(grprsm, "  Number of points along a parallel varies.\n");
 
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
-      return;
-    }
+  ntos = ( fmod((double) isec2[10], 128.) < 64 );
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
+  if ( ntos )
+    fprintf(grprsm, "  Number of points.   Parallel. (North to South)\n");
   else
-    level = PDS_Level1;
+    fprintf(grprsm, "  Number of points.   Parallel. (South to North)\n");
 
-  if ( ((BDS_Flag >> 4)&1) && BDS_Z == 128 )
-    {
-      int s1, s2;
-      s1 = ((int) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
-      s2 = ((int) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
-      cr = ((double)s1)/s2;
-    }
+  /*  Display number of points for each latitude */
+  latcnt  = isec2[2];
+  nextlat = 0;
+  memset(yout, ' ', (size_t) 11);
 
-  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
+  for ( j = 0; j < latcnt; j++ )
     {
-      fprintf(stdout, "Repair GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
-      repair1(gribbuffer, recsize);
+      nextlat = nextlat + 1;
+      sprintf(yout, "%4d", nextlat);
+
+      /*       Finished?  */
+      if ( nextlat > latcnt ) break;
+      if ( nextlat == latcnt )
+	{
+	  fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
+	  break;
+	}
+      /*
+	Look for neighbouring latitudes with same number of points
+      */
+      unsigned nrepeat = 0;
+
+    LABEL110:
+      /*
+	If neighbouring latitudes have same number of points
+	increase the repeat count.
+      */
+      if ( isec2[nextlat+21+1] == isec2[nextlat+21] )
+	{
+          nrepeat = nrepeat + 1;
+          nextlat = nextlat + 1;
+	  if ( nextlat < latcnt ) goto LABEL110;
+	}
+      /*
+	Display neighbouring latitudes with same number of points as
+	'nn to mm'.
+      */
+      if ( nrepeat >= 1 )
+	{
+	  strncpy(yout+4, " to", 3);
+	  sprintf(yout+7, "%5d", nextlat);
+        }
+      fprintf(grprsm, " %5d                %-12s\n", isec2[nextlat+21], yout);
+      memset(yout, ' ', (size_t) 11);
     }
 }
-#include <stdio.h>
-#include <string.h>
 
-#if defined (HAVE_CONFIG_H)
-#endif
+void gribPrintSec2DP(int *isec0, int *isec2, double *fsec2)
+{
+  /*
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
-#if defined(__cplusplus)
-extern "C" {
-#endif
-#if defined (HAVE_LIBAEC)
-#  include <libaec.h>
-#else
-#  include <szlib.h>
-#endif
-#if defined (__cplusplus)
-}
-#endif
+    Print the information in the Grid Description
+    Section (Section 2) of decoded GRIB data.
 
-#if defined (HAVE_LIBAEC)
-#  define AEC_FLAGS           (AEC_DATA_MSB | AEC_DATA_PREPROCESS)
-#else
-#  define OPTIONS_MASK        (SZ_RAW_OPTION_MASK | SZ_MSB_OPTION_MASK | SZ_NN_OPTION_MASK)
-#endif
+    Input Parameters:
+
+       isec0  - Array of decoded integers from Section 0
 
-#  define PIXELS_PER_BLOCK    (8)
-#  define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
+       isec2  - Array of decoded integers from Section 2
 
-#  define MIN_COMPRESS        (0.95)
-#  define MIN_SIZE            (256)
-#endif
+       fsec2  - Array of decoded floats from Section 2
 
-#define  Z_SZIP  128
-#define  Z_AEC   130
+    Comments:
 
+       Only data representation types catered for are Gaussian
+       grid, latitude/longitude grid, Spherical Harmonics,
+       Polar stereographic and Space view perspective.
 
-#define SetLen3(var, offset, value) ((var[offset+0] = 0xFF & (value >> 16)), \
-				     (var[offset+1] = 0xFF & (value >>  8)), \
-				     (var[offset+2] = 0xFF & (value      )))
-#define SetLen4(var, offset, value) ((var[offset+0] = 0xFF & (value >> 24)), \
-				     (var[offset+1] = 0xFF & (value >> 16)), \
-				     (var[offset+2] = 0xFF & (value >>  8)), \
-				     (var[offset+3] = 0xFF & (value      )))
 
+    Converted from EMOS routine GRPRS2.
 
-int gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize)
-{
-  /* urecsize : uncompressed record size  */
-  int compress = 0;
-  int nerr;
-  /* int  bds_len, bds_nbits, lspherc, lcomplex; */
-  int bds_flag, lcompress;
-  long gribsize = 0;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  */
 
-  if ( gribversion == 2 ) return (compress);
+  int i, ibit, iedit, ierr, iout, iresol;
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+  grsdef();
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print GRIB Edition number.
+    -----------------------------------------------------------------
+  */
+  iedit = isec0[1];
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 2 - Grid Description Section.\n");
+  fprintf(grprsm, " -------------------------------------\n");
+  /*
+    -----------------------------------------------------------------
+    Section 2 . Print spherical harmonic data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 50 || isec2[0] == 60 || 
+       isec2[0] == 70 || isec2[0] == 80 )
     {
-      fprintf(stdout, "GRIB message error\n");
-      return (compress);
+      fprintf(grprsm, " Data represent type = spectral     (Table 6) %9d\n", isec2[0]);
+      fprintf(grprsm, " J - Pentagonal resolution parameter.         %9d\n", isec2[1]);
+      fprintf(grprsm, " K - Pentagonal resolution parameter.         %9d\n", isec2[2]);
+      fprintf(grprsm, " M - Pentagonal resolution parameter.         %9d\n", isec2[3]);
+      fprintf(grprsm, " Representation type (Table 9)                %9d\n", isec2[4]);
+      fprintf(grprsm, " Representation mode (Table 10).              %9d\n", isec2[5]);
+      for (i = 7; i <= 11; i++)
+        fprintf(grprsm, " Not used.                                    %9d\n", isec2[i-1]);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      goto LABEL800;
     }
-
-  if ( nerr > 0 )
+  /*
+    -----------------------------------------------------------------
+    Section 3 . Print Gaussian grid data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] ==  4 || isec2[0] == 14 || 
+       isec2[0] == 24 || isec2[0] == 34 )
     {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (compress);
-    }
+      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
+      fprintf(grprsm, " Data represent type = gaussian     (Table 6) %9d\n", isec2[0]);
+      /*
+	Quasi-regular grids introduced in Edition 1.
+      */
+      if ( isec2[16] == 0 || iedit < 1 )
+	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
+      else
+      	printQuasi(isec2);
 
-  /* bds_len   = BDS_Len; */
-  /* bds_nbits = BDS_NumBits; */
-  bds_flag  = BDS_Flag;
-  /* lspherc   =  bds_flag >> 7; */
-  /* lcomplex  = (bds_flag >> 6)&1; */
-  lcompress = (bds_flag >> 4)&1;
+      fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
+      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
+      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
 
-  *urecsize = 0;
-  if ( lcompress )
-    {
-      compress = BDS_Z;
-      if ( compress == Z_SZIP || compress == Z_AEC )
-	{
-	  gribsize = gribrec_len(bds[14], bds[15], bds[16]);
-	}
-    }
+      ibit = 8;
+      iresol = isec2[5] + isec2[17] + isec2[18];
+      prtbin(iresol, ibit, &iout, &ierr);
 
-  *urecsize = gribsize;
+      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
+      fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
+      fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
+      /*
+	Print increment if given.
+      */
+      if ( isec2[5] == 128 )
+	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
+      else
+	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
 
-  return (compress);
-}
+      fprintf(grprsm, " Number of parallels between pole and equator.%9d\n", isec2[9]);
 
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
 
-int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
-{
-  int nerr;
-  int gribLen;
-  int rec_len;
-  int llarge = FALSE;
-#if ! (defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC))
-  static int libszwarn = 1;
-#endif
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      goto LABEL800;
+    }
+  /*
+    -----------------------------------------------------------------
+    Section 4 . Print Latitude / longitude grid data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] ==  0 || isec2[0] == 10 || 
+       isec2[0] == 20 || isec2[0] == 30 )
+    {
+      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
+      fprintf(grprsm, " Data represent type = lat/long     (Table 6) %9d\n", isec2[0]);
+      /*
+	Quasi-regular lat/long grids also possible.
+      */
+      if ( isec2[16] == 0 )
+	fprintf(grprsm, " Number of points along a parallel.           %9d\n", isec2[1]);
+      else
+        printQuasi(isec2);
 
-  gribLen = gribrec_len(dbuf[4], dbuf[5], dbuf[6]);
-  if ( gribLen > JP23SET ) llarge = TRUE;
+      fprintf(grprsm, " Number of points along a meridian.           %9d\n", isec2[2]);
+      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
+      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
 
-  rec_len = gribLen;
+      ibit = 8;
+      iresol = isec2[5] + isec2[17] + isec2[18];
+      prtbin(iresol, ibit, &iout, &ierr);
 
-  long gribrecsize;
-  nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
+      fprintf(grprsm, " Latitude of last grid point.                 %9d\n", isec2[6]);
+      fprintf(grprsm, " Longitude of last grid point.                %9d\n", isec2[7]);
+      /*
+	Print increment if given.
+      */
+      if ( isec2[8] < 0 )
+	fprintf(grprsm, " i direction (East-West) increment            Not given\n");
+      else
+	fprintf(grprsm, " i direction (East-West) increment.           %9d\n", isec2[8]);
+
+      if ( isec2[9] < 0 )
+	fprintf(grprsm, " j direction (North-South) increment          Not given\n");
+      else
+	fprintf(grprsm, " j direction (North-South) increment.         %9d\n", isec2[9]);
+    
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
+
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      goto LABEL800;
+    }
+  /*
+    -----------------------------------------------------------------
+    Section 5 . Print polar stereographic data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 5 )
     {
-      fprintf(stdout, "GRIB message error\n");
-      return (rec_len);
+      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
+      fprintf(grprsm, " Data represent type = polar stereo (Table 6) %9d\n", isec2[0]);
+      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
+      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
+      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
+      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
+      ibit = 8;
+      iresol = isec2[17] + isec2[18];
+      prtbin(iresol, ibit, &iout, &ierr);
+      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
+      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
+      fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
+      fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
+      goto LABEL800;
     }
-
-  if ( nerr > 0 )
+  /*
+    -----------------------------------------------------------------
+    Section 6 . Print Lambert conformal data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 3 )
     {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (rec_len);
+      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
+      fprintf(grprsm, " Data represent type = Lambert      (Table 6) %9d\n", isec2[0]);
+      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
+      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
+      fprintf(grprsm, " Latitude of first grid point.                %9d\n", isec2[3]);
+      fprintf(grprsm, " Longitude of first grid point.               %9d\n", isec2[4]);
+      ibit = 8;
+      iresol = isec2[17] + isec2[18] + isec2[5];
+      prtbin(iresol, ibit, &iout, &ierr);
+      fprintf(grprsm, " Resolution and components flag.               %8.8d\n", iout);
+      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
+      fprintf(grprsm, " X direction increment.                       %9d\n", isec2[8]);
+      fprintf(grprsm, " Y direction increment.                       %9d\n", isec2[9]);
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      fprintf(grprsm, " Projection centre flag.                      %9d\n", isec2[12]);
+      fprintf(grprsm, " Latitude intersection 1 - Latin 1 -.         %9d\n", isec2[13]);
+      fprintf(grprsm, " Latitude intersection 2 - Latin 2 -.         %9d\n", isec2[14]);
+      fprintf(grprsm, " Latitude of Southern Pole.                   %9d\n", isec2[19]);
+      fprintf(grprsm, " Longitude of Southern Pole.                  %9d\n", isec2[20]);
+      goto LABEL800;
     }
+  /*
+    -----------------------------------------------------------------
+    Section 7 . Print space view perspective or orthographic data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 90 )
+    {
+      fprintf(grprsm, " (Southern latitudes and Western longitudes are negative.)\n");
+      fprintf(grprsm, " Data represent type = space/ortho  (Table 6) %9d\n", isec2[0]);
+      fprintf(grprsm, " Number of points along X axis.               %9d\n", isec2[1]);
+      fprintf(grprsm, " Number of points along Y axis.               %9d\n", isec2[2]);
+      fprintf(grprsm, " Latitude of sub-satellite point.             %9d\n", isec2[3]);
+      fprintf(grprsm, " Longitude of sub-satellite point.            %9d\n", isec2[4]);
+      //iresol = isec2[17] + isec2[18];
+      fprintf(grprsm, " Diameter of the earth in x direction.        %9d\n", isec2[6]);
+      fprintf(grprsm, " Y coordinate of sub-satellite point.         %9d\n", isec2[9]);
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      fprintf(grprsm, " Orientation of the grid.                     %9d\n", isec2[6]);
+      fprintf(grprsm, " Altitude of the camera.                      %9d\n", isec2[13]);
+      fprintf(grprsm, " Y coordinate of origin of sector image.      %9d\n", isec2[14]);
+      fprintf(grprsm, " X coordinate of origin of sector image.      %9d\n", isec2[15]);
+      goto LABEL800;
+    }
+  /*
+    -----------------------------------------------------------------
+    Section 7.5 . Print ocean data
+    -----------------------------------------------------------------
+  */
+  /*
+  if ( isec2[0] == 192 && ISEC1_CenterID == 98 )
+    {
+      fprintf(grprsm, " Data represent type = ECMWF ocean  (Table 6) %9d\n", isec2[0]);
+      if ( isec2[1] ==  32767 )
+	fprintf(grprsm, " Number of points along the first axis.       Not used\n");
+      else
+	fprintf(grprsm, " Number of points along the first axis.       %9d\n", isec2[1]);
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
-
-  {
-    long i;
-    int bdsLen;
-    int gribLenOld = 0;
-    int status;
-    size_t datstart, datsize;
-#if defined (HAVE_LIBAEC)
-    struct aec_stream strm;
-#else
-    SZ_com_t sz_param;          /* szip parameter block */
-#endif
-    unsigned char *dest, *source;
-    size_t destLen, sourceLen;
-    int bits_per_sample;
-    int bds_len, bds_nbits, bds_flag, lspherc, lcomplex,/* lcompress,*/ bds_ubits;
-    int bds_head = 11;
-    int bds_ext = 0;
-    int bds_zoffset, bds_zstart;
-    unsigned char *pbuf = NULL;
-
-    bds_zstart  = 14;
-    bds_zoffset = 12;
-    if ( llarge ) bds_zoffset += 2;
-
-    bds_len   = BDS_Len;
-    bds_len   = correct_bdslen(bds_len, gribLen, bds-dbuf);
-    bds_nbits = BDS_NumBits;
-    bds_flag  = BDS_Flag;
-    bds_ubits = bds_flag & 15;
-    lspherc   =  bds_flag >> 7;
-    lcomplex  = (bds_flag >> 6)&1;
-    /* lcompress = (bds_flag >> 4)&1; */
-    
-    if ( bds_nbits != 8 && bds_nbits != 16 && bds_nbits != 24 && bds_nbits != 32 )
-      {
-	static int linfo = 1;
-	if ( linfo && bds_nbits != 0 )
-	  {
-	    linfo = 0;
-	    fprintf(stderr, "GRIB szip only supports 8, 16, 24 and 32 bit data!\n");
-	  }
-	return (rec_len);
-      }
+      if ( isec2[2] ==  32767 )
+	fprintf(grprsm, " Number of points along the second axis.      Not used\n");
+      else
+	fprintf(grprsm, " Number of points along the second axis.      %9d\n", isec2[2]);
 
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      bits_per_sample    = 8;
-    else
-#endif
-      bits_per_sample    = bds_nbits;
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
+      fprintf(grprsm, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      goto LABEL800;
+    }
+    */
+  /*
+    -----------------------------------------------------------------
+    Section 7.6 . Print triangular data
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 192 /* && ISEC1_CenterID == 78 */ )
+    {
+      fprintf(grprsm, " Data represent type = triangular   (Table 6) %9d\n", isec2[0]);
+      fprintf(grprsm, " Number of factor 2 in factorisation of Ni.   %9d\n", isec2[1]);
+      fprintf(grprsm, " Number of factor 3 in factorisation of Ni.   %9d\n", isec2[2]);
+      fprintf(grprsm, " Number of diamonds (Nd).                     %9d\n", isec2[3]);
+      fprintf(grprsm, " Number of triangular subdivisions of the\n");
+      fprintf(grprsm, "           icosahedron (Ni).                  %9d\n", isec2[4]);
+      fprintf(grprsm, " Flag for orientation of diamonds (Table A).  %9d\n", isec2[5]);
+      fprintf(grprsm, " Latitude of pole point.                      %9d\n", isec2[6]);
+      fprintf(grprsm, " Longitude of pole point.                     %9d\n", isec2[7]);
+      fprintf(grprsm, " Longitude of the first diamond.              %9d\n", isec2[8]);
+      fprintf(grprsm, " Flag for storage sequence (Table B).         %9d\n", isec2[9]);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      goto LABEL800;
+    }
+  /*
+    -----------------------------------------------------------------
+    Drop through to here => representation type not catered for.
+    -----------------------------------------------------------------
+  */
+  fprintf(grprsm, "GRPRS2 :Data representation type not catered for -%d\n", isec2[0]);
 
-#if defined (HAVE_LIBAEC)
-    strm.bits_per_sample = bits_per_sample;
-    strm.block_size      = PIXELS_PER_BLOCK;
-    strm.rsi             = PIXELS_PER_SCANLINE / PIXELS_PER_BLOCK;
-    strm.flags           = AEC_FLAGS;
-    if ( bds_nbits == 24 ) strm.flags |= AEC_DATA_3BYTE; 
-#else
-    sz_param.options_mask        = OPTIONS_MASK;
-    sz_param.bits_per_pixel      = bits_per_sample;
-    sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
-    sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
-#endif
+  goto LABEL900;
+  /*
+    -----------------------------------------------------------------
+    Section 8 . Print vertical coordinate parameters,
+                rotated grid information,
+                stretched grid information, if any.
+    -----------------------------------------------------------------
+  */
+ LABEL800:;
+  /*
+    Vertical coordinate parameters ...
+  */
+  if ( isec2[11] != 0 )
+    {
+      fprintf(grprsm, " \n");
+      fprintf(grprsm, " Vertical Coordinate Parameters.\n");
+      fprintf(grprsm, " -------------------------------\n");
+      for ( i = 10; i < isec2[11]+10; i++ )
+	fprintf(grprsm, "    %20.12f\n", fsec2[i]);
+    }
+  /*
+    Rotated and stretched grids introduced in Edition 1.
+  */
+  if ( iedit < 1 ) goto LABEL900;
+  /*
+    Rotated grid information ...
+  */
+  if ( isec2[0] == 10 || isec2[0] == 30 || 
+       isec2[0] == 14 || isec2[0] == 34 || 
+       isec2[0] == 60 || isec2[0] == 80 || 
+       isec2[0] == 30 )
+    {
+      fprintf(grprsm, " \n");
+      fprintf(grprsm, " Latitude of southern pole of rotation.       %9d\n", isec2[12]);
+      fprintf(grprsm, " Longitude of southern pole of rotation.      %9d\n", isec2[13]);
+      fprintf(grprsm, " Angle of rotation.                     %20.10f\n", fsec2[0]);
+    }
+  /*
+    Stretched grid information ...
+  */
+  if ( isec2[0] == 20 || isec2[0] == 30 || 
+       isec2[0] == 24 || isec2[0] == 34 || 
+       isec2[0] == 70 || isec2[0] == 80 )
+    {
+      fprintf(grprsm, " \n");
+      fprintf(grprsm, " Latitude of pole of stretching.              %9d\n", isec2[14]);
+      fprintf(grprsm, " Longitude of pole of stretching.             %9d\n", isec2[15]);
+      fprintf(grprsm, " Stretching factor.                     %20.10f\n", fsec2[1]);
+    }
 
-    if ( lspherc )
-      {
-	if ( lcomplex  )
-	  {
-	    int jup, ioff;
-	    jup  = bds[15];
-	    ioff = (jup+1)*(jup+2);
-	    bds_ext = 4 + 3 + 4*ioff;
-	  }
-	else
-	  {
-	    bds_ext = 4;
-	  }
-      }
+ LABEL900:;
 
-    datstart = bds_head + bds_ext;
+  return;
+}
 
-    datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
+{
+  int inum;
+  int j;
+  double *fsec2;
 
-    if ( datsize < MIN_SIZE ) return (rec_len);
-    /*
-    fprintf(stderr, "%d %d %d %d\n", bds_len, datstart, bds_len - datstart, datsize);
-    */
-    sourceLen = datsize;
-    destLen   = sbufsize;
-    
-    source = bds + datstart;
-    dest = sbuf;
+  inum = 10 + isec2[11];
 
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      {
-	long nelem;
-	nelem = sourceLen/3;
-	pbuf = (unsigned char*) Malloc(sourceLen);
-	for ( i = 0; i < nelem; i++ )
-	  {
-	    pbuf[        i] = source[3*i  ];
-	    pbuf[  nelem+i] = source[3*i+1];
-	    pbuf[2*nelem+i] = source[3*i+2];
-	  }
-	source = pbuf;
-      }
-#endif
+  fsec2 = (double*) Malloc((size_t)inum*sizeof(double));
+  if ( fsec2 == NULL ) SysError("No Memory!");
 
-#if defined (HAVE_LIBAEC)
-    strm.next_in = source;
-    strm.avail_in = sourceLen;
-    strm.next_out = dest;
-    strm.avail_out = destLen;
+  for ( j = 0; j < inum; j++ )
+     fsec2[j] = fsec2sp[j];
+  
+  gribPrintSec2DP(isec0, isec2, fsec2);
 
-    status = aec_buffer_encode(&strm);
-    if ( status != AEC_OK )
-      {
-       	if ( status != AEC_DATA_ERROR )
-	  Warning("AEC ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
-      }
+  Free(fsec2);
+}
 
-    destLen = strm.total_out;
-#else
-    status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
-    if ( status != SZ_OK )
-      {
-	if ( status == SZ_NO_ENCODER_ERROR )
-	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_PARAM_ERROR )
-	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_MEM_ERROR )
-	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_OUTBUFF_FULL )
-	  /*Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2)*/;
-	else
-	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
-      }
-#endif
-    
-    if ( pbuf ) Free(pbuf);
-    /*
-    fprintf(stderr, "sourceLen, destLen %d %d\n", sourceLen, destLen);
-    */
-    if ( destLen < MIN_COMPRESS*sourceLen )
-      {
-	source = bds + datstart + bds_zoffset;
-	memcpy(source, dest, destLen);
-	
-	/* ----++++ number of unused bits at end of section) */
+void gribPrintSec3DP(int *isec0, int *isec3, double *fsec3)
+{
+  /*
 
-	BDS_Flag -= bds_ubits;
-    
-	gribLenOld = gribLen;
+    Print the information in the Bit-Map Section
+    (Section 3) of decoded GRIB data.
 
-	if ( bds_ext )
-	  for ( i = bds_ext-1; i >= 0; --i )
-	    bds[bds_zoffset+bds_head+i] = bds[bds_head+i];
+    Input Parameters:
 
-	/*
-	fprintf(stderr, "destLen, datsize, datstart %d %d %d\n", destLen, datsize, datstart);
-	*/
-	/*	memcpy(bds + datstart + bds_zoffset, source, destLen); */
-	/*
-	  fprintf(stderr, "z>>> %d %d %d %d <<<\n", (int) bds[0+datstart+bds_zoffset],
-	    (int)bds[1+datstart+bds_zoffset], (int)bds[2+datstart+bds_zoffset], (int)bds[3+datstart+bds_zoffset]);
-	*/
-	if ( llarge )
-	  {
-	    if ( gribLenOld%120 )
-	      {
-		fprintf(stderr, "Internal problem, record length not multiple of 120!");
-		while ( gribLenOld%120 ) gribLenOld++;
-	      }
-	    gribLenOld = gribLenOld / (-120);
-	    gribLenOld = JP23SET - gribLenOld + 1;
+       isec0  - Array of decoded integers from Section 0
 
-	    SetLen3(bds, bds_zstart, gribLenOld);
-	    SetLen4(bds, bds_zstart+3, sourceLen);
-	    SetLen4(bds, bds_zstart+7, destLen);
-	  }
-	else
-	  {
-	    SetLen3(bds, bds_zstart, gribLenOld);
-	    SetLen3(bds, bds_zstart+3, sourceLen);
-	    SetLen3(bds, bds_zstart+6, destLen);
-	  }
+       isec3  - Array of decoded integers from Section 3
 
-	bdsLen = datstart + bds_zoffset + destLen;
+       fsec3  - Array of decoded floats from Section 3
 
-	bds[11] = 0;
-	bds[12] = 0;
-#if defined (HAVE_LIBAEC)
-	BDS_Z   = Z_AEC;
-#else
-	BDS_Z   = Z_SZIP;
-#endif
 
-	BDS_Flag += 16;
-	if ( (bdsLen%2) == 1 )
-	  {
-	    BDS_Flag += 8;
-	    bds[bdsLen++] = 0;
-	  }
+    Converted from EMOS routine GRPRS3.
 
-	SetLen3(bds, 0, bdsLen);
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-	gribLen = (bds - dbuf) + bdsLen;
+  */
 
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
+  UNUSED(isec0);
 
-	if ( llarge )
-	  {
-	    long itemp;
-	    long bdslen = gribLen - 4;
+  grsdef();
 
-	    /*
-	      If a very large product, the section 4 length field holds
-	      the number of bytes in the product after section 4 upto
-	      the end of the padding bytes.
-	      This is a fixup to get round the restriction on product lengths
-	      due to the count being only 24 bits. It is only possible because
-	      the (default) rounding for GRIB products is 120 bytes.
-	    */
-	    while ( gribLen%120 ) dbuf[gribLen++] = 0;
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 3 - Bit-map Section.\n");
+  fprintf(grprsm, " -------------------------------------\n");
 
-	    itemp = gribLen / (-120);
-	    itemp = JP23SET - itemp + 1;
+  if ( isec3[0] != 0 )
+    fprintf(grprsm, " Predetermined bit-map number.                %9d\n", isec3[0]);
+  else
+    fprintf(grprsm, " No predetermined bit-map.\n");
 
-	    SetLen3(dbuf, 4, itemp);
+  fprintf(grprsm, " Missing data value for integer data.    %14d\n", isec3[1]);
 
-	    bdslen = gribLen - bdslen;
+  fprintf(grprsm, " Missing data value for real data. %20.6g\n", fsec3[1]);
+}
 
-	    SetLen3(bds, 0, bdslen);
-	  }
-	else
-	  {
-	    SetLen3(dbuf, 4, gribLen);
-	  }
-      }
-    else
-      {
-      }
-    /*
-    fprintf(stderr, "%3d %3d griblen in %6d  out %6d  CR %g   slen %6d dlen %6d  CR %g\n",
-	    PDS_Parameter, PDS_Level1, gribLenOld, gribLen,
-	    ((double)gribLenOld)/gribLen, sourceLen, destLen,
-	    ((double)sourceLen)/destLen);
-    */
-  }
+void gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3sp)
+{
+  double fsec3[2];
 
-#else
+  fsec3[0] = fsec3sp[0];
+  fsec3[1] = fsec3sp[1];
   
-  UNUSED(sbuf);
-  UNUSED(sbufsize);
+  gribPrintSec3DP(isec0, isec3, fsec3);
+}
 
-  if ( libszwarn )
-    {
-      Warning("Compression disabled, szlib or libaec not available!");
-      libszwarn = 0;
-    }
-#endif
+void gribPrintSec4DP(int *isec0, int *isec4, double *fsec4)
+{
+  /*
 
-  if ( llarge )
-    while ( gribLen%120 ) dbuf[gribLen++] = 0;
-  else
-    while ( gribLen & 7 ) dbuf[gribLen++] = 0;
+    Print the information in the Binary Data Section
+    (Section 4) of decoded GRIB data.
 
-  rec_len = gribLen;
+    Input Parameters:
 
-  return (rec_len);
-}
+       isec0  - Array of decoded integers from Section 0
 
+       isec4  - Array of decoded integers from Section 4
 
-int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
-{
-#if ! (defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC))
-  static int libszwarn = 1;
-#endif
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  size_t gribLen = 0;
-  unsigned char *dest, *source;
-  size_t destLen, sourceLen;
-  int /* bds_len, */ bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress*/;
-  enum { bds_head = 11 };
-  int bds_ext = 0;
-  int bds_zoffset, bds_zstart;
-  int llarge = FALSE;
+       fsec4  - Array of decoded floats from Section 4
 
-  UNUSED(dbufsize);
 
-  long gribrecsize;
-  int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "GRIB message error\n");
-      return (0);
-    }
+    Converted from EMOS routine GRPRS4.
 
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
-    }
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  bds_zstart = 14;
+  */
+  int inum;
+  int j;
 
-  int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
-  if ( recLen > JP23SET ) llarge = TRUE;
+  UNUSED(isec0);
 
-  bds_zoffset = 12;
-  if ( llarge ) bds_zoffset += 2;
+  grsdef();
 
-  /* bds_len   = BDS_Len; */
-  bds_nbits = BDS_NumBits;
-  bds_flag  = BDS_Flag;
-  lspherc   =  bds_flag >> 7;
-  lcomplex  = (bds_flag >> 6)&1;
-  /* lcompress = (bds_flag >> 4)&1; */
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print integer information from isec4.
+    -----------------------------------------------------------------
+  */
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 4 - Binary Data  Section.\n");
+  fprintf(grprsm, " -------------------------------------\n");
 
-  if ( lspherc )
+  fprintf(grprsm, " Number of data values coded/decoded.         %9d\n", isec4[0]);
+  fprintf(grprsm, " Number of bits per data value.               %9d\n", isec4[1]);
+  fprintf(grprsm, " Type of data       (0=grid pt, 128=spectral).%9d\n", isec4[2]);
+  fprintf(grprsm, " Type of packing    (0=simple, 64=complex).   %9d\n", isec4[3]);
+  fprintf(grprsm, " Type of data       (0=float, 32=integer).    %9d\n", isec4[4]);
+  fprintf(grprsm, " Additional flags   (0=none, 16=present).     %9d\n", isec4[5]);
+  fprintf(grprsm, " Reserved.                                    %9d\n", isec4[6]);
+  fprintf(grprsm, " Number of values   (0=single, 64=matrix).    %9d\n", isec4[7]);
+  fprintf(grprsm, " Secondary bit-maps (0=none, 32=present).     %9d\n", isec4[8]);
+  fprintf(grprsm, " Values width       (0=constant, 16=variable).%9d\n", isec4[9]);
+  /*
+    If complex packing ..
+  */
+  if ( isec4[3] == 64 )
     {
-      if ( lcomplex  )
+      if ( isec4[2] == 128 )
 	{
-	  int jup, ioff;
-	  jup  = bds[bds_zoffset+15];
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
+	  fprintf(grprsm, " Byte offset of start of packed data (N).     %9d\n", isec4[15]);
+	  fprintf(grprsm, " Power (P * 1000).                            %9d\n", isec4[16]);
+	  fprintf(grprsm, " Pentagonal resolution parameter J for subset.%9d\n", isec4[17]);
+	  fprintf(grprsm, " Pentagonal resolution parameter K for subset.%9d\n", isec4[18]);
+	  fprintf(grprsm, " Pentagonal resolution parameter M for subset.%9d\n", isec4[19]);
 	}
       else
 	{
-	  bds_ext = 4;
-	}
+	  fprintf(grprsm, " Bits number of 2nd order values    (none=>0).%9d\n", isec4[10]);
+	  fprintf(grprsm, " General extend. 2-order packing (0=no,8=yes).%9d\n", isec4[11]);
+	  fprintf(grprsm, " Boustrophedonic ordering        (0=no,4=yes).%9d\n", isec4[12]);
+	  fprintf(grprsm, " Spatial differencing order          (0=none).%9d\n", isec4[13]+isec4[14]);
+        }
     }
-
-  size_t datstart = bds_head + (size_t)bds_ext;
-
-  source = bds + datstart + bds_zoffset;
-  if ( llarge )
-    sourceLen = ((size_t) ((bds[21]<<24)+(bds[22]<<16)+(bds[23]<<8)+bds[24]));
-  else
-    sourceLen = ((size_t) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
-
-  nerr = grib1Sections(dbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+  /*
+    Number of non-missing values
+  */
+  if ( isec4[20] != 0 )
+    fprintf(grprsm, " Number of non-missing values                 %9d\n", isec4[20]);
+  /*
+    Information on matrix of values , if present.
+  */
+  if ( isec4[7] == 64 )
     {
-      fprintf(stdout, "GRIB message error\n");
-      return (0);
+      fprintf(grprsm, " First dimension (rows) of each matrix.       %9d\n", isec4[49]);
+      fprintf(grprsm, " Second dimension (columns) of each matrix.   %9d\n", isec4[50]);
+      fprintf(grprsm, " First dimension coordinate values definition.%9d\n", isec4[51]);
+      fprintf(grprsm, " (Code Table 12)\n");
+      fprintf(grprsm, " NC1 - Number of coefficients for 1st dimension.%7d\n", isec4[52]);
+      fprintf(grprsm, " Second dimension coordinate values definition.%8d\n", isec4[53]);
+      fprintf(grprsm, " (Code Table 12)\n");
+      fprintf(grprsm, " NC2 - Number of coefficients for 2nd dimension.%7d\n", isec4[54]);
+      fprintf(grprsm, " 1st dimension physical signifance (Table 13). %8d\n", isec4[55]);
+      fprintf(grprsm, " 2nd dimension physical signifance (Table 13).%8d\n", isec4[56]);
     }
+  /*
+    -----------------------------------------------------------------
+    Section 2. Print values from fsec4.
+    -----------------------------------------------------------------
+  */
 
-  if ( nerr > 0 )
+  inum = isec4[0];
+  if ( inum <  0 ) inum = - inum;
+  if ( inum > 20 ) inum = 20;
+  /*
+    Print first inum values.
+  */
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " First %4d data values.\n", inum);
+
+  if ( isec4[4] == 0 )
     {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
+      /*
+	Print real values ...
+      */
+      for ( j = 0; j < inum; j++ )
+	{
+	  if ( fabs(fsec4[j]) > 0 )
+	    {
+	      if ( fabs(fsec4[j]) >= 0.1 && fabs(fsec4[j]) <= 1.e8 )
+		fprintf(grprsm, " %#16.8G    \n", fsec4[j]);
+	      else
+		fprintf(grprsm, " %#20.8E\n", fsec4[j]);
+	    }
+	  else
+	    fprintf(grprsm, " %#16.0f    \n", fabs(fsec4[j]));
+	}
     }
-
-  dest = bds + datstart;
-  if ( llarge )
-    destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
   else
-    destLen = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
-
-  BDS_Flag = (unsigned char)(BDS_Flag - 16);
-
-  size_t bdsLen = datstart + destLen;
-
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
-  {
-    int status;
-    long i;
-    size_t tmpLen;
-    int bds_ubits;
-    int bits_per_sample;
-#if defined (HAVE_LIBAEC)
-    struct aec_stream strm;
-#else
-    SZ_com_t sz_param;          /* szip parameter block */
-#endif
-
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      bits_per_sample    = 8;
-    else
-#endif
-      bits_per_sample    = bds_nbits;
-
-#if defined (HAVE_LIBAEC)
-    strm.bits_per_sample         = bits_per_sample;
-    strm.block_size              = PIXELS_PER_BLOCK;
-    strm.rsi                     = PIXELS_PER_SCANLINE / PIXELS_PER_BLOCK;
-    strm.flags                   = AEC_FLAGS;
-    if ( bds_nbits == 24 ) strm.flags |= AEC_DATA_3BYTE; 
-#else
-    sz_param.options_mask        = OPTIONS_MASK;
-    sz_param.bits_per_pixel      = bits_per_sample;
-    sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
-    sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
-#endif
-
-    if ( bds_ext )
-      for ( i = 0; i < bds_ext; ++i )
-	bds[bds_head+i] = bds[bds_zoffset+bds_head+i];
-
-    /*
-    fprintf(stderr, "gribUnzip: sourceLen %ld; destLen %ld\n", (long)sourceLen, (long)destLen);
-    fprintf(stderr, "gribUnzip: sourceOff %d; destOff %d\n", bds[12], bds[11]);
-    fprintf(stderr, "gribUnzip: reclen %d; bdslen %d\n", recLen, bdsLen);
-    */
-
-    tmpLen = destLen;
-#if defined (HAVE_LIBAEC)
-    strm.next_in   = source;
-    strm.avail_in  = sourceLen;
-    strm.next_out  = dest;
-    strm.avail_out = tmpLen;
-
-    status = aec_buffer_decode(&strm);
-    if ( status != AEC_OK )
-      Warning("AEC ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
-
-    tmpLen = strm.total_out;
-#else
-    status = SZ_BufftoBuffDecompress(dest, &tmpLen, source, sourceLen, &sz_param);
-    if ( status != SZ_OK )
-      {
-	if ( status == SZ_NO_ENCODER_ERROR )
-	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_PARAM_ERROR )
-	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_MEM_ERROR )
-	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else if ( status == SZ_OUTBUFF_FULL )
-	  Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2);
-	else
-	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
-      }
-#endif
-    /*
-    fprintf(stderr, "gribUnzip: sl = %ld  dl = %ld   tl = %ld\n",
-	    (long)sourceLen, (long)destLen,(long) tmpLen);
-    */
-    if ( tmpLen != destLen )
-      Warning("unzip size differ: code %3d level %3d  ibuflen %ld ubuflen %ld",
-	      PDS_Parameter, PDS_Level2, (long) destLen, (long) tmpLen);
-
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      {
-	long nelem;
-	unsigned char *pbuf;
-	nelem = tmpLen/3;
-	pbuf = (unsigned char*) Malloc(tmpLen);
-	for ( i = 0; i < nelem; i++ )
-	  {
-	    pbuf[3*i  ] = dest[        i];
-	    pbuf[3*i+1] = dest[  nelem+i];
-	    pbuf[3*i+2] = dest[2*nelem+i];
-	  }
-	memcpy(dest, pbuf, tmpLen);
-	Free(pbuf);
-      }
-#endif
-
-    bds_ubits = BDS_Flag & 15;
-    BDS_Flag -= bds_ubits;
-
-    if ( (bdsLen%2) == 1 )
-      {
-	BDS_Flag += 8;
-	bds[bdsLen++] = 0;
-      }
-
-    SetLen3(bds, 0, bdsLen);
-
-    gribLen = (bds - dbuf) + bdsLen;
-    
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
-
-    if ( llarge )
-      {
-	long itemp;
-        bdsLen = gribLen - 4;
-	/*
-	  If a very large product, the section 4 length field holds
-	  the number of bytes in the product after section 4 upto
-	  the end of the padding bytes.
-	  This is a fixup to get round the restriction on product lengths
-	  due to the count being only 24 bits. It is only possible because
-	  the (default) rounding for GRIB products is 120 bytes.
-	*/
-	while ( gribLen%120 ) dbuf[gribLen++] = 0;
-
-	if ( gribLen != (size_t)recLen )
-	  fprintf(stderr, "Internal problem, recLen and gribLen differ!\n");
-	
-	itemp = gribLen / (-120);
-	itemp = JP23SET - itemp + 1;
-	
-	SetLen3(dbuf, 4, itemp);
-
-	bdsLen = gribLen - bdsLen;
-	    
-	SetLen3(bds, 0, bdsLen);
-      }
-    else
-      {
-	SetLen3(dbuf, 4, recLen);
-      }
-    /*
-    fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
-    */
-    if ( llarge )
-      while ( gribLen%120 ) dbuf[gribLen++] = 0;
-    else
-      while ( gribLen & 7 ) dbuf[gribLen++] = 0;
-    /*
-    fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
-    */
-  }
-#else
-  UNUSED(bds_nbits);
-  UNUSED(sourceLen);
-  UNUSED(source);
-  UNUSED(bdsLen);
-  UNUSED(dest);
-  
-  if ( libszwarn )
     {
-      Warning("Decompression disabled, szlib or libaec not available!");
-      libszwarn = 0;
-    }
-#endif
-
-  return (int)gribLen;
-}
-#include <stdio.h>
-#include <math.h>
-
-
-
-static
-int rowina2(double *p, int ko, int ki, double *pw,
-	    int kcode, double msval, int *kret)
-{
-  /* System generated locals */
-  int pw_dim1, pw_offset, i_1;
-
-  /* Local variables */
-  double zwt1, zrdi, zpos;
-  int jl, ip;
-  double zdo, zwt;
-
-  /* Parameter adjustments */
-  --p;
-  pw_dim1 = ko + 3;
-  pw_offset = pw_dim1;
-  pw -= pw_offset;
-
-  /* **** ROWINA2 - Interpolation of row of values. */
-  /*     Input Parameters. */
-  /*     ----------------- */
-  /*     P      - Row of values to be interpolated. */
-  /*              Dimension must be at least KO. */
-  /*     KO     - Number of values required. */
-  /*     KI     - Number of values in P on input. */
-  /*     PW     - Working array. */
-  /*              Dimension must be at least (0:KO+2,3). */
-  /*     KCODE  - Interpolation required. */
-  /*              1 , linear. */
-  /*              3 , cubic. */
-  /*     PMSVAL - Value used for missing data indicator. */
+      /*
+	Print integer values ...
+      */
+      fprintf(grprsm, " Print of integer values not supported\n");
+      /*
+        CALL SETPAR(IBIT,IDUM,IDUM)
+        DO 212 J=1,INUM
+           INSPT = 0
+           CALL INXBIT(IVALUE,1,INSPT,FSEC4(J),1,IBIT,IBIT,'C',IRET)
+           WRITE (*,9033) IVALUE
+ 9033 FORMAT(' ',I15)
+  212   CONTINUE
+      ENDIF
+      */
+    }
+}
 
-  /*     Output Parameters. */
-  /*     ------------------ */
-  /*     P     - Now contains KO values. */
-  /*     KRET  - Return code */
-  /*             0, OK */
-  /*             Non-zero, error */
+void gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4sp)
+{
+  int inum;
+  int j;
+  double fsec4[20];
 
-  /*     Author. */
-  /*     ------- */
-  /*     J.D.Chambers    ECMWF     22.07.94 */
+  inum = isec4[0];
+  if ( inum <  0 ) inum = -inum;
+  if ( inum > 20 ) inum = 20;
 
-  /*     ********************************    */
-  /*     Section 1.  Linear interpolation .. */
-  /*     ********************************    */
+  for ( j = 0; j < inum; j++ ) fsec4[j] = fsec4sp[j];
+  
+  gribPrintSec4DP(isec0, isec4, fsec4);
+}
 
-  *kret = 0;
+void gribPrintSec4Wave(int *isec4)
+{
+  /*
 
-  if ( kcode == 1 )
-    {
-      /*    Move input values to work array */
-      for ( jl = 1; jl <= ki; ++jl )
-	pw[jl + pw_dim1] = p[jl];
+    Print the wave coordinate information in the Binary Data
+    Section (Section 4) of decoded GRIB data.
 
-      /*    Arrange wrap-around value in work array */
-      pw[ki + 1 + pw_dim1] = p[1];
+    Input Parameters:
 
-      /*    Set up constants to be used to figure out weighting for */
-      /*    values in interpolation. */
-      zrdi = (double) ki;
-      zdo = 1.0 / (double) ko;
+       isec4 - Array of decoded integers from Section 4
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
-	{
+    Comments:
 
-	  /*    Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+       Wave coordinate information held in isec4 are 32-bit floats,
+       hence the PTEMP and NTEMP used for printing are 4-byte variables.
 
-	  /*    Get the current array position(minus 1) from the weight - */
-	  /*    note the implicit truncation. */
-	  ip = (int) zwt;
 
-	  /*    If the left value is missing, use the right value */
-	  if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
-	    {
-	      p[jl] = pw[ip + 2 + pw_dim1];
-	    }
-	  /*    If the right value is missing, use the left value */
-	  else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
-	    {
-	      p[jl] = pw[ip + 1 + pw_dim1];
-	    }
-	  /*    If neither missing, interpolate ... */
-	  else
-	    {
+    Converted from EMOS routine GRPRS4W.
 
-	      /*       Adjust the weight to range (0.0 to 1.0) */
-	      zwt -= ip;
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-	      /*       Interpolate using the weighted values on either side */
-	      /*       of the output point position */
-	      p[jl] = (1.0 - zwt) * pw[ip + 1 + pw_dim1] +
-		zwt * pw[ip + 2 + pw_dim1];
-	    }
-	}
+  */
+  int    jloop;
+  int    ntemp[100];
+  float *ptemp;
 
-      /*     *******************************    */
-      /*     Section 2.  Cubic interpolation .. */
-      /*     *******************************    */
+  grsdef();
 
-    }
-  else if ( kcode == 3 )
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print integer information from isec4.
+    -----------------------------------------------------------------
+  */
+  fprintf(grprsm, " Coefficients defining first dimension coordinates:\n");
+  for ( jloop = 0; jloop < isec4[52]; jloop++ )
     {
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
-	{
-          if ( IS_EQUAL(p[jl], msval) )
-	    {
-	      fprintf(stderr," ROWINA2: ");
-	      fprintf(stderr," Cubic interpolation not supported");
-	      fprintf(stderr," for fields containing missing data.\n");
-	      *kret = 1;
-	      goto L900;
-	    }
-          pw[jl + pw_dim1] = p[jl];
-	}
-      pw[pw_dim1] = p[ki];
-      pw[ki + 1 + pw_dim1] = p[1];
-      pw[ki + 2 + pw_dim1] = p[2];
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
-	{
-          pw[jl + (pw_dim1 << 1)] =
-	        - pw[jl - 1 + pw_dim1] / 3.0 -
-	          pw[jl     + pw_dim1] * 0.5 +
-	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
-          pw[jl + 1 + pw_dim1 * 3] =
-                  pw[jl - 1 + pw_dim1] / 6.0 -
-                  pw[jl     + pw_dim1] +
-                  pw[jl + 1 + pw_dim1] * 0.5 +
-                  pw[jl + 2 + pw_dim1] / 3.0;
-	}
-
-      scm0_double(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
-		  &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
-
-      zrdi = (double) ki;
-      zdo = 1.0 / (double) ko;
-      for ( jl = 1; jl <= ko; ++jl )
-	{
-          zpos = (jl - 1) * zdo;
-          zwt = zpos * zrdi;
-          ip = (int) zwt + 1;
-          zwt = zwt + 1.0 - ip;
-          zwt1 = 1.0 - zwt;
-          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
-	}
-
+      ntemp[jloop] = isec4[59 + jloop];
+      ptemp = (float *) &ntemp[jloop];
+      fprintf(grprsm, "%20.10f\n", *ptemp);
     }
-  else
+  fprintf(grprsm, " Coefficients defining second dimension coordinates:\n");
+  for ( jloop = 0; jloop < isec4[54]; jloop++ )
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA2:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      ntemp[jloop] = isec4[59 + isec4[52] + jloop];
+      ptemp = (float *) &ntemp[jloop];
+      fprintf(grprsm, "%20.10f\n", *ptemp);
     }
+}
+#if defined (HAVE_CONFIG_H)
+#endif
 
-L900:
-    return 0;
-} /* rowina2 */
+#include <string.h>
+#include <ctype.h>
 
 
 
-int qu2reg2(double *pfield, int *kpoint, int klat, int klon,
-	    double *ztemp, double msval, int *kret)
+int gribOpen(const char *filename, const char *mode)
 {
-   /* System generated locals */
-   int i_1, i_2;
-   int kcode = 1;
+  int fileID = fileOpen(filename, mode);
 
-   /* Local variables */
-   int ilii, ilio, icode;
-   double *zline = NULL;
-   double *zwork = NULL;
-   int iregno, iquano, j210, j220, j230, j240, j225;
+#if defined (__sun)
+  if ( fileID != FILE_UNDEFID && tolower(*mode) == 'r' )
+    {
+      fileSetBufferType(fileID, FILE_BUFTYPE_MMAP);
+    }
+#endif
 
+  return fileID;  
+}
 
-   zline = (double*) Malloc(2*(size_t)klon*sizeof(double));
-   if ( zline == NULL ) SysError("No Memory!");
 
-   zwork = (double*) Malloc(3*(2*(size_t)klon+3)*sizeof(double));
-   if ( zwork == NULL ) SysError("No Memory!");
+void gribClose(int fileID)
+{
+  fileClose(fileID);
+}
 
-   /* Parameter adjustments */
-   --pfield;
-   --kpoint;
 
-/* **** QU2REG - Convert quasi-regular grid data to regular. */
-/*     Input Parameters. */
-/*     ----------------- */
-/*     PFIELD     - Array containing quasi-regular grid */
-/*                  data. */
-/*     KPOINT     - Array containing list of the number of */
-/*                  points on each latitude (or longitude) of */
-/*                  the quasi-regular grid. */
-/*     KLAT       - Number of latitude lines */
-/*     KLON       - Number of longitude lines */
-/*     KCODE      - Interpolation required. */
-/*                  1 , linear - data quasi-regular on */
-/*                               latitude lines. */
-/*                  3 , cubic -  data quasi-regular on */
-/*                               latitude lines. */
-/*                  11, linear - data quasi-regular on */
-/*                               longitude lines. */
-/*                  13, cubic -  data quasi-regular on */
-/*                               longitude lines. */
-/*     PMSVAL     - Value used for missing data indicator. */
-/*     Output Parameters. */
-/*     ------------------ */
-/*     KRET       - return code */
-/*                  0 = OK */
-/*                  non-zero indicates fatal error */
-/*     PFIELD     - Array containing regular grid data. */
-/*     Author. */
-/*     ------- */
-/*     J.D.Chambers     ECMWF      22.07.94 */
-/*     J.D.Chambers     ECMWF      13.09.94 */
-/*     Add return code KRET and remove calls to ABORT. */
+off_t gribGetPos(int fileID)
+{
+  return fileGetPos(fileID);
+}
 
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+int gribCheckSeek(int fileID, long *offset, int *version)
+{
+  int ierr = gribFileSeek(fileID, offset);
 
-   *kret = 0;
+  *version = -1;
+  if ( !ierr )
+    {
+      char buffer[4];
+     if ( fileRead(fileID, buffer, 4) == 4 )
+	*version = buffer[3];
+    }
 
-/* Check input parameters. */
+  return ierr;
+}
 
-   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
-      fprintf(stderr," QU2REG :");
-      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
-      *kret = 1;
-      goto L900;
-   }
 
-/* Set array indices to 0. */
+int gribFileSeek(int fileID, long *offset)
+{
+  /* position file pointer after GRIB */
+  const long GRIB = 0x47524942;
+  long code = 0;
+  int ch;
+  int retry = 4096*4096;
 
-   ilii = 0;
-   ilio = 0;
+  *offset = 0;
 
-/* Establish values of loop parameters. */
+  void *fileptr = filePtr(fileID);
 
-   if (kcode > 10) {
+  while ( retry-- )
+    {
+      ch = filePtrGetc(fileptr);
+      if ( ch == EOF ) return -1;
+    
+      code = ( (code << 8) + ch ) & 0xFFFFFFFF;
+      if ( code == GRIB )
+	{
+	  if ( CGRIBEX_Debug ) Message("record offset = %ld", *offset);
+	  return 0;
+	}
 
-/*    Quasi-regular along longitude lines. */
+      (*offset)++;
+    }
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
+  if ( CGRIBEX_Debug ) Message("record offset = %ld", *offset);
 
-/*    Quasi-regular along latitude lines. */
+  return 1;
+}
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+static inline
+unsigned read3ByteMSBFirst(void *fileptr)
+{
+  unsigned b1 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b2 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b3 = (unsigned)(filePtrGetc(fileptr));
+  return GET_UINT3(b1, b2, b3);
+}
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+size_t gribReadSize(int fileID)
+{
+  size_t rgribsize = 0;
+  void *fileptr = filePtr(fileID);
+  off_t pos = fileGetPos(fileID); 
 
-      if (iregno != kpoint[j230]) {
+  unsigned gribsize = read3ByteMSBFirst(fileptr);
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
+  int gribversion = filePtrGetc(fileptr);
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+  if ( gribsize == 24 && gribversion != 1 && gribversion != 2 ) gribversion = 0;
 
-/*       and interpolate this line. */
+  if ( CGRIBEX_Debug ) Message("gribversion = %d", gribversion);
 
-         rowina2(zline, iregno, kpoint[j230], zwork, icode, msval, kret);
-         if (*kret != 0) goto L900;
+  if ( gribversion == 0 )
+    {
+      unsigned gdssize = 0, bmssize = 0;
+      unsigned issize = 4, essize = 4;
 
-/*       Add regular grid values for this line to the
-         temporary array. */
+      unsigned pdssize = gribsize;
+      fileSetPos(fileID, (off_t) 3, SEEK_CUR);
+      if ( CGRIBEX_Debug ) Message("pdssize     = %u", pdssize);
+      int flag = filePtrGetc(fileptr);
+      if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
+  
+      fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
 
-         i_2 = iregno;
-         for (j220 = 1; j220 <= i_2; ++j220) {
-            ++ilio;
-            ztemp[ilio - 1] = zline[j220 - 1];
-         }
+      if ( flag & 128 )
+	{
+	  gdssize = read3ByteMSBFirst(fileptr);
+	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
+	  if ( CGRIBEX_Debug ) Message("gdssize     = %u", gdssize);
+	}
 
-      } else {
+      if ( flag & 64 )
+	{
+	  bmssize = read3ByteMSBFirst(fileptr);
+	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
+	  if ( CGRIBEX_Debug ) Message("bmssize     = %u", bmssize);
+	}
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+      unsigned bdssize = read3ByteMSBFirst(fileptr);
+      if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
+      gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
+      rgribsize = (size_t) gribsize;
+    }
+  else if ( gribversion == 1 )
+    {
+      if ( gribsize > JP23SET ) // Large GRIB record
+	{
+	  unsigned pdssize = read3ByteMSBFirst(fileptr);
+	  if ( CGRIBEX_Debug ) Message("pdssize     = %u", pdssize);
 
-/* Copy temporary array to user array. */
+	  int flag;
+	  for ( int i = 0; i < 5; ++i ) flag = filePtrGetc(fileptr);
+	  if ( CGRIBEX_Debug ) Message("flag        = %d", flag);
+  
+	  fileSetPos(fileID, (off_t) pdssize-8, SEEK_CUR);
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+          unsigned gdssize = 0;
+	  if ( flag & 128 )
+	    {
+	      gdssize = read3ByteMSBFirst(fileptr);
+	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
+	      if ( CGRIBEX_Debug ) Message("gdssize     = %u", gdssize);
+	    }
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+          unsigned bmssize = 0;
+	  if ( flag & 64 )
+	    {
+	      bmssize = read3ByteMSBFirst(fileptr);
+	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
+	      if ( CGRIBEX_Debug ) Message("bmssize     = %u", bmssize);
+	    }
 
-L900:
+	  unsigned bdssize = read3ByteMSBFirst(fileptr);
+	  if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
+          if ( bdssize <= 120 )
+            {
+              const int issize = 4;
+              gribsize &= JP23SET;
+              gribsize *= 120;
+              bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
+              if ( CGRIBEX_Debug ) Message("bdssize     = %u", bdssize);
 
-   Free(zline);
-   Free(zwork);
+              gribsize = issize + pdssize + gdssize + bmssize + bdssize + 4;
+            }
+	}
+      rgribsize = (size_t) gribsize;
+    }
+  else if ( gribversion == 2 )
+    {
+      /* we set gribsize the following way because it doesn't matter then
+	 whether int is 4 or 8 bytes long - we don't have to care if the size
+	 really fits: if it does not, the record can not be read at all */
+      rgribsize = 0;
+      for ( int i = 0; i < 8; i++ ) rgribsize = (rgribsize << 8) | filePtrGetc(fileptr);
+    }
+  else
+    {
+      rgribsize = 0;
+      Warning("GRIB version %d unsupported!", gribversion);
+    }
 
-   return 0;
-} /* qu2reg2 */
+  if ( filePtrEOF(fileptr) ) rgribsize = 0;
 
+  if ( CGRIBEX_Debug ) Message("gribsize = %zu", rgribsize);
 
+  fileSetPos(fileID, pos, SEEK_SET);
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
+  return rgribsize;
+}
 
-/* calculate_pfactor: source code from grib_api-1.8.0 */
-double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
-{
-  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
-  long loop, index, m, n = 0;
-  double pFactor, zeps = 1.0e-15;
-  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
-  double* weights, range, * norms;
-  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
-  double numerator = 0.0, denominator = 0.0, slope;
 
-  /*
-  // Setup the weights
-   */
+size_t gribGetSize(int fileID)
+{
+  long offset;
+  int ierr = gribFileSeek(fileID, &offset); // position file pointer after GRIB
+  if ( ierr > 0 )
+    {
+      Warning("GRIB record not found!");
+      return 0;
+    }
 
-  range = (double) (ismax - ismin +1);
+  if      ( ierr == -1 ) return 0;
+  else if ( ierr ==  1 ) return 0;
 
-  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
-  for( loop = ismin; loop <= ismax; loop++ )
-    weights[loop] = range / (double) (loop-ismin+1);
-  /*
-  // Compute norms
-  // Handle values 2 at a time (real and imaginary parts).
-   */
-  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  size_t recSize = gribReadSize(fileID);
 
-  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
-  /*
-  // Form norms for the rows which contain part of the unscaled subset.
-   */
+  if ( CGRIBEX_Debug ) Message("recsize = %zu", recSize);
 
-  index = -2;
-  for( m = 0; m < subsetTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      index += 2;
-      if( n >= subsetTruncation ) {
-        double tval = spectralField[index];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-        tval = spectralField[index+1];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-      }
-    }
-  /*
-  // Form norms for the rows which do not contain part of the unscaled subset.
-   */
+  fileSetPos(fileID, (off_t) -4, SEEK_CUR);
 
-  for( m = subsetTruncation; m <= fieldTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      double tval = spectralField[index];
-      index += 2;
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-      tval = spectralField[index+1];
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-    }
+  return recSize;
+}
 
-  /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    norms[n] = norms[n] > zeps ? norms[n] : zeps;
-    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
-  }
+int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
+{
+  long offset;
+  int ierr = gribFileSeek(fileID, &offset); // position file pointer after GRIB
+  if ( ierr > 0 )
+    {
+      Warning("GRIB record not found!");
+      return -2;
+    }
 
-  /*
-  // Do linear fit to find the slope
-   */
+  if      ( ierr == -1 ) { *buffersize = 0; return -1; }
+  else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    x = log( (double) (loop*(loop+1)) );
-    y = log( norms[loop] );
-    weightedSumOverX = weightedSumOverX + x * weights[loop];
-    weightedSumOverY = weightedSumOverY + y * weights[loop];
-    sumOfWeights = sumOfWeights + weights[loop];
-  }
-  weightedSumOverX = weightedSumOverX / sumOfWeights;
-  weightedSumOverY = weightedSumOverY / sumOfWeights;
+  size_t recSize  = gribReadSize(fileID);
+  size_t readSize = recSize;
 
-  /*
-  // Perform a least square fit for the equation
-   */
+  if ( readSize > *buffersize )
+    {
+      readSize = *buffersize;
+      ierr = -3;          // Tell the caller that the buffer was insufficient.
+    }
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
+  *buffersize = recSize;  // Inform the caller about the record size.
 
-    x = log( (double)(loop*(loop+1)) );
-    y = log( norms[loop] );
-    numerator =
-      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
-    denominator =
-      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
-  }
-  slope = numerator / denominator;
+  // Write the stuff to the buffer that has already been read in gribFileSeek().
+  buffer[0] = 'G';
+  buffer[1] = 'R';
+  buffer[2] = 'I';
+  buffer[3] = 'B';
 
-  Free(weights);
-  Free(norms);
+  readSize -= 4;
+  // Read the rest of the record into the buffer.
+  size_t nread = fileRead(fileID, &buffer[4], readSize);
 
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
+  if ( nread != readSize ) ierr = 1;
 
-  return pFactor;
+  return ierr;
 }
 
-void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
-{
-  double power;
-  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
-  if ( scale == NULL ) SysError("No Memory!");
+int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
+{
+  int nwrite = 0;
 
-  if ( pcScale < -10000 || pcScale > 10000 )
+  if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
     {
-      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
-      return;
-   }
+      perror(__func__);
+      nwrite = -1;
+    }
 
-  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
+  return nwrite;
+}
+#include <string.h>
+#include <ctype.h>
 
-  if ( pcScale == 0 ) return;
 
-  power = (double) pcScale / 1000.;
-  scale[0] = 1.0;
+FILE *grprsm = NULL;
+double fref;
+double fmaxval;
+int nfref;
+int nfmaxval;
+int nrnd;
+int ndbg;
+int nvck;
+int nonoff;
+int noabort;
+int num2ok;
+int next2o;
+int nloc2o;
+int nsubce;
+int grib_calendar = -1;
 
-  if (pcScale != 1000)
-    for ( int n = 1; n <= trunc; n++ )
-      scale[n] = pow((double) (n*(n+1)), power);
-  else
-    for ( int n = 1; n <= trunc; n++ )
-      scale[n] =     (double) (n*(n+1));
 
-  if ( inv )
-    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+void gribSetCalendar(int calendar)
+{
+  grib_calendar = calendar;
+}
 
-  /* Scale the values */
 
-  size_t index = 0;
+void grsdef(void)
+{
+  /*
+C---->
+C**** GRSDEF - Initial (default) setting of common area variables
+C              for GRIBEX package.
+C
+C     Purpose.
+C     --------
+C
+C     Sets initial values for common area variables for all
+C     routines of GRIBEX package, if not already done.
+C
+C**   Interface.
+C     ----------
+C
+C     CALL GRSDEF
+C
+C     Input Parameters.
+C     -----------------
+C
+C     None.
+C
+C     Output Parameters.
+C     ------------------
+C
+C     None.
+C
+C     Method.
+C     -------
+C
+C     Self-explanatory.
+C
+C     Externals.
+C     ----------
+C
+C     None.
+C
+C     Reference.
+C     ----------
+C
+C     See subroutine GRIBEX.
+C
+C     Comments.
+C     ---------
+C
+C     None
+C
+C     Author.
+C     -------
+C
+C     J. Clochard, Meteo France, for ECMWF - March 1998.
+C
+C     Modifications.
+C     --------------
+C
+C     J. Clochard, Meteo France, for ECMWF - June 1999.
+C     Add variable NSUBCE.
+C     Use a static variable to determine if initialisation has already
+C     been done. NUSER removed .
+C     Reverse defaults for NEXT2O and NLOC2O, for consistency with
+C     version 13.023 of software .
+C
+  */
+  /*
+C     ----------------------------------------------------------------
+C*    Section 0 . Definition of variables.
+C     ----------------------------------------------------------------
+  */
+  char *envString;
+  char *env_stream;
+  static bool lfirst = true;
+  extern int CGRIBEX_Const;
 
-  for ( int m = 0;   m < pcStart; m++ )
-    for ( int n = m; n <= trunc; n++, index += 2 )
-      if ( n >= pcStart )
-        {
-          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
-          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
-        }
+  if ( ! lfirst ) return;
 
-  for ( int m = pcStart; m <= trunc; m++ )
-    for ( int n = m;     n <= trunc; n++, index += 2 )
-      {
-	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
-	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
-      }
+  /*
+    ----------------------------------------------------------------
+    Section 1 . Set values, conditionally.
+    ----------------------------------------------------------------
+  */
+  /*
+    Common area variables have not been set. Set them.
+    
+    User supplied reference value.
+  */
+  fref   = 0.0;
+  /*
+    Reference value supplied by user flag. Set to off.
+  */
+  nfref  = 0;
+  /*
+    User supplied maximum value.
+  */
+  fmaxval   = 0.0;
+  /*
+    Maximum value supplied by user flag. Set to off.
+  */
+  nfmaxval  = 0;
+  /*
+    Set rounding to 120 bytes on.
+  */
+  nrnd   = 1;
+  /*
+    Set GRIB calendar.
+  */
+  if ( grib_calendar == -1 )
+    {
+      grib_calendar = CALENDAR_PROLEPTIC;
+  
+      envString = getenv("GRIB_CALENDAR");
+      if ( envString )
+	{
+	  if      ( strncmp(envString, "standard", 8) == 0 )
+	    grib_calendar = CALENDAR_STANDARD;
+	  else if ( strncmp(envString, "proleptic", 9) == 0 )
+	    grib_calendar = CALENDAR_PROLEPTIC;
+	  else if ( strncmp(envString, "360days", 7) == 0 )
+	    grib_calendar = CALENDAR_360DAYS;
+	  else if ( strncmp(envString, "365days", 7) == 0 )
+	    grib_calendar = CALENDAR_365DAYS;
+	  else if ( strncmp(envString, "366days", 7) == 0 )
+	    grib_calendar = CALENDAR_366DAYS;
+	  else if ( strncmp(envString, "none", 4) == 0 )
+	    grib_calendar = CALENDAR_NONE;
+	}
+    }
+  /*
+    Set debug print off.
+  */
+  ndbg   = 0;
+  
+  envString = getenv("GRIBEX_DEBUG");
+  if ( envString != NULL )
+    {
+      if ( !strncmp(envString, "ON", 2) )
+        ndbg = 1;
+      else if( *envString == '1')
+        ndbg = 1;
+      else if( *envString == '2')
+        ndbg = 2;
+      else
+        ndbg = 0;
+    }
+  /*
+    Set GRIBEX compatibility mode.
+  */
+  envString = getenv("GRIB_GRIBEX_MODE_ON");
+  if ( envString != NULL )
+    {
+      if ( atoi(envString) == 1 ) CGRIBEX_Const = 0;
+    }
 
-  Free(scale);
+  /*
+    Set GRIB value checking on.
+  */
+  nvck   = 1;
+  
+  envString = getenv("GRIBEX_CHECK");
+  if ( envString )
+    {
+      if ( !strncmp(envString, "OFF", 3) )
+        nvck = 0;
+      else
+        nvck = 1;
+    }
+  /*
+    See if output stream needs changing
+  */
+  grprsm = stdout;
+  env_stream = getenv("GRPRS_STREAM");
+  if ( env_stream )
+    {
+      if ( isdigit((int) env_stream[0]) )
+	{
+	  int unit;
+	  unit = atoi(env_stream);
+	  if ( unit < 1 || unit > 99 )
+	    Warning("Invalid number for GRPRS_STREAM: %d", unit);
+	  else if ( unit == 2 )
+	    grprsm = stderr;
+	  else if ( unit == 6 )
+	    grprsm = stdout;
+	  else
+	    {
+	      char filename[] = "unit.00";
+	      sprintf(filename, "%2.2d", unit);
+	      grprsm = fopen(filename, "w");
+	      if ( ! grprsm )
+		SysError("GRPRS_STREAM = %d", unit);
+	    }
+	}
+      else
+	{
+	  if ( env_stream[0] )
+	    {
+	      grprsm = fopen(env_stream, "w");
+	      if ( ! grprsm )
+		SysError("GRPRS_STREAM = %s", env_stream);
+	    }
+	}
+    }
+  /*
+    Set P factor switch to default, user supplies the P factor.
+  */
+  nonoff = 0;
+  /*
+    Set abort flag to NO abort
+  */
+  noabort = 1;
+  /*
+    Mark common area values set by user.
+  */
+  lfirst = false;
+  /*
+    Exhaustive use of all possible second-order packing methods
+    for HOPER='K'. Set to off.
+  */
+  num2ok  = 0;
+  /*
+    Use of extended second-order packing methods for grid-point
+    encoding (HOPER='C' and 'K'). Set to on.
+  */
+  next2o  = 1;
+  /*
+    Use of non-local second-order packing methods for grid-point
+    encoding (HOPER='C' and 'K'). Set to on.
+  */
+  nloc2o  = 1;
+  /*
+    Use of (all valid) sub-centre values for ECMWF fields encoding .
+    encoding. Set to off.
+  */
+  nsubce  = 0;
 }
 
+/* pack 8-bit bytes from 64-bit words to a packed buffer */
+/* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (unsigned char) up[i]; */
 
-void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+long packInt64(unsigned INT64 *up, unsigned char *cp, long bc, long tc)
 {
-  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
+#if defined (CRAY)
+  (void) _pack(up, cp, bc, tc);
+#else
+  U_BYTEORDER;
+  unsigned char *cp0;
+  unsigned INT64 upi, *up0, *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
+  long head, trail, inner, i, j;
+  long ipack = sizeof(INT64);
+  
+  /* Bytes until first word boundary in destination buffer */
 
-  if ( fphelp == NULL ) SysError("No Memory!");
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
 
-  index = inext = 0;
+  inner = bc - head;
 
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( pcStart >= n )
-	  {
-	    fphelp[index  ] = fpdata[inext++];
-	    fphelp[index+1] = fpdata[inext++];
-	  }
-	index += 2;
-      }
+  /* Trailing bytes which do not make a full word */
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n > pcStart )
-	  {
-	    fphelp[index  ] = fpdata[inext++];
-	    fphelp[index+1] = fpdata[inext++];
-	  }
-	index += 2;
-      }
+  trail = inner & (ipack-1);
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  /* Number of bytes/words to be processed in fast loop */
 
-  Free(fphelp);
-}
+  inner -= trail;
+  inner /= ipack;
+
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
+  ip4 = ip0 + 4;
+  ip5 = ip0 + 5;
+  ip6 = ip0 + 6;
+  ip7 = ip0 + 7;
 
+  up0 = (unsigned INT64 *) (cp + head);
 
-void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
-{
-  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
-  size_t inext = 0;
+  /* Here we should process any bytes until the first word boundary 
+   * of our destination buffer 
+   * That code is missing so far  because our output buffer is 
+   * word aligned by FORTRAN 
+   */
 
-  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
-    for ( size_t n = m; n <= trunc; n++ )
-      {
-	if ( pcStart >= n )
-	  {
-	    fphelp[inext++] = fpdata[index];
-	    fphelp[inext++] = fpdata[index+1];
-	  }
-	index += 2;
-      }
+  j = 0;
 
-  for ( size_t m = 0, index = 0; m <= trunc; m++ )
-    for ( size_t n = m; n <= trunc; n++ )
-      {
-	if ( n > pcStart )
-	  {
-	    fphelp[inext++] = fpdata[index];
-	    fphelp[inext++] = fpdata[index+1];
-	  }
-	index += 2;
-      }
+  if ( IS_BIGENDIAN() )
+    {
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+      for ( i = 0 ; i < inner ; i++ )
+	{
+	  upi =             (   ip0[j]          << 56 ) 
+	                 |  ( ( ip1[j] & 0xFF ) << 48 )
+	                 |  ( ( ip2[j] & 0xFF ) << 40 )
+	                 |  ( ( ip3[j] & 0xFF ) << 32 )
+	                 |  ( ( ip4[j] & 0xFF ) << 24 ) ;
+	  up0[i] = upi   |  ( ( ip5[j] & 0xFF ) << 16 )
+	                 |  ( ( ip6[j] & 0xFF ) <<  8 )
+	                 |    ( ip7[j] & 0xFF ) ;
+	  j += ipack;
+	}
+    }
+  else
+    {
+      for ( i = 0 ; i < inner ; i++ )
+	{
+	  upi =             (   ip7[j]          << 56 ) 
+	                 |  ( ( ip6[j] & 0xFF ) << 48 )
+                         |  ( ( ip5[j] & 0xFF ) << 40 )
+                         |  ( ( ip4[j] & 0xFF ) << 32 )
+                         |  ( ( ip3[j] & 0xFF ) << 24 ) ;
+	  up0[i] = upi   |  ( ( ip2[j] & 0xFF ) << 16 )
+                         |  ( ( ip1[j] & 0xFF ) <<  8 )
+                         |    ( ip0[j] & 0xFF ) ;
+	  j += ipack;
+	}
+    }
 
-  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  cp0 = (unsigned char *) ( up0 + inner );
+  if ( trail > 0 )
+    {
+      up0[inner] = 0;
+      for ( i = 0 ; i < trail ; i ++ )
+	{
+	  *cp0 = (unsigned char) ip0[ipack*inner+i];
+	  cp0++;
+	}
+    }
 
-  Free(fphelp);
+  if ( tc != -1 )
+    {
+      bc++;
+      *cp0 = (unsigned char) tc;
+    }
+#endif
+  return (bc);
 }
 
+/* unpack 8-bit bytes from a packed buffer with 64-bit words */
+/* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT64) cp[i]; */
 
-void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
+long unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc)
 {
-  /* System generated locals */
-  double r_1;
+  U_BYTEORDER;
+  const unsigned char *cp0;
+  unsigned INT64 *up0;
+  unsigned INT64 *ip0, *ip1, *ip2, *ip3, *ip4, *ip5, *ip6, *ip7;
+  long head, trail, inner, i, j;
+  long offset;
+  long ipack = sizeof(INT64);
 
-  /* Local variables */
-  int jl;
-  double zfac, zeps, zbeta;
-  double zalpha;
+  UNUSED(tc);
+
+  /* Bytes until first word boundary in source buffer */
+
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
+  if ( head > bc ) head = bc;
+
+  inner = bc - head;
+
+  /* Trailing bytes which do not make a full word */
+ 
+  trail = inner & (ipack-1);
+ 
+  /* Number of bytes/words to be processed in fast loop */
+
+  inner -= trail;
+  inner /= ipack;
+
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
+  ip4 = ip0 + 4;
+  ip5 = ip0 + 5;
+  ip6 = ip0 + 6;
+  ip7 = ip0 + 7;
 
-  /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
-  /* output: */
-  /*   pdl   = the limited derivative at the left edge of the interval */
-  /*   pdr   = the limited derivative at the right edge of the interval */
-  /* inputs */
-  /*   pdl   = the original derivative at the left edge */
-  /*   pdr   = the original derivative at the right edge */
-  /*   pfl   = function value at the left edge of the interval */
-  /*   pfr   = function value at the right edge of the interval */
-  /*   klg   = number of intervals where the derivatives are limited */
+  up0 = (unsigned INT64 *) (cp + head);
 
-  /*  define constants */
+  /* Process any bytes until the first word boundary 
+   * of our source buffer 
+   */
+  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT64) cp[i];
 
-  zeps = 1.0e-12;
-  zfac = (1.0 - zeps) * 3.0;
+  j = 0;
 
-  for ( jl = 0; jl < klg; ++jl )
+  if ( IS_BIGENDIAN() )
     {
-      if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+      for ( i = 0 ; i < inner ; i++ )
 	{
-	  zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
-	  zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
-	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
-	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
-	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
-	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
+	  ip0[j] = (up0[i] >> 56) & 0xFF;
+	  ip1[j] = (up0[i] >> 48) & 0xFF;
+	  ip2[j] = (up0[i] >> 40) & 0xFF;
+	  ip3[j] = (up0[i] >> 32) & 0xFF;
+	  ip4[j] = (up0[i] >> 24) & 0xFF;
+	  ip5[j] = (up0[i] >> 16) & 0xFF;
+	  ip6[j] = (up0[i] >>  8) & 0xFF;
+	  ip7[j] = (up0[i])       & 0xFF;
+
+	  j += ipack;
 	}
-      else
+    }
+  else
+    {
+      for ( i = 0 ; i < inner ; i++ )
 	{
-	  pdl[jl] = 0.0;
-	  pdr[jl] = 0.0;
+	  ip7[j] = (up0[i] >> 56) & 0xFF;
+	  ip6[j] = (up0[i] >> 48) & 0xFF;
+	  ip5[j] = (up0[i] >> 40) & 0xFF;
+	  ip4[j] = (up0[i] >> 32) & 0xFF;
+	  ip3[j] = (up0[i] >> 24) & 0xFF;
+	  ip2[j] = (up0[i] >> 16) & 0xFF;
+	  ip1[j] = (up0[i] >>  8) & 0xFF;
+	  ip0[j] = (up0[i])       & 0xFF;
+
+	  j += ipack;
 	}
     }
-} /* scm0 */
 
-static
-int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
-			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
-{
+  if ( trail > 0 )
+    {
+      offset = head + ipack*inner;
+      cp0 = cp + offset;
+      for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT64) cp0[i];
+    }
   /*
-C---->
-C**** ROWINA3 - Interpolation of row of values.
-C
-C     Purpose.
-C     --------
-C
-C     Interpolate a row of values.
-C
-C
-C**   Interface.
-C     ----------
-C
-C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
-C
-C
-C     Input Parameters.
-C     -----------------
-C
-C     P      - Row of values to be interpolated.
-C              Dimension must be at least KO.
-C
-C     KO     - Number of values required.
-C
-C     KI     - Number of values in P on input.
-C
-C     PW     - Working array.
-C              Dimension must be at least (0:KO+2,3).
-C
-C     KCODE  - Interpolation required.
-C              1 , linear.
-C              3 , cubic.
-C
-C     PMSVAL - Value used for missing data indicator.
-C
-C     OMISNG - True if missing values are present in field.
-C
-C     OPERIO - True if input field is periodic.
-C
-C     OVEGGY - True if 'nearest neighbour' processing must be used
-C              for interpolation
-C
-C     Output Parameters.
-C     ------------------
-C
-C     P     - Now contains KO values.
-C     KRET  - Return code
-C             0, OK
-C             Non-zero, error
-C
-C
-C     Method.
-C     -------
-C
-C     Linear or cubic interpolation performed as required.
-C
-C     Comments.
-C     ---------
-C
-C     This is a version of ROWINA which allows for missing data
-C     values and hence for bitmapped fields.
-C
-C
-C     Author.
-C     -------
-C
-C     J.D.Chambers    ECMWF     22.07.94
-C
-C
-C     Modifications.
-C     --------------
-C
-C     J.D.Chambers    ECMWF     13.09.94
-C     Add return code KRET and remove calls to ABORT.
-C
-C     J. Clochard, Meteo France, for ECMWF - January 1998.
-C     Addition of OMISNG and OPERIO arguments.
-C
-C
-C     -----------------------------------------------------------------
-*/
-  /* System generated locals */
-  int pw_dim1, pw_offset, i_1;
+  if ( tc != -1 ) {
+    bc++;
+    *cp0 = (unsigned char) tc;
+  }
+  */
+  return (bc);
+}
 
-  /* Local variables */
-  int jl, ip;
-  double zwt1, zrdi, zpos;
-  double zdo, zwt;
+/* pack 8-bit bytes from 32-bit words to a packed buffer */
+/* same as : for ( int i = 0; i < bc; ++i ) cp[i] = (char) up[i]; */
 
-  UNUSED(omisng);
+#if  defined  (INT32)
+long packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc)
+{
+  U_BYTEORDER;
+  unsigned char *cp0;
+  unsigned INT32 *up0, *ip0, *ip1, *ip2, *ip3;
+  long head, trail, inner, i, j;
+  long ipack = sizeof(INT32);
+  
+  /* Bytes until first word boundary in destination buffer */
 
-  /* Parameter adjustments */
-  --p;
-  pw_dim1 = ko + 3;
-  pw_offset = pw_dim1;
-  pw -= pw_offset;
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
 
-  *kret = 0;
+  inner = bc - head;
 
-  if ( kcode == 1 )
-    {
-      /*    Move input values to work array */
-      for ( jl = 1; jl <= ki; ++jl )
-	pw[jl + pw_dim1] = p[jl];
+  /* Trailing bytes which do not make a full word */
 
-      if ( operio )
-	{
-	  /* Arrange wrap-around value in work array */
-	  pw[ki + 1 + pw_dim1] = p[1];
+  trail = inner & (ipack-1);
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) ki;
-	  zdo = 1.0 / (double) ko;
-	}
-      else
-	{
-	  /* Repeat last value, to cope with "implicit truncation" below */
-	  pw[ki + 1 + pw_dim1] = p[ki];
+  /* Number of bytes/words to be processed in fast loop */
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) (ki-1);
-	  zdo = 1.0 / (double) (ko-1);
- 	}
+  inner -= trail;
+  inner /= ipack;
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
-	{
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
 
-	  /* Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+  up0 = (unsigned INT32 *) (cp + head);
 
-	  /* Get the current array position(minus 1) from the weight - */
-	  /* note the implicit truncation. */
-	  ip = (int) zwt;
-		  
-	  /* Adjust the weight to range (0.0 to 1.0) */
-	  zwt -= ip;
+  /* Here we should process any bytes until the first word boundary 
+   * of our destination buffer 
+   * That code is missing so far  because our output buffer is 
+   * word aligned by FORTRAN 
+   */
 
-          /* If 'nearest neighbour' processing must be used */
-	  if ( oveggy )
-	    {
-              if ( zwt < 0.5 )
-                p[jl] = pw[ip + 1 + pw_dim1];
-	      else
-		p[jl] = pw[ip + 2 + pw_dim1];
-	    }
-	  else
-	    {
-	      /*    If the left value is missing, use the right value */
-	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
-		{
-		  p[jl] = pw[ip + 2 + pw_dim1];
-		}
-	      /*    If the right value is missing, use the left value */
-	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
-		{
-		  p[jl] = pw[ip + 1 + pw_dim1];
-		}
-	      /*    If neither missing, interpolate ... */
-	      else
-		{
-		  /*  Interpolate using the weighted values on either side */
-		  /*  of the output point position */
-		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
-                              + zwt * pw[ip+2 + pw_dim1]);
-		}
-	    }
-	}
-    }
-  else if ( kcode == 3 )
+  j = 0;
+
+  if ( IS_BIGENDIAN() )
     {
-      /*     *******************************    */
-      /*     Section 2.  Cubic interpolation .. */
-      /*     *******************************    */
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+      for ( i = 0 ; i < inner ; i++ )
 	{
-          if ( IS_EQUAL(p[jl], msval) )
-	    {
-	      fprintf(stderr," ROWINA3: ");
-	      fprintf(stderr," Cubic interpolation not supported");
-	      fprintf(stderr," for fields containing missing data.\n");
-	      *kret = 1;
-	      goto L900;
-	    }
-          pw[jl + pw_dim1] = p[jl];
+	  up0[i] =          (   ip0[j]          << 24 ) 
+	                 |  ( ( ip1[j] & 0xFF ) << 16 )
+	                 |  ( ( ip2[j] & 0xFF ) <<  8 )
+	                 |    ( ip3[j] & 0xFF ) ;
+	  j += ipack;
 	}
-      pw[pw_dim1] = p[ki];
-      pw[ki + 1 + pw_dim1] = p[1];
-      pw[ki + 2 + pw_dim1] = p[2];
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
+    }
+  else
+    {
+      for ( i = 0 ; i < inner ; i++ )
 	{
-          pw[jl + (pw_dim1 << 1)] =
-            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
-                pw[jl     + pw_dim1] * 0.5 +
-                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
-          pw[jl + 1 + pw_dim1 * 3] =
-            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
-                pw[jl     + pw_dim1] +
-                pw[jl + 1 + pw_dim1] * 0.5 +
-                pw[jl + 2 + pw_dim1] / 3.0);
+	  up0[i] =          (   ip3[j]          << 24 ) 
+	                 |  ( ( ip2[j] & 0xFF ) << 16 )
+                         |  ( ( ip1[j] & 0xFF ) <<  8 )
+                         |    ( ip0[j] & 0xFF ) ;
+	  j += ipack;
 	}
+    }
 
-      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
-		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
-
-      zrdi = (double) ki;
-      zdo = 1.0 / (double) ko;
-      for ( jl = 1; jl <= ko; ++jl )
+  cp0 = (unsigned char *) ( up0 + inner );
+  if ( trail > 0 )
+    {
+      up0[inner] = 0;
+      for ( i = 0 ; i < trail ; i ++ )
 	{
-          zpos = (jl - 1) * zdo;
-          zwt = zpos * zrdi;
-          ip = (int) zwt + 1;
-          zwt = zwt + 1.0 - ip;
-          zwt1 = 1.0 - zwt;
-          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
+	  *cp0 = (unsigned char) ip0[ipack*inner+i];
+	  cp0++;
 	}
-
     }
-  else
+
+  if ( tc != -1 )
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA3:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      bc++;
+      *cp0 = (unsigned char) tc;
     }
 
-L900:
-    return 0;
-} /* rowina3 */
+  return (bc);
+}
+#endif
 
+/* unpack 8-bit bytes from a packed buffer with 32-bit words */
+/* same as : for ( int i = 0; i < bc; ++i ) up[i] = (INT32) cp[i]; */
 
-int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
-			T msval, int *kret, int omisng, int operio, int oveggy)
+#if  defined  (INT32)
+long unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc)
 {
-  /*
-C**** QU2REG3 - Convert quasi-regular grid data to regular.
-C
-C     Purpose.
-C     --------
-C
-C     Convert quasi-regular grid data to regular,
-C     using either a linear or cubic interpolation.
-C
-C
-C**   Interface.
-C     ----------
-C
-C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
-C    X            OVEGGY)
-C
-C
-C     Input Parameters.
-C     -----------------
-C
-C     PFIELD     - Array containing quasi-regular grid data.
-C
-C     KPOINT     - Array containing list of the number of
-C                  points on each latitude (or longitude) of
-C                  the quasi-regular grid.
-C
-C     KLAT       - Number of latitude lines
-C
-C     KLON       - Number of longitude lines
-C
-C     KCODE      - Interpolation required.
-C                  1 , linear - data quasi-regular on latitude lines.
-C                  3 , cubic -  data quasi-regular on latitude lines.
-C                  11, linear - data quasi-regular on longitude lines.
-C                  13, cubic -  data quasi-regular on longitude lines.
-C
-C     PMSVAL     - Value used for missing data indicator.
-C
-C     OMISNG     - True if missing values are present in field.
-C
-C     OPERIO     - True if input field is periodic.
-C
-C     OVEGGY     - True if 'nearest neighbour' processing must be used
-C                  for interpolation
-C
-C
-C     Output Parameters.
-C     ------------------
-C
-C     KRET       - return code
-C                  0 = OK
-C                  non-zero indicates fatal error
-C
-C
-C     Output Parameters.
-C     ------------------
-C
-C     PFIELD     - Array containing regular grid data.
-C
-C
-C     Method.
-C     -------
-C
-C     Data is interpolated and expanded into a temporary array,
-C     which is then copied back into the user's array.
-C     Returns an error code if an invalid interpolation is requested
-C     or field size exceeds array dimensions.
-C
-C     Comments.
-C     ---------
-C
-C     This routine is an adaptation of QU2REG to allow missing data
-C     values, and hence bit mapped fields.
-C
-C
-C     Author.
-C     -------
-C
-C     J.D.Chambers     ECMWF      22.07.94
-C
-C
-C     Modifications.
-C     --------------
-C
-C     J.D.Chambers     ECMWF      13.09.94
-C     Add return code KRET and remove calls to ABORT.
-C
-C     J.D.Chambers     ECMWF        Feb 1997
-C     Allow for 64-bit pointers
-C
-C     J. Clochard, Meteo France, for ECMWF - January 1998.
-C     Addition of OMISNG and OPERIO arguments.
-C     Fix message for longitude number out of bounds, and routine
-C     name in title and formats.
-C
-*/
-   /* System generated locals */
-   int i_1, i_2;
-   int kcode = 1;
+  U_BYTEORDER;
+  const unsigned char *cp0;
+  unsigned INT32 *up0;
+  unsigned INT32 *ip0, *ip1, *ip2, *ip3;
+  long head, trail, inner, i, j;
+  long offset;
+  long ipack = sizeof(INT32);
+
+  UNUSED(tc);
+
+  /* Bytes until first word boundary in source buffer */
+
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
+  if ( head > bc ) head = bc;
+
+  inner = bc - head;
+
+  /* Trailing bytes which do not make a full word */
+ 
+  trail = inner & (ipack-1);
+ 
+  /* Number of bytes/words to be processed in fast loop */
+
+  inner -= trail;
+  inner /= ipack;
+
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
+
+  up0 = (unsigned INT32 *) (cp + head);
 
-   /* Local variables */
-   int ilii, ilio, icode;
-   int iregno, iquano, j210, j220, j230, j240, j225;
-   T *ztemp = NULL;
-   T *zline = NULL;
-   T *zwork = NULL;
+  /* Process any bytes until the first word boundary 
+   * of our source buffer 
+   */
+  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT32) cp[i];
 
-   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
+  j = 0;
 
-   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
+  if ( IS_BIGENDIAN() )
+    {
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+      for ( i = 0 ; i < inner ; i++ )
+	{
+	  ip0[j] = (up0[i] >> 24) & 0xFF;
+	  ip1[j] = (up0[i] >> 16) & 0xFF;
+	  ip2[j] = (up0[i] >>  8) & 0xFF;
+	  ip3[j] = (up0[i])       & 0xFF;
 
-   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
+	  j += ipack;
+	}
+    }
+  else
+    {
+      for ( i = 0 ; i < inner ; i++ )
+	{
+	  ip3[j] = (up0[i] >> 24) & 0xFF;
+	  ip2[j] = (up0[i] >> 16) & 0xFF;
+	  ip1[j] = (up0[i] >>  8) & 0xFF;
+	  ip0[j] = (up0[i])       & 0xFF;
 
-   /* Parameter adjustments */
-   --pfield;
-   --kpoint;
+	  j += ipack;
+	}
+    }
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+  if ( trail > 0 )
+    {
+      offset = head + ipack*inner;
+      cp0 = cp + offset;
+      for ( i = 0 ; i < trail ; i++ ) up[i+offset] = (unsigned INT32) cp0[i];
+    }
+  /*
+  if ( tc != -1 ) {
+    bc++;
+    *cp0 = (unsigned char) tc;
+  }
+  */
 
-   *kret = 0;
+  return (bc);
+}
+#endif
+#include <stdio.h>
 
-/* Check input parameters. */
+void prtbin(int kin, int knbit, int *kout, int *kerr)
+{
+  /*
 
-   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
-      fprintf(stderr," QU2REG :");
-      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
-      *kret = 1;
-      goto L900;
-   }
+    Produces a decimal number with ones and zeroes
+    corresponding to the ones and zeroes of the input
+    binary number.
+    eg input number 1011 binary, output number 1011 decimal.
 
-/* Set array indices to 0. */
 
-   ilii = 0;
-   ilio = 0;
+    Input Parameters:
+    
+       kin   - Integer variable containing binary number.
 
-/* Establish values of loop parameters. */
+       knbit - Number of bits in binary number.
 
-   if (kcode > 10) {
+    Output Parameters:
 
-/*    Quasi-regular along longitude lines. */
+       kout  - Integer variable containing decimal value
+               with ones and zeroes corresponding to those of
+	       the input binary number.
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
+       kerr  - 0, If no error.
+               1, Number of bits in binary number exceeds
+	          maximum allowed or is less than 1.
 
-/*    Quasi-regular along latitude lines. */
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+    Converted from EMOS routine PRTBIN.
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+  */
+  int idec;
+  int ik;
+  int itemp;
+  int j;
 
-      if (iregno != kpoint[j230]) {
+  /*
+    Check length of binary number to ensure decimal number
+    generated will fit in the computer word - in this case will
+    it fit in a Cray 48 bit integer?
+  */
+  if ( knbit < 1 || knbit > 14 )
+    {
+      *kerr = 1;
+      printf(" prtbin : Error in binary number length - %3d bits.\n", knbit);
+      return;
+    }
+  else
+    *kerr = 0;
+  /*
+    -----------------------------------------------------------------
+    Section 1. Generate required number.
+    -----------------------------------------------------------------
+  */
+  *kout = 0;
+  ik    = kin;
+  idec  = 1;
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
+  for ( j = 0; j < knbit; j++ )
+    {
+      itemp = ik - ( (ik/2)*2 );
+      *kout = (*kout) + itemp * idec;
+      ik    = ik / 2;
+      idec  = idec * 10;
+    }
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+  return;
+}
 
-/*       and interpolate this line. */
 
-         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
-         if (*kret != 0) goto L900;
+void ref2ibm(double *pref, int kbits)
+{
+  /*
 
-/*       Add regular grid values for this line to the
-         temporary array. */
+    Purpose:
+    --------
 
-         i_2 = iregno;
-         for (j220 = 1; j220 <= i_2; ++j220) {
-            ++ilio;
-            ztemp[ilio - 1] = zline[j220 - 1];
-         }
+    Code and check reference value in IBM format
 
-      } else {
+    Input Parameters:
+    -----------------
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+    pref       - Reference value
+    kbits      - Number of bits per computer word.
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
+    Output Parameters:
+    ------------------
 
-/* Copy temporary array to user array. */
+    pref       - Reference value
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+    Method:
+    -------
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+    Codes in IBM format, then decides to ensure that reference 
+    value used for packing is not different from that stored
+    because of packing differences.
 
-L900:
+    Externals.
+    ----------
 
-   Free(zwork);
-   Free(zline);
-   Free(ztemp);
+    confp3    - Encode into IBM floating point format.
+    decfp2    - Decode from IBM floating point format.
 
-   return 0;
-} /* qu2reg3 */
+    Reference:
+    ----------
 
-#endif /* T */
+    None.
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+    Comments:
+    --------
 
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
+    None.
 
-/* calculate_pfactor: source code from grib_api-1.8.0 */
-double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
-{
-  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
-  long loop, index, m, n = 0;
-  double pFactor, zeps = 1.0e-15;
-  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
-  double* weights, range, * norms;
-  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
-  double numerator = 0.0, denominator = 0.0, slope;
+    Author:
+    -------
 
-  /*
-  // Setup the weights
-   */
+    J.D.Chambers     ECMWF      17:05:94
 
-  range = (double) (ismax - ismin +1);
+    Modifications:
+    --------------
 
-  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
-  for( loop = ismin; loop <= ismax; loop++ )
-    weights[loop] = range / (double) (loop-ismin+1);
-  /*
-  // Compute norms
-  // Handle values 2 at a time (real and imaginary parts).
-   */
-  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+    Uwe Schulzweida   MPIfM   01/04/2001
 
-  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
-  /*
-  // Form norms for the rows which contain part of the unscaled subset.
-   */
+    Convert to C from EMOS library version 130
 
-  index = -2;
-  for( m = 0; m < subsetTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      index += 2;
-      if( n >= subsetTruncation ) {
-        double tval = spectralField[index];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-        tval = spectralField[index+1];
-        tval=tval<0?-tval:tval;
-        norms[n] = norms[n] > tval ? norms[n] : tval;
-      }
-    }
-  /*
-  // Form norms for the rows which do not contain part of the unscaled subset.
-   */
+  */
 
-  for( m = subsetTruncation; m <= fieldTruncation; m++ )
-    for( n = m; n <= fieldTruncation; n++ ) {
-      double tval = spectralField[index];
-      index += 2;
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-      tval = spectralField[index+1];
-      tval=tval<0?-tval:tval;
-      norms[n] = norms[n] > tval ? norms[n] : tval;
-    }
+  static int itrnd;
+  static int kexp, kmant;
+  static double ztemp, zdumm;
+  extern int CGRIBEX_Debug;
 
-  /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
+  /* ----------------------------------------------------------------- */
+  /*   Section 1. Convert to and from IBM format.                      */
+  /* ----------------------------------------------------------------- */
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    norms[n] = norms[n] > zeps ? norms[n] : zeps;
-    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
-  }
+  /*  Convert floating point reference value to IBM representation. */
 
-  /*
-  // Do linear fit to find the slope
-   */
+  itrnd = 1;
+  zdumm = ztemp = *pref;
+  confp3(zdumm, &kexp, &kmant, kbits, itrnd);
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
-    x = log( (double) (loop*(loop+1)) );
-    y = log( norms[loop] );
-    weightedSumOverX = weightedSumOverX + x * weights[loop];
-    weightedSumOverY = weightedSumOverY + y * weights[loop];
-    sumOfWeights = sumOfWeights + weights[loop];
-  }
-  weightedSumOverX = weightedSumOverX / sumOfWeights;
-  weightedSumOverY = weightedSumOverY / sumOfWeights;
+  if ( kexp == 0 && kmant == 0 ) return;
 
-  /*
-  // Perform a least square fit for the equation
-   */
+  /*  Set reference value to that actually stored in the GRIB code. */
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
+  *pref = decfp2(kexp, kmant);
 
-    x = log( (double)(loop*(loop+1)) );
-    y = log( norms[loop] );
-    numerator =
-      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
-    denominator =
-      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
-  }
-  slope = numerator / denominator;
+  /*  If the nearest number which can be represented in */
+  /*  GRIB format is greater than the reference value,  */
+  /*  find the nearest number in GRIB format lower      */
+  /*  than the reference value.                         */
 
-  Free(weights);
-  Free(norms);
+  if ( ztemp < *pref )
+    {
+      /*  Convert floating point to GRIB representation */
+      /*  using truncation to ensure that the converted */
+      /*  number is smaller than the original one.      */
 
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
+      itrnd = 0;
+      zdumm = *pref = ztemp;
+      confp3(zdumm, &kexp, &kmant, kbits, itrnd);
 
-  return pFactor;
-}
+      /*  Set reference value to that stored in the GRIB code. */
 
-void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
-{
-  double power;
-  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
+      *pref = decfp2(kexp, kmant);
 
-  if ( scale == NULL ) SysError("No Memory!");
+      if ( ztemp < *pref )
+	{
+	  if ( CGRIBEX_Debug )
+	    {
+	      Message("Reference value error.");
+	      Message("Notify Met.Applications Section.");
+	      Message("ZTEMP = ", ztemp);
+	      Message("PREF = ", pref);
+	    }
+	  *pref = ztemp;
+	}
+    }
 
-  if ( pcScale < -10000 || pcScale > 10000 )
-    {
-      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
-      return;
-   }
+  return;
+} /* ref2ibm */
+#include <math.h>
+#include <string.h>
 
-  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
 
-  if ( pcScale == 0 ) return;
+unsigned correct_bdslen(unsigned bdslen, long recsize, long gribpos)
+{
+  /*
+    If a very large product, the section 4 length field holds
+    the number of bytes in the product after section 4 upto
+    the end of the padding bytes.
+    This is a fixup to get round the restriction on product lengths
+    due to the count being only 24 bits. It is only possible because
+    the (default) rounding for GRIB products is 120 bytes.
+  */
+  if ( recsize > JP23SET && bdslen <= 120 ) bdslen = (unsigned)(recsize - gribpos - bdslen);
+  return bdslen;
+}
 
-  power = (double) pcScale / 1000.;
-  scale[0] = 1.0;
 
-  if (pcScale != 1000)
-    for ( int n = 1; n <= trunc; n++ )
-      scale[n] = pow((double) (n*(n+1)), power);
-  else
-    for ( int n = 1; n <= trunc; n++ )
-      scale[n] =     (double) (n*(n+1));
+int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
+		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize)
+{
+  *gribrecsize = 0;
+  *pdsp = NULL;
+  *gdsp = NULL;
+  *bmsp = NULL;
+  *bdsp = NULL;
 
-  if ( inv )
-    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+  unsigned char *section = gribbuffer;
+  unsigned char *is = gribbuffer;
+  if ( ! GRIB_START(section) )
+    {
+      fprintf(stderr, "Wrong GRIB indicator section: found >%c%c%c%c<\n",
+	      section[0], section[1], section[2], section[3]);
+      return -1;
+    }
 
-  /* Scale the values */
+  unsigned recsize = GET_UINT3(section[4], section[5], section[6]);
 
-  size_t index = 0;
+  int gribversion = GRIB_EDITION(section);
+  if ( recsize == 24 && gribversion == 0 ) gribversion = 0;
 
-  for ( int m = 0;   m < pcStart; m++ )
-    for ( int n = m; n <= trunc; n++, index += 2 )
-      if ( n >= pcStart )
-        {
-          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
-          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
-        }
+  unsigned grib1offset = (gribversion == 1) ? 4 : 0;
 
-  for ( int m = pcStart; m <= trunc; m++ )
-    for ( int n = m;     n <= trunc; n++, index += 2 )
-      {
-	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
-	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
-      }
+  unsigned char *pds = is + 4 + grib1offset;
+  unsigned char *bufpointer = pds + PDS_Len;
+  unsigned gribsize = 4 + grib1offset + PDS_Len;
 
-  Free(scale);
-}
+  unsigned char *gds = NULL;
+  if ( PDS_HAS_GDS )
+    {
+      gds = bufpointer;
+      bufpointer += GDS_Len;
+      gribsize += GDS_Len;
+    }
+
+  unsigned char *bms = NULL;
+  if ( PDS_HAS_BMS )
+    {
+      bms = bufpointer;
+      bufpointer += BMS_Len;
+      gribsize += BMS_Len;
+    }
 
+  unsigned char *bds = bufpointer;
+  unsigned bdslen = BDS_Len;
+  if ( recsize > JP23SET && bdslen <= 120 )
+    {
+      recsize &= JP23SET;
+      recsize *= 120;
+      bdslen = correct_bdslen(bdslen, recsize, gribsize);
+    }
+  bufpointer += bdslen;
+  gribsize += bdslen;
+  gribsize += 4;
 
-void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
-{
-  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
-  int  m, n;
-  int  index, inext;
+  *pdsp = pds;
+  *gdsp = gds;
+  *bmsp = bms;
+  *bdsp = bds;
 
-  if ( fphelp == NULL ) SysError("No Memory!");
+  *gribrecsize = gribsize;
+  if ( gribbufsize < gribsize )
+    {
+      fprintf(stderr, "Inconsistent length of GRIB message (grib_buffer_size=%ld < grib_record_size=%u)!\n", gribbufsize, gribsize);
+      return 1;
+    }
 
-  index = inext = 0;
+  if ( !GRIB_FIN(bufpointer) ) // end section - "7777" in ASCII
+    {
+      fprintf(stderr, "Missing GRIB end section: found >%c%c%c%c<\n",
+	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
+      return -2;
+    }
 
-  for ( m = 0;   m <= pcStart; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( pcStart >= n )
-	  {
-	    fphelp[index  ] = fpdata[inext++];
-	    fphelp[index+1] = fpdata[inext++];
-	  }
-	index += 2;
-      }
+  return 0;
+}
 
-  index = 0;
-  for ( m = 0;   m <= trunc; m++ )
-    for ( n = m; n <= trunc; n++ )
-      {
-	if ( n > pcStart )
-	  {
-	    fphelp[index  ] = fpdata[inext++];
-	    fphelp[index+1] = fpdata[inext++];
-	  }
-	index += 2;
-      }
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+int grib2Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **idsp,
+		  unsigned char **lusp, unsigned char **gdsp, unsigned char **pdsp,
+		  unsigned char **drsp, unsigned char **bmsp, unsigned char **bdsp)
+{
+  UNUSED(gribbufsize);
+
+  *idsp = NULL;
+  *lusp = NULL;
+  *gdsp = NULL;
+  *pdsp = NULL;
+  *drsp = NULL;
+  *bmsp = NULL;
+  *bdsp = NULL;
 
-  Free(fphelp);
-}
+  unsigned char *section = gribbuffer;
+  unsigned sec_len = 16;
 
+  if ( !GRIB_START(section) )
+    {
+      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
+	      section[0], section[1], section[2], section[3]);
+      return -1;
+    }
 
-void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
-{
-  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
-  size_t inext = 0;
+  int gribversion = GRIB_EDITION(section);
+  if ( gribversion != 2 )
+    {
+      fprintf(stderr, "wrong GRIB version %d\n", gribversion);
+      return -1;      
+    }
 
-  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
-    for ( size_t n = m; n <= trunc; n++ )
-      {
-	if ( pcStart >= n )
-	  {
-	    fphelp[inext++] = fpdata[index];
-	    fphelp[inext++] = fpdata[index+1];
-	  }
-	index += 2;
-      }
+  unsigned gribsize = 0;
+  for ( int i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | section[8+i];
 
-  for ( size_t m = 0, index = 0; m <= trunc; m++ )
-    for ( size_t n = m; n <= trunc; n++ )
-      {
-	if ( n > pcStart )
-	  {
-	    fphelp[inext++] = fpdata[index];
-	    fphelp[inext++] = fpdata[index+1];
-	  }
-	index += 2;
-      }
+  unsigned grib_len = sec_len;
+  section  += sec_len;
 
-  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  /* section 1 */
+  sec_len = GRIB2_SECLEN(section);
+  int sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "ids %d %ld\n", sec_num, sec_len);
 
-  Free(fphelp);
-}
+  if ( sec_num != 1 )
+    {
+      fprintf(stderr, "Unexpected section1 number %d\n", sec_num);
+      return -1;
+    }
 
+  *idsp = section;
 
-void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
-{
-  /* System generated locals */
-  double r_1;
+  grib_len += sec_len;
+  section  += sec_len;
 
-  /* Local variables */
-  int jl;
-  double zfac, zeps, zbeta;
-  double zalpha;
+  /* section 2 and 3 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "lus %d %ld\n", sec_num, sec_len);
 
-  /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
-  /* output: */
-  /*   pdl   = the limited derivative at the left edge of the interval */
-  /*   pdr   = the limited derivative at the right edge of the interval */
-  /* inputs */
-  /*   pdl   = the original derivative at the left edge */
-  /*   pdr   = the original derivative at the right edge */
-  /*   pfl   = function value at the left edge of the interval */
-  /*   pfr   = function value at the right edge of the interval */
-  /*   klg   = number of intervals where the derivatives are limited */
+  if ( sec_num == 2 )
+    {
+      *lusp = section;
 
-  /*  define constants */
+      grib_len += sec_len;
+      section  += sec_len;
 
-  zeps = 1.0e-12;
-  zfac = (1.0 - zeps) * 3.0;
+      /* section 3 */
+      sec_len = GRIB2_SECLEN(section);
+      //sec_num = GRIB2_SECNUM(section);
+      //fprintf(stderr, "gds %d %ld\n", sec_num, sec_len);
 
-  for ( jl = 0; jl < klg; ++jl )
+      *gdsp = section;
+    }
+  else if ( sec_num == 3 )
     {
-      if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
-	{
-	  zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
-	  zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
-	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
-	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
-	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
-	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
-	}
-      else
-	{
-	  pdl[jl] = 0.0;
-	  pdr[jl] = 0.0;
-	}
+      *gdsp = section;
+    }
+  else
+    {
+      fprintf(stderr, "Unexpected section3 number %d\n", sec_num);
+      return -1;
     }
-} /* scm0 */
 
-static
-int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
-			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
-{
-  /*
-C---->
-C**** ROWINA3 - Interpolation of row of values.
-C
-C     Purpose.
-C     --------
-C
-C     Interpolate a row of values.
-C
-C
-C**   Interface.
-C     ----------
-C
-C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
-C
-C
-C     Input Parameters.
-C     -----------------
-C
-C     P      - Row of values to be interpolated.
-C              Dimension must be at least KO.
-C
-C     KO     - Number of values required.
-C
-C     KI     - Number of values in P on input.
-C
-C     PW     - Working array.
-C              Dimension must be at least (0:KO+2,3).
-C
-C     KCODE  - Interpolation required.
-C              1 , linear.
-C              3 , cubic.
-C
-C     PMSVAL - Value used for missing data indicator.
-C
-C     OMISNG - True if missing values are present in field.
-C
-C     OPERIO - True if input field is periodic.
-C
-C     OVEGGY - True if 'nearest neighbour' processing must be used
-C              for interpolation
-C
-C     Output Parameters.
-C     ------------------
-C
-C     P     - Now contains KO values.
-C     KRET  - Return code
-C             0, OK
-C             Non-zero, error
-C
-C
-C     Method.
-C     -------
-C
-C     Linear or cubic interpolation performed as required.
-C
-C     Comments.
-C     ---------
-C
-C     This is a version of ROWINA which allows for missing data
-C     values and hence for bitmapped fields.
-C
-C
-C     Author.
-C     -------
-C
-C     J.D.Chambers    ECMWF     22.07.94
-C
-C
-C     Modifications.
-C     --------------
-C
-C     J.D.Chambers    ECMWF     13.09.94
-C     Add return code KRET and remove calls to ABORT.
-C
-C     J. Clochard, Meteo France, for ECMWF - January 1998.
-C     Addition of OMISNG and OPERIO arguments.
-C
-C
-C     -----------------------------------------------------------------
-*/
-  /* System generated locals */
-  int pw_dim1, pw_offset, i_1;
+  grib_len += sec_len;
+  section  += sec_len;
 
-  /* Local variables */
-  int jl, ip;
-  double zwt1, zrdi, zpos;
-  double zdo, zwt;
+  /* section 4 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "pds %d %ld\n", sec_num, sec_len);
 
-  UNUSED(omisng);
+  if ( sec_num != 4 )
+    {
+      fprintf(stderr, "Unexpected section4 number %d\n", sec_num);
+      return -1;
+    }
 
-  /* Parameter adjustments */
-  --p;
-  pw_dim1 = ko + 3;
-  pw_offset = pw_dim1;
-  pw -= pw_offset;
+  *pdsp = section;
 
-  *kret = 0;
+  grib_len += sec_len;
+  section  += sec_len;
 
-  if ( kcode == 1 )
+  /* section 5 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "drs %d %ld\n", sec_num, sec_len);
+
+  if ( sec_num != 5 )
     {
-      /*    Move input values to work array */
-      for ( jl = 1; jl <= ki; ++jl )
-	pw[jl + pw_dim1] = p[jl];
+      fprintf(stderr, "Unexpected section5 number %d\n", sec_num);
+      return -1;
+    }
 
-      if ( operio )
-	{
-	  /* Arrange wrap-around value in work array */
-	  pw[ki + 1 + pw_dim1] = p[1];
+  *drsp = section;
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) ki;
-	  zdo = 1.0 / (double) ko;
-	}
-      else
-	{
-	  /* Repeat last value, to cope with "implicit truncation" below */
-	  pw[ki + 1 + pw_dim1] = p[ki];
+  grib_len += sec_len;
+  section  += sec_len;
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) (ki-1);
-	  zdo = 1.0 / (double) (ko-1);
- 	}
+  /* section 6 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "bms %d %ld\n", sec_num, sec_len);
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
-	{
+  if ( sec_num != 6 )
+    {
+      fprintf(stderr, "Unexpected section6 number %d\n", sec_num);
+      return -1;
+    }
 
-	  /* Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+  *bmsp = section;
 
-	  /* Get the current array position(minus 1) from the weight - */
-	  /* note the implicit truncation. */
-	  ip = (int) zwt;
-		  
-	  /* Adjust the weight to range (0.0 to 1.0) */
-	  zwt -= ip;
+  grib_len += sec_len;
+  section  += sec_len;
 
-          /* If 'nearest neighbour' processing must be used */
-	  if ( oveggy )
-	    {
-              if ( zwt < 0.5 )
-                p[jl] = pw[ip + 1 + pw_dim1];
-	      else
-		p[jl] = pw[ip + 2 + pw_dim1];
-	    }
-	  else
-	    {
-	      /*    If the left value is missing, use the right value */
-	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
-		{
-		  p[jl] = pw[ip + 2 + pw_dim1];
-		}
-	      /*    If the right value is missing, use the left value */
-	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
-		{
-		  p[jl] = pw[ip + 1 + pw_dim1];
-		}
-	      /*    If neither missing, interpolate ... */
-	      else
-		{
-		  /*  Interpolate using the weighted values on either side */
-		  /*  of the output point position */
-		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
-                              + zwt * pw[ip+2 + pw_dim1]);
-		}
-	    }
-	}
+  /* section 7 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "bds %d %ld\n", sec_num, sec_len);
+
+  if ( sec_num != 7 )
+    {
+      fprintf(stderr, "Unexpected section7 number %d\n", sec_num);
+      return -1;
     }
-  else if ( kcode == 3 )
+
+  *bdsp = section;
+
+  grib_len += sec_len;
+  section  += sec_len;
+
+  /* skip multi GRIB sections */
+  int msec = 1;
+  while ( !GRIB_FIN(section) )
     {
-      /*     *******************************    */
-      /*     Section 2.  Cubic interpolation .. */
-      /*     *******************************    */
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
-	{
-          if ( IS_EQUAL(p[jl], msval) )
-	    {
-	      fprintf(stderr," ROWINA3: ");
-	      fprintf(stderr," Cubic interpolation not supported");
-	      fprintf(stderr," for fields containing missing data.\n");
-	      *kret = 1;
-	      goto L900;
-	    }
-          pw[jl + pw_dim1] = p[jl];
-	}
-      pw[pw_dim1] = p[ki];
-      pw[ki + 1 + pw_dim1] = p[1];
-      pw[ki + 2 + pw_dim1] = p[2];
-      i_1 = ki;
-      for ( jl = 1; jl <= i_1; ++jl )
-	{
-          pw[jl + (pw_dim1 << 1)] =
-            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
-                pw[jl     + pw_dim1] * 0.5 +
-                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
-          pw[jl + 1 + pw_dim1 * 3] =
-            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
-                pw[jl     + pw_dim1] +
-                pw[jl + 1 + pw_dim1] * 0.5 +
-                pw[jl + 2 + pw_dim1] / 3.0);
-	}
+      sec_len = GRIB2_SECLEN(section);
+      sec_num = GRIB2_SECNUM(section);
 
-      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
-		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
+      if ( sec_num < 1 || sec_num > 7 ) break;
 
-      zrdi = (double) ki;
-      zdo = 1.0 / (double) ko;
-      for ( jl = 1; jl <= ko; ++jl )
-	{
-          zpos = (jl - 1) * zdo;
-          zwt = zpos * zrdi;
-          ip = (int) zwt + 1;
-          zwt = zwt + 1.0 - ip;
-          zwt1 = 1.0 - zwt;
-          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
-                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
-                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
-                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
-	}
+      if ( sec_num == 7 )
+	fprintf(stderr, "Skipped unsupported multi GRIB section %d!\n", ++msec);
+
+      if ( (grib_len + sec_len) > gribsize ) break;
 
+      grib_len += sec_len;
+      section  += sec_len;
     }
-  else
+
+  /* end section - "7777" in ASCII */
+  if ( !GRIB_FIN(section) )
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA3:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
+	      section[0], section[1], section[2], section[3]);
+      return -2;
     }
 
-L900:
-    return 0;
-} /* rowina3 */
-
+  return 0;
+}
 
-int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
-			T msval, int *kret, int omisng, int operio, int oveggy)
-{
-  /*
-C**** QU2REG3 - Convert quasi-regular grid data to regular.
-C
-C     Purpose.
-C     --------
-C
-C     Convert quasi-regular grid data to regular,
-C     using either a linear or cubic interpolation.
-C
-C
-C**   Interface.
-C     ----------
-C
-C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
-C    X            OVEGGY)
-C
-C
-C     Input Parameters.
-C     -----------------
-C
-C     PFIELD     - Array containing quasi-regular grid data.
-C
-C     KPOINT     - Array containing list of the number of
-C                  points on each latitude (or longitude) of
-C                  the quasi-regular grid.
-C
-C     KLAT       - Number of latitude lines
-C
-C     KLON       - Number of longitude lines
-C
-C     KCODE      - Interpolation required.
-C                  1 , linear - data quasi-regular on latitude lines.
-C                  3 , cubic -  data quasi-regular on latitude lines.
-C                  11, linear - data quasi-regular on longitude lines.
-C                  13, cubic -  data quasi-regular on longitude lines.
-C
-C     PMSVAL     - Value used for missing data indicator.
-C
-C     OMISNG     - True if missing values are present in field.
-C
-C     OPERIO     - True if input field is periodic.
-C
-C     OVEGGY     - True if 'nearest neighbour' processing must be used
-C                  for interpolation
-C
-C
-C     Output Parameters.
-C     ------------------
-C
-C     KRET       - return code
-C                  0 = OK
-C                  non-zero indicates fatal error
-C
-C
-C     Output Parameters.
-C     ------------------
-C
-C     PFIELD     - Array containing regular grid data.
-C
-C
-C     Method.
-C     -------
-C
-C     Data is interpolated and expanded into a temporary array,
-C     which is then copied back into the user's array.
-C     Returns an error code if an invalid interpolation is requested
-C     or field size exceeds array dimensions.
-C
-C     Comments.
-C     ---------
-C
-C     This routine is an adaptation of QU2REG to allow missing data
-C     values, and hence bit mapped fields.
-C
-C
-C     Author.
-C     -------
-C
-C     J.D.Chambers     ECMWF      22.07.94
-C
-C
-C     Modifications.
-C     --------------
-C
-C     J.D.Chambers     ECMWF      13.09.94
-C     Add return code KRET and remove calls to ABORT.
-C
-C     J.D.Chambers     ECMWF        Feb 1997
-C     Allow for 64-bit pointers
-C
-C     J. Clochard, Meteo France, for ECMWF - January 1998.
-C     Addition of OMISNG and OPERIO arguments.
-C     Fix message for longitude number out of bounds, and routine
-C     name in title and formats.
-C
-*/
-   /* System generated locals */
-   int i_1, i_2;
-   int kcode = 1;
 
-   /* Local variables */
-   int ilii, ilio, icode;
-   int iregno, iquano, j210, j220, j230, j240, j225;
-   T *ztemp = NULL;
-   T *zline = NULL;
-   T *zwork = NULL;
+int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
+			int *intnum, float *fltnum, off_t *bignum)
+{
+  long gribsize = 0;
+  off_t bpos = 0;
 
-   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
+  unsigned char *section = gribbuffer;
+  unsigned char *is = gribbuffer;
+  if ( ! GRIB_START(section) )
+    {
+      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
+	      section[0], section[1], section[2], section[3]);
+      return -1;
+    }
 
-   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
+  int gribversion = GRIB_EDITION(section);
+  if ( recsize == 24 && gribversion == 0 ) gribversion = 0;
 
-   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
+  unsigned grib1offset = (gribversion == 1) ? 4 : 0;
 
-   /* Parameter adjustments */
-   --pfield;
-   --kpoint;
+  unsigned char *pds = is + 4 + grib1offset;
+  unsigned char *bufpointer = pds + PDS_Len;
+  gribsize += 4 + grib1offset + PDS_Len;
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+  unsigned char *gds = NULL;
+  if ( PDS_HAS_GDS )
+    {
+      gds = bufpointer;
+      bufpointer += GDS_Len;
+      gribsize += GDS_Len;
+    }
 
-   *kret = 0;
+  unsigned char *bms = NULL;
+  if ( PDS_HAS_BMS )
+    {
+      bms = bufpointer;
+      bufpointer += BMS_Len;
+      bpos = recpos + gribsize + 6;
+      gribsize += BMS_Len;
+    }
 
-/* Check input parameters. */
+  unsigned char *bds = bufpointer;
 
-   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
-      fprintf(stderr," QU2REG :");
-      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
-      *kret = 1;
-      goto L900;
-   }
+  off_t dpos = recpos + gribsize + 11;
 
-/* Set array indices to 0. */
+  unsigned bdslen = BDS_Len;
+  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
+  bufpointer += bdslen;
+  gribsize += bdslen;
+  gribsize += 4;
 
-   ilii = 0;
-   ilio = 0;
+  if ( gribsize > recsize )
+    {
+      fprintf(stderr, "GRIB buffer size %ld too small! Min size = %ld\n", recsize, gribsize);
+      return 1;
+    }
 
-/* Establish values of loop parameters. */
+  /* end section - "7777" in ascii */
+  if ( !GRIB_FIN(bufpointer) )
+    {
+      fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
+	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
+    }
 
-   if (kcode > 10) {
+  int bs = BDS_BinScale;
+  if ( bs > 32767 ) bs = 32768-bs;
+  float bsf = ldexpf(1.0f, bs);
 
-/*    Quasi-regular along longitude lines. */
+  bignum[0] = dpos;
+  bignum[1] = bms ? bpos : -999;
+  intnum[0] = BDS_NumBits;
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
+  /*  fltnum[0] = 1.0; */
+  fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
+  fltnum[1] = bsf;
+  fltnum[2] = (float)BDS_RefValue;
+  /*
+  printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
+  printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
+  */
+  return 0;
+}
 
-/*    Quasi-regular along latitude lines. */
+static
+int get_level(unsigned char *pds)
+{
+  int level = 0;
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+  if ( PDS_LevelType == 100 )
+    level = PDS_Level * 100;
+  else if ( PDS_LevelType == 99 )
+    level = PDS_Level;
+  else if ( PDS_LevelType == 109 )
+    level = PDS_Level;
+  else
+    level = PDS_Level1;
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
+  return level;
+}
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+static
+double get_cr(unsigned char *w1, unsigned char *w2)
+{
+  unsigned s1 = GET_UINT3(w1[0], w1[1], w1[2]);
+  unsigned s2 = GET_UINT3(w2[0], w2[1], w2[2]);
+  return ((double)s1)/s2;
+}
 
-      if (iregno != kpoint[j230]) {
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
+void grib1PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  static int header = 1;
+  unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+  if ( header )
+    {
+      fprintf(stdout, 
+      "  Rec : Off Position   Size : V PDS  GDS    BMS    BDS : Code Level :  LType GType: CR LL\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
+    }
 
-/*       and interpolate this line. */
+  is = gribbuffer;
 
-         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
-         if (*kret != 0) goto L900;
+  unsigned gribsize = GET_UINT3(is[4], is[5], is[6]);
 
-/*       Add regular grid values for this line to the
-         temporary array. */
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "%5d :%4ld %8ld %6ld : GRIB message error\n", nrec, offset, recpos, recsize);
+      return;
+    }
 
-         i_2 = iregno;
-         for (j220 = 1; j220 <= i_2; ++j220) {
-            ++ilio;
-            ztemp[ilio - 1] = zline[j220 - 1];
-         }
+  int GridType = (gds == NULL) ? -1 : (int)GDS_GridType;
 
-      } else {
+  int level = get_level(pds);
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+  unsigned bdslen = BDS_Len;
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
+  bool llarge = (gribsize > JP23SET && bdslen <= 120);
 
-/* Copy temporary array to user array. */
+  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+  double cr = (((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130)) ? get_cr(&bds[14], &gribbuffer[4]) : 1;
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+  fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d%4d%5d %6d %6d : %3d %6d : %5d %5d %6.4g  %c",
+	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
+	  PDS_Len, GDS_Len, BMS_Len, bdslen,
+	  PDS_Parameter, level, PDS_LevelType, GridType, cr, llarge?'T':'F');
 
-L900:
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
+}
 
-   Free(zwork);
-   Free(zline);
-   Free(ztemp);
 
-   return 0;
-} /* qu2reg3 */
+void grib2PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  static int header = 1;
+  unsigned char *is  = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  unsigned char *ids = NULL, *lus = NULL, *drs = NULL;
+  long ids_len = 0, lus_len = 0, gds_len = 0, pds_len = 0, drs_len = 0, bms_len = 0, bds_len = 0;
+  int gridtype, paramnum, level1type /*, level2type*/;
+  int level1 /*, level1sf*/;
+  /* int level2, level2sf; */
+  double cr = 1;
 
-#endif /* T */
+  if ( header )
+    {
+      fprintf(stdout, 
+      "  Rec : Off Position   Size : V IDS LUS GDS PDS  DRS    BMS    BDS : Code Level :  LType GType: CR\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
+    }
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
-#include <string.h>
+  is = gribbuffer;
 
+  int nerr = grib2Sections(gribbuffer, recsize, &ids, &lus, &gds, &pds, &drs, &bms, &bds);
+  if ( nerr )
+    {
+      fprintf(stdout, "%5d :%4ld %8ld %6ld : error\n", nrec, offset, recpos, recsize);
+      return;
+    }
 
+  if ( ids ) ids_len = GRIB2_SECLEN(ids);
+  if ( lus ) lus_len = GRIB2_SECLEN(lus);
+  if ( gds ) gds_len = GRIB2_SECLEN(gds);
+  if ( pds ) pds_len = GRIB2_SECLEN(pds);
+  if ( drs ) drs_len = GRIB2_SECLEN(drs);
+  if ( bms ) bms_len = GRIB2_SECLEN(bms);
+  if ( bds ) bds_len = GRIB2_SECLEN(bds);
 
-int gribVersion(unsigned char *is, size_t buffersize)
-{
-  if ( buffersize < 8 )
-    Error("Buffer too small (current size %d)!", (int) buffersize);
+  // double cr = (((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130)) ? get_cr(&bds[14], &gribbuffer[4]) : 1;
 
-  return (GRIB_EDITION(is));
+  gridtype   = GET_UINT2(gds[12],gds[13]);
+  paramnum   = GET_UINT1(pds[10]);
+  level1type = GET_UINT1(pds[22]);
+  /* level1sf   = GET_UINT1(pds[23]); */
+  level1     = GET_UINT4(pds[24],pds[25],pds[26],pds[27]);
+  /* level2type = GET_UINT1(pds[28]); */
+  /* level2sf   = GET_UINT1(pds[29]); */
+  /* level2     = GET_UINT4(pds[30],pds[31],pds[32],pds[33]); */
+  /*
+  printf("level %d %d %d %d %d %d %d\n", level1type, level1sf, level1, level1*level1sf, level2sf, level2, level2*level2sf);
+  */
+  fprintf(stdout, "%5d :%4ld %8ld %6ld :%2d %3ld %3ld %3ld %3ld %4ld %6ld %6ld : %3d%7d : %5d %5d %6.4g\n",
+	  nrec, offset, recpos, recsize, GRIB_EDITION(is),
+	  ids_len, lus_len, gds_len, pds_len, drs_len, bms_len, bds_len,
+	  paramnum, level1, level1type, gridtype, cr);
 }
 
-static 
-double GET_Real(unsigned char *grib)
-{
-  int iexp, imant;
 
-  iexp  = GET_UINT1(grib[0]);
-  imant = GET_UINT3(grib[1], grib[2], grib[3]);
+void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-  return (decfp2(iexp, imant));
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintALL(nrec, offset, recpos, recsize, gribbuffer);
+  else if ( gribversion == 2 )
+    grib2PrintALL(nrec, offset, recpos, recsize, gribbuffer);
+  else
+    {
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, offset, recpos, recsize, gribversion); 
+    }
 }
 
-static 
-int decodeIS(unsigned char *is, int *isec0, int *iret)
+
+void grib1PrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  int isLen = 0;
-  int grib1offset;
-  int lgrib = FALSE, lbudg = FALSE, ltide = FALSE;
+  static int header = 1;
+  unsigned char *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  int century, subcenter, decimalscale;
+  int fc_num = 0;
+  int year = 0, date;
 
-  /*
-    Octets 1 - 4 : The letters G R I B.
-    Four 8 bit fields.
-  */
-  /*
-    Check letters -> GRIB, BUDG or TIDE.
-  */
-  /*
-    Check that 'GRIB' is found where expected.
-  */
-  if ( GRIB_START(is) ) lgrib = TRUE;
-  /*
-    ECMWF pseudo-grib data uses 'BUDG' and 'TIDE'.
-  */
-  if ( BUDG_START(is) ) lbudg = TRUE;
-  if ( TIDE_START(is) ) ltide = TRUE;
-  /*
-    Data is not GRIB or pseudo-grib.
-  */
-  if ( lgrib == FALSE && lbudg == FALSE && ltide == FALSE )
+  UNUSED(recpos);
+
+  if ( header )
     {
-      *iret = 305;
-      gprintf(__func__, "Input data is not GRIB or pseudo-grib.");
-      gprintf(__func__, "Return code = %d", *iret);
+      fprintf(stdout, 
+      "  Rec : PDS Tab Cen Sub Ver Grid Code LTyp Level1 Level2    Date  Time P1 P2 TU TR NAVE Scale FCnum CT\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
     }
-  if ( lbudg == TRUE || ltide == TRUE )
+
+  is = gribbuffer;
+
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      *iret = 305;
-      gprintf(__func__, "Pseudo-grib data unsupported.");
-      gprintf(__func__, "Return code = %d", *iret);
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
 
-  /*
-    Octets 5 - 7 : Length of message.
-    One 24 bit field.
-  */
-  ISEC0_GRIB_Len = GRIB1_SECLEN(is);
-  /*
-    Octet 8 : GRIB Edition Number.
-    One 8 bit field.
-  */
-  ISEC0_GRIB_Version = GRIB_EDITION(is);
-
-  if ( ISEC0_GRIB_Version > 1 )
-    Error("GRIB version %d unsupported!", ISEC0_GRIB_Version);
+  switch(GRIB_EDITION(is))
+    {   
+    case 0:
+      year                = GET_UINT1(pds[12]);
+      century             = 1;
+      subcenter           = 0;
+      decimalscale        = 0;
+      break;
+    case 1:
+      year                = PDS_Year;
+      century             = PDS_Century;
+      subcenter           = PDS_Subcenter;
+      decimalscale        = PDS_DecimalScale;
+      break;
+    default:
+      fprintf(stderr, "Grib version %d not supported!", GRIB_EDITION(is));
+      exit(EXIT_FAILURE);
+    }
 
-  grib1offset = ISEC0_GRIB_Version * 4;
+  if ( PDS_Len > 28 )
+    if ( PDS_CenterID    == 98 || PDS_Subcenter == 98 ||
+	(PDS_CenterID    ==  7 && PDS_Subcenter == 98) )
+      if ( pds[40] == 1 )
+	fc_num = GET_UINT1(pds[49]);
 
-  isLen = 4 + grib1offset;
+  if ( year < 0 )
+    {
+      date = (-year)*10000+PDS_Month*100+PDS_Day;
+      century = -century;
+    }
+  else
+    {
+      date =    year*10000+PDS_Month*100+PDS_Day;
+    }
+      
+  fprintf(stdout, "%5d :%4d%4d%4d%4d%4d %4d %4d%4d%7d%7d %8d%6d%3d%3d%3d%3d%5d%6d%5d%4d", nrec,
+	  PDS_Len,  PDS_CodeTable,   PDS_CenterID, subcenter, PDS_ModelID,
+	  PDS_GridDefinition, PDS_Parameter, PDS_LevelType, PDS_Level1, PDS_Level2,
+	  date, PDS_Time, PDS_TimePeriod1, PDS_TimePeriod2, PDS_TimeUnit, PDS_TimeRange,
+	  PDS_AvgNum, decimalscale, fc_num, century);
 
-  return (isLen);
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
 }
 
-static 
-void decodePDS_ECMWF_local_Extension_1(unsigned char *pds, int *isec1)
+
+void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  isec1[36] = GET_UINT1(pds[40]);         /* extension identifier       */
-  isec1[37] = GET_UINT1(pds[41]);         /* Class                      */
-  isec1[38] = GET_UINT1(pds[42]);         /* Type                       */
-  isec1[39] = GET_UINT2(pds[43],pds[44]); /* Stream                     */
-  /* isec1[40] = GET_UINT4(pds[45],pds[46],pds[47],pds[48]); */
-  memcpy((char*) &isec1[40], &pds[45], 4);
-  isec1[41] = GET_UINT1(pds[49]);         /* Forecast number            */
-  isec1[42] = GET_UINT1(pds[50]);         /* Total number of forecasts  */
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintPDS(nrec, recpos, recsize, gribbuffer);
+  /*
+  else if ( gribversion == 2 )
+    grib2PrintPDS(nrec, recpos, recsize, gribbuffer);
+  */
+  else
+    {
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, 0L, recpos, recsize, gribversion); 
+    }
 }
 
-static 
-void decodePDS_DWD_local_Extension_254(unsigned char *pds, int *isec1)
-{
-  long i;
-  int isvn;
 
-  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
-  for ( i = 0; i < 11; i++ ) 
-    { 
-      isec1[37+i] =  GET_UINT1(pds[41+i]);
-    } 
+void grib1PrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  static int header = 1;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  isvn = GET_UINT2(pds[52],pds[53]);
-  
-  isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
-  isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
+  UNUSED(recpos);
 
-}
+  if ( header )
+    {
+      fprintf(stdout, 
+      "  Rec : GDS  NV PVPL Typ : xsize ysize   Lat1   Lon1   Lat2   Lon2    dx    dy\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
+    }
 
-static 
-void decodePDS_DWD_local_Extension_253(unsigned char *pds, int *isec1)
-{
-  long i;
-  int isvn;
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
+    }
 
-  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
-  for ( i = 0; i < 11; i++ ) 
-    { 
-      isec1[37+i] =  GET_UINT1(pds[41+i]);
-    } 
+  fprintf(stdout, "%5d :", nrec);
 
-  isvn = GET_UINT2(pds[52],pds[53]);
-  
-  isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
-  isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
-  isec1[50] =  GET_UINT1(pds[54]);         /* User id, specified by table          */
-  isec1[51] =  GET_UINT2(pds[55],pds[56]); /* Experiment identifier                */
-  isec1[52] =  GET_UINT2(pds[57],pds[58]); /* Ensemble identification by table     */
-  isec1[53] =  GET_UINT2(pds[59],pds[60]); /* Number of ensemble members           */
-  isec1[54] =  GET_UINT2(pds[61],pds[62]); /* Actual number of ensemble member     */
-  isec1[55] =  GET_UINT1(pds[63]);         /* Model major version number           */
-  isec1[56] =  GET_UINT1(pds[64]);         /* Model minor version number           */
+  if ( gds )
+    fprintf(stdout, "%4d%4d%4d %4d :%6d%6d%7d%7d%7d%7d%6d%6d",
+	    GDS_Len,  GDS_NV,   GDS_PVPL, GDS_GridType,
+	    GDS_NumLon,   GDS_NumLat,
+	    GDS_FirstLat, GDS_FirstLon,
+	    GDS_LastLat,  GDS_LastLon,
+	    GDS_LonIncr,  GDS_LatIncr);
+  else
+    fprintf(stdout, " Grid Description Section not defined");
 
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
 }
 
-static 
-void decodePDS_MPIM_local_Extension_1(unsigned char *pds, int *isec1)
+
+void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  isec1[36] = GET_UINT1(pds[40]);         /* extension identifier            */
-  isec1[37] = GET_UINT1(pds[41]);         /* type of ensemble forecast       */
-  isec1[38] = GET_UINT2(pds[42],pds[43]); /* individual ensemble member      */
-  isec1[39] = GET_UINT2(pds[44],pds[45]); /* number of forecasts in ensemble */
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
+  /*
+  else if ( gribversion == 2 )
+    grib2PrintGDS(nrec, recpos, recsize, gribbuffer);
+  */
+  else
+    {
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, 0L, recpos, recsize, gribversion); 
+    }
 }
 
-static 
-int decodePDS(unsigned char *pds, int *isec0, int *isec1)
+
+void grib1PrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  int pdsLen;
+  static int header = 1;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  pdsLen = PDS_Len;
+  UNUSED(recpos);
 
-  ISEC1_CodeTable      = PDS_CodeTable;
-  ISEC1_CenterID       = PDS_CenterID;
-  ISEC1_ModelID        = PDS_ModelID;
-  ISEC1_GridDefinition = PDS_GridDefinition;
-  ISEC1_Sec2Or3Flag    = PDS_Sec2Or3Flag;
-  ISEC1_Parameter      = PDS_Parameter;
-  ISEC1_LevelType      = PDS_LevelType;
+  if ( header )
+    {
+      fprintf(stdout, 
+      "  Rec : Code Level     BMS    Size\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
+    }
 
-  if ( (ISEC1_LevelType !=  20) && 
-       (ISEC1_LevelType != GRIB1_LTYPE_99)        && 
-       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)  && 
-       (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)  && 
-       (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)    && 
-       (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)     && 
-       (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)    && 
-       (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH) && 
-       (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC) && 
-       (ISEC1_LevelType != 115) && 
-       (ISEC1_LevelType != 117) && 
-       (ISEC1_LevelType != 125) && 
-       (ISEC1_LevelType != 127) && 
-       (ISEC1_LevelType != GRIB1_LTYPE_SEADEPTH)  && 
-       (ISEC1_LevelType != 210) )
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      ISEC1_Level1 = PDS_Level1;
-      ISEC1_Level2 = PDS_Level2;
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
+
+  int level = get_level(pds);
+
+  fprintf(stdout, "%5d :", nrec);
+
+  if ( bms )
+    fprintf(stdout, "%4d%7d %7d %7d",
+	    PDS_Parameter, level, BMS_Len, BMS_BitmapSize);
+  else
+    fprintf(stdout, "%4d%7d Bit Map Section not defined", PDS_Parameter, level);
+
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
+}
+
+
+void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
+  /*
+  else if ( gribversion == 2 )
+    grib2PrintBMS(nrec, recpos, recsize, gribbuffer);
+  */
   else
     {
-      ISEC1_Level1 = PDS_Level;
-      ISEC1_Level2 = 0;
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, 0L, recpos, recsize, gribversion); 
     }
+}
 
-  /* ISEC1_Year        = PDS_Year; */
-  ISEC1_Month          = PDS_Month;
-  ISEC1_Day            = PDS_Day;
-  ISEC1_Hour           = PDS_Hour;
-  ISEC1_Minute         = PDS_Minute;
-  ISEC1_TimeUnit       = PDS_TimeUnit;
-  ISEC1_TimePeriod1    = PDS_TimePeriod1;
-  ISEC1_TimePeriod2    = PDS_TimePeriod2;
-  ISEC1_TimeRange      = PDS_TimeRange;
-  ISEC1_AvgNum         = PDS_AvgNum;
-  ISEC1_AvgMiss        = PDS_AvgMiss;
 
-  if ( ISEC0_GRIB_Version == 1 )
-    {
-      ISEC1_Year           = PDS_Year;
-      ISEC1_Century        = PDS_Century;
-      ISEC1_SubCenterID    = PDS_Subcenter;
-      ISEC1_DecScaleFactor = PDS_DecimalScale;
-    }
-  else
+void grib1PrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  static int header = 1;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  double scale;
+
+  UNUSED(recpos);
+
+  if ( header )
     {
-      int year;
-      year                 = GET_UINT1(pds[12]);
-      if ( year <= 100 )
-	{
-	  ISEC1_Year       = year;
-	  ISEC1_Century    = 1;
-	}
-      else
-	{
-	  ISEC1_Year       = year%100;
-	  ISEC1_Century    = 1 + (year-ISEC1_Year)/100;
-	}
-      ISEC1_SubCenterID    = 0;
-      ISEC1_DecScaleFactor = 0;
+      fprintf(stdout, 
+      "  Rec : Code Level     BDS Flag     Scale   RefValue Bits  CR\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
     }
 
-  if ( ISEC1_Year < 0 )
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      ISEC1_Year    = -ISEC1_Year;
-      ISEC1_Century = -ISEC1_Century;
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
 
-  ISEC1_LocalFLag = 0;
-  if ( pdsLen > 28 )
-    {
-      int localextlen;
-      localextlen = pdsLen-28;
+  int level = get_level(pds);
 
-      if ( localextlen > 4000 )
-	{
-	  Warning("PDS larger than 4000 bytes not supported!");
-	}
-      else
-	{
-	  ISEC1_LocalFLag = 1;
+  double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
 
-	  if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
-	    {
-	      if ( pds[40] == 254 ) 
-		{
-		  decodePDS_DWD_local_Extension_254(pds, isec1);
-		}
-	      else if ( pds[40] == 253 )
-		{ 
-		  decodePDS_DWD_local_Extension_253(pds, isec1);
-		}
-	    }
-	  else if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
-		    (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
-		    (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
-	    {
-	      if ( pds[40] == 1 )
-		decodePDS_ECMWF_local_Extension_1(pds, isec1);
-	    }
-	  else if ( ISEC1_CenterID    == 252 && ISEC1_LocalFLag ==  1 )
-	    {
-	      if ( pds[40] == 1 )
-		decodePDS_MPIM_local_Extension_1(pds, isec1);	      
-	    }
-	  else
-	    {
-	      long i;
-	      for ( i = 0; i < localextlen; i++ )
-		{
-		  isec1[24+i] = pds[28+i];
-		}
-	    }
-	}
-    }
+  double refval = BDS_RefValue;
 
-  return (pdsLen);
-}
+  if ( BDS_BinScale < 0 )
+    scale = 1.0/pow(2.0, (double) -BDS_BinScale);
+  else
+    scale = pow(2.0, (double) BDS_BinScale);
 
+  if ( PDS_DecimalScale )
+    {
+      double decscale = pow(10.0, (double)-PDS_DecimalScale);
+      refval *= decscale;
+      scale  *= decscale;
+    }
 
-void gribPrintSec2_double(int *isec0, int *isec2, double *fsec2) {gribPrintSec2DP(isec0, isec2, fsec2);}
-void gribPrintSec3_double(int *isec0, int *isec3, double *fsec3) {gribPrintSec3DP(isec0, isec3, fsec3);}
-void gribPrintSec4_double(int *isec0, int *isec4, double *fsec4) {gribPrintSec4DP(isec0, isec4, fsec4);}
-void gribPrintSec2_float(int *isec0, int *isec2, float *fsec2) {gribPrintSec2SP(isec0, isec2, fsec2);}
-void gribPrintSec3_float(int *isec0, int *isec3, float *fsec3) {gribPrintSec3SP(isec0, isec3, fsec3);}
-void gribPrintSec4_float(int *isec0, int *isec4, float *fsec4) {gribPrintSec4SP(isec0, isec4, fsec4);}
+  fprintf(stdout, "%5d :", nrec);
 
+  if ( bds )
+    fprintf(stdout, "%4d%7d %7d %4d %8.5g %11.5g%4d %6.4g",
+	    PDS_Parameter, level,
+	    BDS_Len, BDS_Flag, scale, refval, BDS_NumBits, cr);
+  else
+    fprintf(stdout, " Binary Data Section not defined");
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
+}
 
-#include <inttypes.h>
 
-static 
-void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T *restrict fpdata)
+void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  unsigned int tbits = 0;
-  int n_bits = NumBits;
-  int t_bits = 0;
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-  unsigned jmask = (1U << n_bits) - 1U;
-  for ( i = 0; i < jlend; i++ )
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
+  /*
+  else if ( gribversion == 2 )
+    grib2PrintBDS(nrec, recpos, recsize, gribbuffer);
+  */
+  else
     {
-      if (n_bits - t_bits > 8)
-	{
-	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
-	  bits += 2;
-	  t_bits += 16;
-	}
-
-      while ( t_bits < n_bits )
-	{
-	  tbits = (tbits * 256) + *bits++;
-	  t_bits += 8;
-	}
-      t_bits -= n_bits;
-      fpdata[i] = (float)((tbits >> t_bits) & jmask);
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, 0L, recpos, recsize, gribversion); 
     }
-  /* at least this vectorizes :) */
-  for ( i = 0; i < jlend; i++ )
-    fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-static
-void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
-				      T fmin, T zscale, T *restrict fpdata)
+
+void gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
-  static const double shift[9]
-    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  int n_bits = NumBits;
-  int c_bits, j_bits;
+  UNUSED(recpos);
 
-  /* older unoptimized code, not often used */
-  c_bits = 8;
-  for ( i = 0; i < jlend; i++ )
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      double jj = 0.0;
-      j_bits = n_bits;
-      while (c_bits <= j_bits)
-	{
-	  if (c_bits == 8)
-	    {
-	      jj = jj * 256.0  + (double) (*bits++);
-	      j_bits -= 8;
-	    }
-	  else
-	    {
-	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
-	      bits++;
-	      j_bits -= c_bits;
-	      c_bits = 8;
-	    }
-	}
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
+    }
 
-      if (j_bits)
-	{
-	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
-	}
-      fpdata[i] = (T)(fmin + zscale*jj);
+  if ( nerr > 0 )
+    {
+      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
+      return;
     }
+
+  int level = get_level(pds);
+
+  double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
+
+  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
+    fprintf(stdout, "GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
 }
 
+
 static
-void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
-                                    T *fpdata, T fmin, T zscale)
+void repair1(unsigned char *gbuf, long gbufsize)
 {
-  U_BYTEORDER;
-  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  /* int recLen; */
+  unsigned char *source;
+  size_t sourceLen;
+  int bds_nbits, bds_flag, lspherc, lcomplex /*, lcompress */;
+  int bds_head = 11;
+  int bds_ext = 0, bds_ubits;
+  int datstart = 0;
 
-  if ( IS_BIGENDIAN() )
+  long gribrecsize;
+  int nerr = grib1Sections(gbuf, gbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      for ( size_t i = 0; i < jlend; i++ )
-        {
-          fpdata[i] = fmin + zscale * sgrib[i];
-        }
+      fprintf(stdout, "GRIB message error\n");
+      return;
     }
-  else
+
+  if ( nerr > 0 )
     {
-      uint16_t ui16;
-      for ( size_t i = 0; i < jlend; i++ )
-        {
-          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
-          fpdata[i] = fmin + zscale * ui16;
-        }
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return;
     }
-}
-
-static 
-void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
-			      T fmin, T zscale, T *restrict fpdata)
-{
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
-  uint64_t start_decode, end_decode;
-#endif
 
-  long i;
-#if defined (VECTORCODE)
-  GRIBPACK *lgrib = NULL;
+  unsigned bds_len   = BDS_Len;
+  bds_nbits = BDS_NumBits;
+  bds_flag  = BDS_Flag;
+  bds_ubits = bds_flag & 15;
+  lspherc   =  bds_flag >> 7;
+  lcomplex  = (bds_flag >> 6)&1;
+  /* lcompress = (bds_flag >> 4)&1; */
 
-  if ( numBits%8 == 0 )
+  if ( lspherc )
     {
-      long jlenc = jlend * numBits / 8;
-      if ( jlenc > 0 ) 
+      if ( lcomplex  )
 	{
-	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
-	  if ( lgrib == NULL ) SysError("No Memory!");
-
-	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
+	  int jup, ioff;
+	  jup  = bds[15];
+	  ioff = (jup+1)*(jup+2);
+	  bds_ext = 4 + 3 + 4*ioff;
+	}
+      else
+	{
+	  bds_ext = 4;
 	}
     }
 
-  if ( numBits ==  0 )
-    {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
-    }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (int)lgrib[i];
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 16 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 24 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
-	  	 (int)lgrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
-		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits <= 25 )
-    {
-      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else if ( numBits > 25 && numBits < 32 )
-    {
-      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else
-    {
-      Error("Unimplemented packing factor %d!", numBits);
-    }
+  datstart = bds_head + bds_ext;
 
-  if ( lgrib ) Free(lgrib);
+  source = bds + datstart;
 
-#else
-  if ( numBits ==  0 )
-    {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
-    }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (int)igrib[i];
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 16 )
+  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
+
+  if ( bds_nbits == 24 )
     {
-      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
+      unsigned char *pbuf = (unsigned char*) Malloc(sourceLen);;
+      size_t nelem = sourceLen/3;
+      for ( size_t i = 0; i < nelem; i++ )
+	{
+	  pbuf[3*i  ] = source[        i];
+	  pbuf[3*i+1] = source[  nelem+i];
+	  pbuf[3*i+2] = source[2*nelem+i];
+	}
+      memcpy(source, pbuf, sourceLen);
+      Free(pbuf);
     }
-  else if ( numBits == 24 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-                     (int)igrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits <= 25 )
+}
+
+
+void gribRepair1(int nrec, long recsize, unsigned char *gribbuffer)
+{
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
-  else if ( numBits > 25 && numBits < 32 )
+
+  if ( nerr > 0 )
     {
-      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
+      return;
     }
-  else
+
+  int level = get_level(pds);
+
+  double cr = (((BDS_Flag >> 4)&1) && BDS_Z == 128) ? get_cr(&bds[17], &bds[20]) : 1;
+
+  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
     {
-      Error("Unimplemented packing factor %d!", numBits);
+      fprintf(stdout, "Repair GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
+      repair1(gribbuffer, recsize);
     }
+}
+#include <stdio.h>
+#include <string.h>
+
+#if defined (HAVE_CONFIG_H)
+#endif
+
+#if  defined (HAVE_LIBSZ)
+#if defined(__cplusplus)
+extern "C" {
 #endif
+#include <szlib.h>
+#if defined (__cplusplus)
 }
+#endif
 
-#endif /* T */
+#define OPTIONS_MASK        (SZ_RAW_OPTION_MASK | SZ_MSB_OPTION_MASK | SZ_NN_OPTION_MASK)
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+#define PIXELS_PER_BLOCK    (8)
+#define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
 
-#ifdef T
-#undef T
+#define MIN_COMPRESS        (0.95)
+#define MIN_SIZE            (256)
 #endif
-#define T float
-#ifdef T
 
-#include <inttypes.h>
+#define  Z_SZIP  128
 
-static 
-void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
-				     T fmin, T zscale, T *restrict fpdata)
-{
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  unsigned int tbits = 0;
-  int n_bits = NumBits;
-  int t_bits = 0;
 
-  unsigned jmask = (1U << n_bits) - 1U;
-  for ( i = 0; i < jlend; i++ )
-    {
-      if (n_bits - t_bits > 8)
-	{
-	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
-	  bits += 2;
-	  t_bits += 16;
-	}
+#define SetLen3(var, offset, value) ((var[offset+0] = 0xFF & (value >> 16)), \
+				     (var[offset+1] = 0xFF & (value >>  8)), \
+				     (var[offset+2] = 0xFF & (value      )))
+#define SetLen4(var, offset, value) ((var[offset+0] = 0xFF & (value >> 24)), \
+				     (var[offset+1] = 0xFF & (value >> 16)), \
+				     (var[offset+2] = 0xFF & (value >>  8)), \
+				     (var[offset+3] = 0xFF & (value      )))
 
-      while ( t_bits < n_bits )
-	{
-	  tbits = (tbits * 256) + *bits++;
-	  t_bits += 8;
-	}
-      t_bits -= n_bits;
-      fpdata[i] = (float)((tbits >> t_bits) & jmask);
-    }
-  /* at least this vectorizes :) */
-  for ( i = 0; i < jlend; i++ )
-    fpdata[i] = fmin + zscale*fpdata[i];
-}
 
-static
-void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
-				      T fmin, T zscale, T *restrict fpdata)
+int gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize)
 {
-  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
-  static const double shift[9]
-    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+  int compress = 0;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  int n_bits = NumBits;
-  int c_bits, j_bits;
+  int gribversion = gribVersion(gribbuffer, recsize);
 
-  /* older unoptimized code, not often used */
-  c_bits = 8;
-  for ( i = 0; i < jlend; i++ )
-    {
-      double jj = 0.0;
-      j_bits = n_bits;
-      while (c_bits <= j_bits)
-	{
-	  if (c_bits == 8)
-	    {
-	      jj = jj * 256.0  + (double) (*bits++);
-	      j_bits -= 8;
-	    }
-	  else
-	    {
-	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
-	      bits++;
-	      j_bits -= c_bits;
-	      c_bits = 8;
-	    }
-	}
+  if ( gribversion == 2 ) return compress;
 
-      if (j_bits)
-	{
-	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
-	}
-      fpdata[i] = (T)(fmin + zscale*jj);
+  long gribrecsize;
+  int nerr = grib1Sections(gribbuffer, (long)recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "GRIB message error\n");
+      return compress;
     }
-}
-
-static
-void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
-                                    T *fpdata, T fmin, T zscale)
-{
-  U_BYTEORDER;
-  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
 
-  if ( IS_BIGENDIAN() )
+  if ( nerr > 0 )
     {
-      for ( size_t i = 0; i < jlend; i++ )
-        {
-          fpdata[i] = fmin + zscale * sgrib[i];
-        }
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return compress;
     }
-  else
+
+  /* bds_len   = BDS_Len; */
+  /* bds_nbits = BDS_NumBits; */
+  int bds_flag  = BDS_Flag;
+  /* lspherc   =  bds_flag >> 7; */
+  /* lcomplex  = (bds_flag >> 6)&1; */
+  int lcompress = (bds_flag >> 4)&1;
+
+  size_t gribsize = 0;
+  if ( lcompress )
     {
-      uint16_t ui16;
-      for ( size_t i = 0; i < jlend; i++ )
-        {
-          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
-          fpdata[i] = fmin + zscale * ui16;
-        }
+      compress = BDS_Z;
+      if ( compress == Z_SZIP ) gribsize = (size_t) GET_UINT3(bds[14], bds[15], bds[16]);
     }
+
+  *urecsize = gribsize;
+
+  return compress;
 }
 
-static 
-void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
-			      T fmin, T zscale, T *restrict fpdata)
+
+int gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
 {
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
-  uint64_t start_decode, end_decode;
+#if ! defined(HAVE_LIBSZ)
+  static int libszwarn = 1;
 #endif
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  bool llarge = false;
 
-  long i;
-#if defined (VECTORCODE)
-  GRIBPACK *lgrib = NULL;
+  unsigned gribLen = GET_UINT3(dbuf[4], dbuf[5], dbuf[6]);
 
-  if ( numBits%8 == 0 )
-    {
-      long jlenc = jlend * numBits / 8;
-      if ( jlenc > 0 ) 
-	{
-	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
-	  if ( lgrib == NULL ) SysError("No Memory!");
+  int rec_len = gribLen;
 
-	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
-	}
+  long gribrecsize;
+  int nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "GRIB message error\n");
+      return gribrecsize;
     }
 
-  if ( numBits ==  0 )
+  if ( nerr > 0 )
     {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return gribrecsize;
     }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (int)lgrib[i];
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 16 )
-    for ( i = 0; i < jlend; i++ )
+
+   int bds_zoffset = 12;
+
+   int bds_len   = BDS_Len;
+   if ( gribLen > JP23SET && bds_len <= 120 )
+     {
+       gribLen &= JP23SET;
+       gribLen *= 120;
+       bds_len = correct_bdslen(bds_len, gribLen, bds-dbuf);
+       llarge = true;
+       bds_zoffset += 2;
+     }
+
+   if ( gribLen > JP24SET || llarge ) return gribLen;
+ 
+#if  defined(HAVE_LIBSZ)
+  {
+    int bds_zstart = 14;
+    unsigned gribLenOld = 0;
+    int bds_head = 11;
+    int bds_ext = 0;
+    unsigned char *pbuf = NULL;
+
+    int bds_nbits = BDS_NumBits;
+    int bds_flag  = BDS_Flag;
+    int bds_ubits = bds_flag & 15;
+    int lspherc   =  bds_flag >> 7;
+    int lcomplex  = (bds_flag >> 6)&1;
+    /* lcompress = (bds_flag >> 4)&1; */
+    
+    if ( bds_nbits != 8 && bds_nbits != 16 && bds_nbits != 24 && bds_nbits != 32 )
       {
-	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
-	fpdata[i] = fmin + zscale * dval;
+	static bool linfo = true;
+	if ( linfo && bds_nbits != 0 )
+	  {
+	    linfo = false;
+	    fprintf(stderr, "GRIB szip supports only 8, 16, 24 and 32 bit data!\n");
+	  }
+	return rec_len;
       }
-  else if ( numBits == 24 )
-    for ( i = 0; i < jlend; i++ )
+
+    int bits_per_sample = (bds_nbits == 24) ? 8 : bds_nbits;
+
+    SZ_com_t sz_param;          /* szip parameter block */
+    sz_param.options_mask        = OPTIONS_MASK;
+    sz_param.bits_per_pixel      = bits_per_sample;
+    sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
+    sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
+
+    if ( lspherc )
       {
-	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
-	  	 (int)lgrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
+        bds_ext = 4;
+	if ( lcomplex )
+	  {
+	    int jup  = bds[15];
+	    int ioff = (jup+1)*(jup+2);
+	    bds_ext += 3 + 4*ioff;
+	  }
       }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
+
+    size_t datstart = bds_head + bds_ext;
+
+    size_t datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+
+    if ( datsize < MIN_SIZE ) return rec_len;
+    /*
+    fprintf(stderr, "%d %d %d %d\n", bds_len, datstart, bds_len - datstart, datsize);
+    */
+    size_t sourceLen = datsize;
+    size_t destLen   = sbufsize;
+    
+    unsigned char *source = bds + datstart;
+    unsigned char *dest = sbuf;
+
+    if ( bds_nbits == 24 )
       {
-	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
-		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
-	fpdata[i] = fmin + zscale * dval;
+	long nelem = sourceLen/3;
+	pbuf = (unsigned char*) Malloc(sourceLen);
+	for ( long i = 0; i < nelem; i++ )
+	  {
+	    pbuf[        i] = source[3*i  ];
+	    pbuf[  nelem+i] = source[3*i+1];
+	    pbuf[2*nelem+i] = source[3*i+2];
+	  }
+	source = pbuf;
       }
-  else if ( numBits <= 25 )
-    {
-      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else if ( numBits > 25 && numBits < 32 )
-    {
-      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else
-    {
-      Error("Unimplemented packing factor %d!", numBits);
-    }
-
-  if ( lgrib ) Free(lgrib);
 
-#else
-  if ( numBits ==  0 )
-    {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
-    }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
+    int status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
+    if ( status != SZ_OK )
       {
-	T dval = (int)igrib[i];
-	fpdata[i] = fmin + zscale * dval;
+	if ( status == SZ_NO_ENCODER_ERROR )
+	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_PARAM_ERROR )
+	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_MEM_ERROR )
+	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_OUTBUFF_FULL )
+	  /*Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2)*/;
+	else
+	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
       }
-  else if ( numBits == 16 )
-    {
-      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
-    }
-  else if ( numBits == 24 )
-    for ( i = 0; i < jlend; i++ )
+    
+    if ( pbuf ) Free(pbuf);
+    /*
+    fprintf(stderr, "sourceLen, destLen %d %d\n", sourceLen, destLen);
+    */
+    if ( destLen < MIN_COMPRESS*sourceLen )
       {
-	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-                     (int)igrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
+	source = bds + datstart + bds_zoffset;
+	memcpy(source, dest, destLen);
+	
+	/* ----++++ number of unused bits at end of section) */
+
+	BDS_Flag -= bds_ubits;
+    
+	gribLenOld = gribLen;
+
+	if ( bds_ext )
+	  for ( long i = bds_ext-1; i >= 0; --i )
+	    bds[bds_zoffset+bds_head+i] = bds[bds_head+i];
+
+	/*
+	fprintf(stderr, "destLen, datsize, datstart %d %d %d\n", destLen, datsize, datstart);
+	*/
+	/*	memcpy(bds + datstart + bds_zoffset, source, destLen); */
+	/*
+	  fprintf(stderr, "z>>> %d %d %d %d <<<\n", (int) bds[0+datstart+bds_zoffset],
+	    (int)bds[1+datstart+bds_zoffset], (int)bds[2+datstart+bds_zoffset], (int)bds[3+datstart+bds_zoffset]);
+	*/
+	if ( llarge )
+	  {
+	    if ( gribLenOld%120 )
+	      {
+		fprintf(stderr, "Internal problem, record length not multiple of 120!");
+		while ( gribLenOld%120 ) gribLenOld++;
+	      }
+            // gribLenOld = gribLenOld / (-120);
+	    // gribLenOld = JP23SET - gribLenOld + 1;
+
+	    SetLen3(bds, bds_zstart, gribLenOld);
+	    SetLen4(bds, bds_zstart+3, sourceLen);
+	    SetLen4(bds, bds_zstart+7, destLen);
+	  }
+	else
+	  {
+	    SetLen3(bds, bds_zstart, gribLenOld);
+	    SetLen3(bds, bds_zstart+3, sourceLen);
+	    SetLen3(bds, bds_zstart+6, destLen);
+	  }
+
+	int bdsLen = datstart + bds_zoffset + destLen;
+
+	bds[11] = 0;
+	bds[12] = 0;
+
+	BDS_Z   = Z_SZIP;
+
+	BDS_Flag += 16;
+	if ( (bdsLen%2) == 1 )
+	  {
+	    BDS_Flag += 8;
+	    bds[bdsLen++] = 0;
+	  }
+
+	SetLen3(bds, 0, bdsLen);
+
+	gribLen = (bds - dbuf) + bdsLen;
+
+	dbuf[gribLen++] = '7';
+	dbuf[gribLen++] = '7';
+	dbuf[gribLen++] = '7';
+	dbuf[gribLen++] = '7';
+
+	if ( llarge )
+	  {
+	    long bdslen = gribLen - 4;
+
+	    /*
+	      If a very large product, the section 4 length field holds
+	      the number of bytes in the product after section 4 upto
+	      the end of the padding bytes.
+	      This is a fixup to get round the restriction on product lengths
+	      due to the count being only 24 bits. It is only possible because
+	      the (default) rounding for GRIB products is 120 bytes.
+	    */
+	    while ( gribLen%120 ) dbuf[gribLen++] = 0;
+
+	    long itemp = gribLen / (-120);
+	    itemp = JP23SET - itemp + 1;
+
+	    SetLen3(dbuf, 4, itemp);
+
+	    bdslen = gribLen - bdslen;
+
+	    SetLen3(bds, 0, bdslen);
+	  }
+	else
+	  {
+	    SetLen3(dbuf, 4, gribLen);
+	  }
       }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
+    else
       {
-	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
-                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
-	fpdata[i] = fmin + zscale * dval;
       }
-  else if ( numBits <= 25 )
-    {
-      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else if ( numBits > 25 && numBits < 32 )
-    {
-      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
-    }
-  else
+    /*
+    fprintf(stderr, "%3d %3d griblen in %6d  out %6d  CR %g   slen %6d dlen %6d  CR %g\n",
+	    PDS_Parameter, PDS_Level1, gribLenOld, gribLen,
+	    ((double)gribLenOld)/gribLen, sourceLen, destLen,
+	    ((double)sourceLen)/destLen);
+    */
+  }
+
+#else
+  
+  UNUSED(sbuf);
+  UNUSED(sbufsize);
+
+  if ( libszwarn )
     {
-      Error("Unimplemented packing factor %d!", numBits);
+      Warning("Compression disabled, szlib not available!");
+      libszwarn = 0;
     }
 #endif
-}
 
-#endif /* T */
+  if ( llarge )
+    while ( gribLen%120 ) dbuf[gribLen++] = 0;
+  else
+    while ( gribLen & 7 ) dbuf[gribLen++] = 0;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+  rec_len = gribLen;
 
+  return rec_len;
+}
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
 
-static 
-int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
+int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
 {
-  /* int imisng = 0; */
-  int  ReducedGrid = FALSE, VertCoorTab = FALSE;
-#if defined (VECTORCODE)
-  unsigned char *igrib;
-  GRIBPACK *lgrib = NULL;
-  size_t lGribLen = 0;
+#if ! defined(HAVE_LIBSZ)
+  static int libszwarn = 1;
 #endif
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  size_t gribLen = 0;
+  size_t destLen, sourceLen;
+  enum { bds_head = 11 };
+  int bds_ext = 0;
 
-  *numGridVals = 0;
-
-  memset(isec2, 0, 22*sizeof(int));
-
-  int gdsLen = GDS_Len;
-
-  int ipvpl = GDS_PVPL;
-  if ( ipvpl == 0 ) ipvpl = 0xFF;
+  UNUSED(dbufsize);
 
-  if ( ipvpl != 0xFF )
-    { /* Either vct or reduced grid */
-      if ( GDS_NV != 0 )
-	{ /* we have vct */
-	  VertCoorTab = TRUE;
-	  int ipl =  4*GDS_NV + ipvpl - 1;
-	  if ( ipl < gdsLen )
-	    {
-	      ReducedGrid = TRUE;
-	    }
-	}
-      else
-	{
-	  VertCoorTab = FALSE;
-	  ReducedGrid = TRUE;
-	}
-      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
+  long gribrecsize;
+  int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "GRIB message error\n");
+      return 0;
     }
- 
-  if ( ISEC0_GRIB_Version == 0 )
+
+  if ( nerr > 0 )
     {
-      VertCoorTab = (gdsLen - 32) > 0;
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return 0;
     }
-  
-  if ( ReducedGrid )
+
+  //unsigned bds_len = BDS_Len;
+  bool llarge = false;
+
+  int bds_zoffset = 12;
+  if ( llarge ) bds_zoffset += 2;
+
+  int bds_nbits = BDS_NumBits;
+  int bds_flag  = BDS_Flag;
+  int lspherc   =  bds_flag >> 7;
+  int lcomplex  = (bds_flag >> 6)&1;
+  /* lcompress = (bds_flag >> 4)&1; */
+
+  if ( lspherc )
     {
-      int locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
-      int jlenl = (gdsLen - locnl)  >> 1;
-      if ( jlenl == GDS_NumLat )
+      if ( lcomplex  )
 	{
-	  *numGridVals = 0;
-	  ISEC2_Reduced = TRUE;
-	  for ( int i = 0; i < jlenl; i++ )
-	    {
-	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
-	      *numGridVals += ISEC2_RowLon(i);
-	    }
+	  int jup  = bds[bds_zoffset+15];
+	  int ioff = (jup+1)*(jup+2);
+	  bds_ext = 4 + 3 + 4*ioff;
 	}
       else
 	{
-	  ReducedGrid = FALSE;
+	  bds_ext = 4;
 	}
     }
 
-  ISEC2_GridType = GDS_GridType;
+  size_t datstart = bds_head + (size_t)bds_ext;
 
-  /*
-     Gaussian grid definition.
-  */
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
-       ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
-       ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-    {
-      ISEC2_NumLat    = GDS_NumLat;
-      if ( ! ReducedGrid )
-	{
-	  ISEC2_NumLon = GDS_NumLon;
-	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
-	}
-      ISEC2_FirstLat  = GDS_FirstLat;
-      ISEC2_FirstLon  = GDS_FirstLon;
-      ISEC2_ResFlag   = GDS_ResFlag;
-      ISEC2_LastLat   = GDS_LastLat;
-      ISEC2_LastLon   = GDS_LastLon;
-      ISEC2_LonIncr   = GDS_LonIncr;
+  unsigned char *source = bds + datstart + bds_zoffset;
+  if ( llarge )
+    sourceLen = ((size_t) ((bds[21]<<24)+(bds[22]<<16)+(bds[23]<<8)+bds[24]));
+  else
+    sourceLen = ((size_t) ((bds[20]<<16)+(bds[21]<<8)+bds[22]));
 
-      ISEC2_NumPar    = GDS_NumPar;
-      ISEC2_ScanFlag  = GDS_ScanFlag;
-      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-	{
-	  ISEC2_LatSP     = GDS_LatSP;
-	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = (T)GDS_RotAngle;
-	}
-      /*
-	if ( Lons != Longitudes || Lats != Latitudes )
-	Error("Latitude/Longitude Conflict");
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
-    {
-      /*
-      iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
-    {
-      /*
-      iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
-    {
-      ISEC2_NumLon    = GDS_NumLon;
-      ISEC2_NumLat    = GDS_NumLat;
-      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
-      ISEC2_FirstLat  = GDS_FirstLat;
-      ISEC2_FirstLon  = GDS_FirstLon;
-      ISEC2_ResFlag   = GDS_ResFlag;
-      ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
-      ISEC2_Lambert_dx    = GDS_Lambert_dx;
-      ISEC2_Lambert_dy    = GDS_Lambert_dy;
-      ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
-      ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
-      ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
-      ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
-      ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
-      ISEC2_ScanFlag      = GDS_ScanFlag;
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
+  nerr = grib1Sections(dbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
-      ISEC2_PentaK  = GDS_PentaK;
-      ISEC2_PentaM  = GDS_PentaM;
-      ISEC2_RepType = GDS_RepType;
-      ISEC2_RepMode = GDS_RepMode;
-      *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
-      isec2[ 6] = 0;
-      isec2[ 7] = 0;
-      isec2[ 8] = 0;
-      isec2[ 9] = 0;
-      isec2[10] = 0;
-      /*
-      iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
-      */
+      fprintf(stdout, "GRIB message error\n");
+      return 0;
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+
+  if ( nerr > 0 )
     {
-      ISEC2_GME_NI2    = GDS_GME_NI2;
-      ISEC2_GME_NI3    = GDS_GME_NI3;
-      ISEC2_GME_ND     = GDS_GME_ND;
-      ISEC2_GME_NI     = GDS_GME_NI;
-      ISEC2_GME_AFlag  = GDS_GME_AFlag;
-      ISEC2_GME_LatPP  = GDS_GME_LatPP;
-      ISEC2_GME_LonPP  = GDS_GME_LonPP;
-      ISEC2_GME_LonMPL = GDS_GME_LonMPL;
-      ISEC2_GME_BFlag  = GDS_GME_BFlag;
-      *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
-      /*
-      iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
-      */
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return 0;
     }
+
+  unsigned char *dest = bds + datstart;
+  if ( llarge )
+    destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
   else
-    {
-      ISEC2_NumLon = GDS_NumLon;
-      ISEC2_NumLat = GDS_NumLat;
-      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
-      Message("Gridtype %d unsupported", ISEC2_GridType);
-    }
+    destLen = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
+
+  BDS_Flag = (unsigned char)(BDS_Flag - 16);
+
+  size_t bdsLen = datstart + destLen;
+
+#if  defined(HAVE_LIBSZ)
+  {
+    int bds_zstart = 14;
+    unsigned recLen = GET_UINT3(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
+
+    int bits_per_sample = (bds_nbits == 24) ? 8 : bds_nbits;
+
+    SZ_com_t sz_param;          /* szip parameter block */
+    sz_param.options_mask        = OPTIONS_MASK;
+    sz_param.bits_per_pixel      = bits_per_sample;
+    sz_param.pixels_per_block    = PIXELS_PER_BLOCK;
+    sz_param.pixels_per_scanline = PIXELS_PER_SCANLINE;
+
+    if ( bds_ext )
+      for ( long i = 0; i < bds_ext; ++i )
+	bds[bds_head+i] = bds[bds_zoffset+bds_head+i];
+
+    /*    fprintf(stderr, "gribUnzip: sourceLen %ld; destLen %ld\n", (long)sourceLen, (long)destLen);
+    fprintf(stderr, "gribUnzip: sourceOff %d; destOff %d\n", bds[12], bds[11]);
+    fprintf(stderr, "gribUnzip: reclen %d; bdslen %d\n", recLen, bdsLen);
+    */
+
+    size_t tmpLen = destLen;
+
+    int status = SZ_BufftoBuffDecompress(dest, &tmpLen, source, sourceLen, &sz_param);
+    if ( status != SZ_OK )
+      {
+	if ( status == SZ_NO_ENCODER_ERROR )
+	  Warning("SZ_NO_ENCODER_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_PARAM_ERROR )
+	  Warning("SZ_PARAM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_MEM_ERROR )
+	  Warning("SZ_MEM_ERROR code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else if ( status == SZ_OUTBUFF_FULL )
+	  Warning("SZ_OUTBUFF_FULL code %3d level %3d", PDS_Parameter, PDS_Level2);
+	else
+	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
+      }
+    /*
+    fprintf(stderr, "gribUnzip: sl = %ld  dl = %ld   tl = %ld\n",
+	    (long)sourceLen, (long)destLen,(long) tmpLen);
+    */
+    if ( tmpLen != destLen )
+      Warning("unzip size differ: code %3d level %3d  ibuflen %ld ubuflen %ld",
+	      PDS_Parameter, PDS_Level2, (long) destLen, (long) tmpLen);
+
+    if ( bds_nbits == 24 )
+      {
+	long nelem = tmpLen/3;
+	unsigned char *pbuf = (unsigned char*) Malloc(tmpLen);
+	for ( long i = 0; i < nelem; i++ )
+	  {
+	    pbuf[3*i  ] = dest[        i];
+	    pbuf[3*i+1] = dest[  nelem+i];
+	    pbuf[3*i+2] = dest[2*nelem+i];
+	  }
+	memcpy(dest, pbuf, tmpLen);
+	Free(pbuf);
+      }
+
+    int bds_ubits = BDS_Flag & 15;
+    BDS_Flag -= bds_ubits;
 
-  /*    vertical coordinate parameters for hybrid levels.     */
-  /*    get number of vertical coordinate parameters, if any. */
+    if ( (bdsLen%2) == 1 )
+      {
+	BDS_Flag += 8;
+	bds[bdsLen++] = 0;
+      }
 
-  ISEC2_NumVCP = 0;
+    SetLen3(bds, 0, bdsLen);
 
-  isec2[17] = 0;
-  isec2[18] = 0;
+    gribLen = (bds - dbuf) + bdsLen;
+    
+    dbuf[gribLen++] = '7';
+    dbuf[gribLen++] = '7';
+    dbuf[gribLen++] = '7';
+    dbuf[gribLen++] = '7';
 
-  if ( VertCoorTab == TRUE )
-    {
-      int locnv;
-      if ( ISEC0_GRIB_Version  == 0 )
-	{
-	  locnv = 32;
-	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
-	}
-      else
-	{
-	  locnv = GDS_PVPL - 1;
-	  ISEC2_NumVCP = GDS_NV;
-	}
-#if defined (SX)
-      lGribLen = 4*ISEC2_NumVCP;	      
-      lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
+    if ( llarge )
+      {
+	long itemp;
+        bdsLen = gribLen - 4;
+	/*
+	  If a very large product, the section 4 length field holds
+	  the number of bytes in the product after section 4 upto
+	  the end of the padding bytes.
+	  This is a fixup to get round the restriction on product lengths
+	  due to the count being only 24 bits. It is only possible because
+	  the (default) rounding for GRIB products is 120 bytes.
+	*/
+	while ( gribLen%120 ) dbuf[gribLen++] = 0;
 
-      igrib = &gds[locnv];
-      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  int iexp   = (lgrib[4*i  ]);
-	  int imant  =(((lgrib[4*i+1]) << 16) +
-                       ((lgrib[4*i+2]) <<  8) +
-                       ( lgrib[4*i+3]));
-	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
-	}
+	if ( gribLen != (size_t)recLen )
+	  fprintf(stderr, "Internal problem, recLen and gribLen differ!\n");
+	
+	itemp = gribLen / (-120);
+	itemp = JP23SET - itemp + 1;
+	
+	SetLen3(dbuf, 4, itemp);
 
-      Free(lgrib);
+	bdsLen = gribLen - bdsLen;
+	    
+	SetLen3(bds, 0, bdsLen);
+      }
+    else
+      {
+	SetLen3(dbuf, 4, recLen);
+      }
+    /*
+    fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
+    */
+    if ( llarge )
+      while ( gribLen%120 ) dbuf[gribLen++] = 0;
+    else
+      while ( gribLen & 7 ) dbuf[gribLen++] = 0;
+    /*
+    fprintf(stderr, "recLen, gribLen, bdsLen %d %d %d\n", recLen, gribLen, bdsLen);
+    */
+  }
 #else
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  int iexp   = (gds[locnv+4*i  ]);
-	  int imant  =(((gds[locnv+4*i+1]) << 16) +
-                       ((gds[locnv+4*i+2]) <<  8) +
-                       ( gds[locnv+4*i+3]));
-	  fsec2[10+i] = (T)decfp2(iexp,imant);
-	}
-#endif
+  UNUSED(bds_nbits);
+  UNUSED(sourceLen);
+  UNUSED(source);
+  UNUSED(bdsLen);
+  UNUSED(dest);
+  
+  if ( libszwarn )
+    {
+      Warning("Decompression disabled, szlib not available!");
+      libszwarn = 0;
     }
+#endif
 
-  return gdsLen;
+  return (int)gribLen;
 }
+#include <stdio.h>
+#include <math.h>
+
 
-#define ldexp_double ldexp
-#define ldexp_float ldexpf
 
 static
-int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
-			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
+int rowina2(double *p, int ko, int ki, double *pw,
+	    int kcode, double msval, int *kret)
 {
-  unsigned char *igrib;
-  int lspherc = FALSE, lcomplex = FALSE;
-  int lcompress;
-  int jup, kup, mup;
-  int locnd;
-  int bds_flag, jscale, imiss;
-  int bds_ubits;
-  int ioff = 0;
-  int iexp, imant;
-  int zoff;
-  int bds_head = 11;
-  T zscale = 0.;
-  T fmin = 0.;
-  T *fpdata = fsec4;
-  int bdsLen;
-  extern int CGRIBEX_Fix_ZSE;
-
-  *iret = 0;
-  igrib = bds;
-
-  memset(isec4, 0, 42*sizeof(int));
+  /* System generated locals */
+  int pw_dim1, pw_offset, i_1;
 
-  /* get length of binary data block. */
+  /* Local variables */
+  double zwt1, zrdi, zpos;
+  int jl, ip;
+  double zdo, zwt;
 
-  bdsLen = BDS_Len;
-  /*
-    If a very large product, the section 4 length field holds
-    the number of bytes in the product after section 4 upto
-    the end of the padding bytes.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  if ( llarge ) bdsLen = bdsLenIn - bdsLen;
+  /* Parameter adjustments */
+  --p;
+  pw_dim1 = ko + 3;
+  pw_offset = pw_dim1;
+  pw -= pw_offset;
 
-  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
+  /* **** ROWINA2 - Interpolation of row of values. */
+  /*     Input Parameters. */
+  /*     ----------------- */
+  /*     P      - Row of values to be interpolated. */
+  /*              Dimension must be at least KO. */
+  /*     KO     - Number of values required. */
+  /*     KI     - Number of values in P on input. */
+  /*     PW     - Working array. */
+  /*              Dimension must be at least (0:KO+2,3). */
+  /*     KCODE  - Interpolation required. */
+  /*              1 , linear. */
+  /*              3 , cubic. */
+  /*     PMSVAL - Value used for missing data indicator. */
 
-  bds_flag = BDS_Flag;
+  /*     Output Parameters. */
+  /*     ------------------ */
+  /*     P     - Now contains KO values. */
+  /*     KRET  - Return code */
+  /*             0, OK */
+  /*             Non-zero, error */
 
-  /* 0------- grid point           */
-  /* 1------- spherical harmonics  */
+  /*     Author. */
+  /*     ------- */
+  /*     J.D.Chambers    ECMWF     22.07.94 */
 
-  lspherc = bds_flag >> 7;
+  /*     ********************************    */
+  /*     Section 1.  Linear interpolation .. */
+  /*     ********************************    */
 
-  if ( lspherc ) isec4[2] = 128;
-  else           isec4[2] = 0;
+  *kret = 0;
 
-  /* -0------  simple packing */
-  /* -1------ complex packing */
+  if ( kcode == 1 )
+    {
+      /*    Move input values to work array */
+      for ( jl = 1; jl <= ki; ++jl )
+	pw[jl + pw_dim1] = p[jl];
 
-  lcomplex = (bds_flag >> 6)&1;
+      /*    Arrange wrap-around value in work array */
+      pw[ki + 1 + pw_dim1] = p[1];
 
-  if ( lcomplex ) isec4[3] = 64;
-  else            isec4[3] =  0;
+      /*    Set up constants to be used to figure out weighting for */
+      /*    values in interpolation. */
+      zrdi = (double) ki;
+      zdo = 1.0 / (double) ko;
 
-  /* ---0---- No additional flags */
-  /* ---1---- No additional flags */
+      /*    Loop through the output points */
+      for ( jl = 1; jl <= ko; ++jl )
+	{
 
-  lcompress = (bds_flag >> 4)&1; /* compress */
+	  /*    Calculate weight from the start of row */
+	  zpos = (jl - 1) * zdo;
+	  zwt = zpos * zrdi;
 
-  if ( lcompress )
-    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
-  else
-    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
+	  /*    Get the current array position(minus 1) from the weight - */
+	  /*    note the implicit truncation. */
+	  ip = (int) zwt;
 
-  /* ----++++ number of unused bits at end of section) */
+	  /*    If the left value is missing, use the right value */
+	  if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
+	    {
+	      p[jl] = pw[ip + 2 + pw_dim1];
+	    }
+	  /*    If the right value is missing, use the left value */
+	  else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
+	    {
+	      p[jl] = pw[ip + 1 + pw_dim1];
+	    }
+	  /*    If neither missing, interpolate ... */
+	  else
+	    {
 
-  bds_ubits = bds_flag & 0xF;
-  
-  /* scale factor (2 bytes) */;
+	      /*       Adjust the weight to range (0.0 to 1.0) */
+	      zwt -= ip;
 
-  jscale = BDS_BinScale;
+	      /*       Interpolate using the weighted values on either side */
+	      /*       of the output point position */
+	      p[jl] = (1.0 - zwt) * pw[ip + 1 + pw_dim1] +
+		zwt * pw[ip + 2 + pw_dim1];
+	    }
+	}
 
-  /* check for missing data indicators. */
+      /*     *******************************    */
+      /*     Section 2.  Cubic interpolation .. */
+      /*     *******************************    */
 
-  iexp  = bds[ 6];
-  imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
+    }
+  else if ( kcode == 3 )
+    {
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
+	{
+          if ( IS_EQUAL(p[jl], msval) )
+	    {
+	      fprintf(stderr," ROWINA2: ");
+	      fprintf(stderr," Cubic interpolation not supported");
+	      fprintf(stderr," for fields containing missing data.\n");
+	      *kret = 1;
+	      goto L900;
+	    }
+          pw[jl + pw_dim1] = p[jl];
+	}
+      pw[pw_dim1] = p[ki];
+      pw[ki + 1 + pw_dim1] = p[1];
+      pw[ki + 2 + pw_dim1] = p[2];
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
+	{
+          pw[jl + (pw_dim1 << 1)] =
+	        - pw[jl - 1 + pw_dim1] / 3.0 -
+	          pw[jl     + pw_dim1] * 0.5 +
+	          pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0;
+          pw[jl + 1 + pw_dim1 * 3] =
+                  pw[jl - 1 + pw_dim1] / 6.0 -
+                  pw[jl     + pw_dim1] +
+                  pw[jl + 1 + pw_dim1] * 0.5 +
+                  pw[jl + 2 + pw_dim1] / 3.0;
+	}
 
-  imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
+      scm0_double(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
+		  &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
 
-  /* convert reference value and scale factor. */
+      zrdi = (double) ki;
+      zdo = 1.0 / (double) ko;
+      for ( jl = 1; jl <= ko; ++jl )
+	{
+          zpos = (jl - 1) * zdo;
+          zwt = zpos * zrdi;
+          ip = (int) zwt + 1;
+          zwt = zwt + 1.0 - ip;
+          zwt1 = 1.0 - zwt;
+          p[jl] = ((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                  zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                  ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                  zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt;
+	}
 
-  if ( ! (dfunc == 'J') && imiss == 0 )
+    }
+  else
     {
-      fmin = (T)BDS_RefValue;
-      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
+      /*    **************************************    */
+      /*    Section 3.  Invalid interpolation code .. */
+      /*    **************************************    */
+      fprintf(stderr," ROWINA2:");
+      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
+      *kret = 2;
     }
 
-  /* get number of bits in each data value. */
+L900:
+    return 0;
+} /* rowina2 */
 
-  ISEC4_NumBits = BDS_NumBits;
 
-  /* octet number of start of packed data */
-  /* calculated from start of block 4 - 1 */
 
-  locnd = zoff + bds_head;
+int qu2reg2(double *pfield, int *kpoint, int klat, int klon,
+	    double *ztemp, double msval, int *kret)
+{
+   /* System generated locals */
+   int i_1, i_2;
+   int kcode = 1;
 
-  /* if data is in spherical harmonic form, distinguish   */
-  /* between simple/complex packing (lcomplex = 0/1)      */
+   /* Local variables */
+   int ilii, ilio, icode;
+   double *zline = NULL;
+   double *zwork = NULL;
+   int iregno, iquano, j210, j220, j230, j240, j225;
 
-  if ( lspherc )
-    {
-      if ( !lcomplex )
-	{
-	  /*    no unpacked binary data present */
 
-	  //jup = kup = mup = 0;
+   zline = (double*) Malloc(2*(size_t)klon*sizeof(double));
+   if ( zline == NULL ) SysError("No Memory!");
 
-	  /*    octet number of start of packed data */
-	  /*    calculated from start of block 4 - 1 */
+   zwork = (double*) Malloc(3*(2*(size_t)klon+3)*sizeof(double));
+   if ( zwork == NULL ) SysError("No Memory!");
 
-	  ioff   = 1;
-	  locnd += 4*ioff;  /* RealCoef */
+   /* Parameter adjustments */
+   --pfield;
+   --kpoint;
 
-	  /*    get real (0,0) coefficient in grib format and     */
-	  /*    convert to floating point.                        */
+/* **** QU2REG - Convert quasi-regular grid data to regular. */
+/*     Input Parameters. */
+/*     ----------------- */
+/*     PFIELD     - Array containing quasi-regular grid */
+/*                  data. */
+/*     KPOINT     - Array containing list of the number of */
+/*                  points on each latitude (or longitude) of */
+/*                  the quasi-regular grid. */
+/*     KLAT       - Number of latitude lines */
+/*     KLON       - Number of longitude lines */
+/*     KCODE      - Interpolation required. */
+/*                  1 , linear - data quasi-regular on */
+/*                               latitude lines. */
+/*                  3 , cubic -  data quasi-regular on */
+/*                               latitude lines. */
+/*                  11, linear - data quasi-regular on */
+/*                               longitude lines. */
+/*                  13, cubic -  data quasi-regular on */
+/*                               longitude lines. */
+/*     PMSVAL     - Value used for missing data indicator. */
+/*     Output Parameters. */
+/*     ------------------ */
+/*     KRET       - return code */
+/*                  0 = OK */
+/*                  non-zero indicates fatal error */
+/*     PFIELD     - Array containing regular grid data. */
+/*     Author. */
+/*     ------- */
+/*     J.D.Chambers     ECMWF      22.07.94 */
+/*     J.D.Chambers     ECMWF      13.09.94 */
+/*     Add return code KRET and remove calls to ABORT. */
 
-	  if ( dfunc != 'J' )
-	    {
-	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = (T)BDS_RealCoef;
-	    }
-	}
-      else /* complex packed spherical harmonics */
-	{
-	  isec4[15] = BDS_PackData;
-	  /*    scaling factor */
-	  isec4[16] = BDS_Power;
 
-	  /*    pentagonal resolution parameters of the */
-	  /*    unpacked section of data field          */
+/* ------------------------------ */
+/* Section 1. Set initial values. */
+/* ------------------------------ */
 
-	  jup = bds[zoff+15];
-	  kup = bds[zoff+16];
-	  mup = bds[zoff+17];
+   *kret = 0;
 
-	  isec4[zoff+17] = jup;
-	  isec4[zoff+18] = kup;
-	  isec4[zoff+19] = mup;
+/* Check input parameters. */
 
-	  /*    unpacked binary data */
+   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
+      fprintf(stderr," QU2REG :");
+      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
+      *kret = 1;
+      goto L900;
+   }
 
-	  locnd += 4; /* 2 + power */
-	  locnd += 3; /* j, k, m   */
-	  ioff   = (jup+1)*(jup+2);
+/* Set array indices to 0. */
 
-	  if ( dfunc != 'J' )
-	    for ( int i = 0; i < ioff; i++ )
-	      {
-		if ( imiss )
-		  *fpdata++ = 0.0;
-		else
-		  {
-		    iexp   = (bds[locnd+4*i  ]);
-		    imant  =((bds[locnd+4*i+1]) << 16) +
-		            ((bds[locnd+4*i+2]) <<  8) +
-		             (bds[locnd+4*i+3]);
+   ilii = 0;
+   ilio = 0;
 
-		    *fpdata++ = (T)decfp2(iexp,imant);
-		  }
-	      }
-	  
-	  locnd += 4*ioff;  /* RealCoef */
-	}
-    }
-  else
-    {
-      if ( lcomplex )
-	{
-	  *iret = 1999;
-	  gprintf(__func__, " Second order packed grids unsupported!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
-    }
+/* Establish values of loop parameters. */
 
-  /* Decode data values to floating point and store in fsec4.  */
-  /* First calculate the number of data values.                */
-  /* Take into account that spherical harmonics can be packed  */
-  /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
+   if (kcode > 10) {
 
-  int jlend = bdsLen - locnd;
+/*    Quasi-regular along longitude lines. */
 
-  if ( ISEC4_NumBits == 0 )
-    {
-      if ( jlend > 1 )
-	{
-	  *iret = 2001;
-	  gprintf(__func__, " Number of bits per data value = 0!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
+      iquano = klon;
+      iregno = klat;
+      icode = kcode - 10;
+   } else {
 
-      if ( numGridVals == 0 )
-	{
-	  *iret = 2002;
-	  gprintf(__func__, " Constant field unsupported for this grid type!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
+/*    Quasi-regular along latitude lines. */
 
-      jlend = numGridVals;
-      jlend -= ioff;
-    }
-  else
-    {
-      jlend = (jlend*8 - bds_ubits) / ISEC4_NumBits;
-    }
+      iquano = klat;
+      iregno = klon;
+      icode = kcode;
+   }
 
-  ISEC4_NumValues        = jlend + ioff;
-  ISEC4_NumNonMissValues = 0;
+/*     -------------------------------------------------------- */
+/**    Section 2. Interpolate field from quasi to regular grid. */
+/*     -------------------------------------------------------- */
 
-  if ( lcompress )
-    {
-      size_t len;
+   i_1 = iquano;
+   for (j230 = 1; j230 <= i_1; ++j230) {
 
-      if ( gribrec_len(bds[14], bds[15], bds[16]) > JP23SET )
-	len = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
-      else
-        len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
+      if (iregno != kpoint[j230]) {
 
-      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
+/*       Line contains less values than required,so */
+/*       extract quasi-regular grid values for a line */
 
-      if ( lspherc )
-	{
-	  if ( lcomplex )
-	    ISEC4_NumValues += ioff;
-	  else
-	    ISEC4_NumValues++;
-	}
-    }
+         i_2 = kpoint[j230];
+         for (j210 = 1; j210 <= i_2; ++j210) {
+            ++ilii;
+            zline[j210 - 1] = pfield[ilii];
+         }
 
-  if ( dfunc == 'J' ) return bdsLen;
+/*       and interpolate this line. */
 
-  /* check length of output array. */
-  
-  if ( ISEC4_NumValues > fsec4len )
-    {
-      *iret = 710;
-      gprintf(__func__, " Output array too small. Length = %d", fsec4len);
-      gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
-      gprintf(__func__, " Return code =  %d", *iret);
-      return 0;
-    }
+         rowina2(zline, iregno, kpoint[j230], zwork, icode, msval, kret);
+         if (*kret != 0) goto L900;
+
+/*       Add regular grid values for this line to the
+         temporary array. */
+
+         i_2 = iregno;
+         for (j220 = 1; j220 <= i_2; ++j220) {
+            ++ilio;
+            ztemp[ilio - 1] = zline[j220 - 1];
+         }
+
+      } else {
+
+/*       Line contains the required number of values, so add */
+/*       this line to the temporary array. */
+
+         i_2 = iregno;
+         for (j225 = 1; j225 <= i_2; ++j225) {
+            ++ilio;
+            ++ilii;
+            ztemp[ilio - 1] = pfield[ilii];
+         }
+      }
+   }
+
+/* Copy temporary array to user array. */
+
+   i_1 = klon * klat;
+   for (j240 = 1; j240 <= i_1; ++j240) {
+      pfield[j240] = ztemp[j240 - 1];
+   }
 
-  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
-  else
-    {
-      igrib += locnd;
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
 
-      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
-    }
+L900:
 
-  if ( lspherc && lcomplex )
-    {
-      int pcStart = isec4[19], pcScale = isec4[16];
-      TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
-      TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
-    }
+   Free(zline);
+   Free(zwork);
 
-  if ( CGRIBEX_Fix_ZSE )  /* Fix ZeroShiftError of simple packed spherical harmonics */
-    if ( lspherc && !lcomplex )
-      {
-        /* 20100705: Fix ZeroShiftError - Edi Kirk */
-	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
-	  {
-	    T zserr = fsec4[1];
-	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
-	  }
-      }
+   return 0;
+} /* qu2reg2 */
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double)-decscale);
-      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
-    }
 
-  return bdsLen;
-}
 
+#ifdef T
+#undef T
+#endif
+#define T double
+#ifdef T
 
-void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
-			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
-			     int kleng, int *kword, int dfunc, int *iret)
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
 {
-  UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gdsIncluded = FALSE;
-  int bmsIncluded = FALSE;
-  int bitmapSize = 0;
-  int imaskSize = 0;
-  int ldebug = FALSE;
-  int llarge = FALSE, l_iorj = FALSE;
-  int lsect2 = FALSE, lsect3 = FALSE;
-  int numGridVals = 0;
-  static int lmissvalinfo = 1;
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
 
-  UNUSED(kleng);
+  /*
+  // Setup the weights
+   */
 
-  *iret = 0;
+  range = (double) (ismax - ismin +1);
 
-  grsdef();
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
 
-  ISEC2_Reduced = FALSE;
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
 
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
+    }
   /*
-    ----------------------------------------------------------------
-    IS Indicator Section (Section 0)
-    ----------------------------------------------------------------
-  */
-  is = (unsigned char *) &kgrib[0];
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
 
-  isLen = decodeIS(is, isec0, iret);
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+    }
 
   /*
-    If count is negative, have to rescale by factor of -120.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  if ( ISEC0_GRIB_Len < 0 )
-    {
-      if ( ldebug )
-	gprintf(__func__, "Special case, negative length multiplied by -120");
-      llarge = TRUE;
-      ISEC0_GRIB_Len *= (-120);
-    }
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
+
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
+
   /*
-    When decoding or calculating length, previous editions
-    of the GRIB code must be taken into account.
+  // Do linear fit to find the slope
+   */
 
-    In the table below, covering sections 0 and 1 of the GRIB
-    code, octet numbering is from the beginning of the GRIB
-    message;
-    * indicates that the value is not available in the code edition;
-    R indicates reserved, should be set to 0;
-    Experimental edition is considered as edition -1.
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
 
-    GRIB code edition -1 has fixed length of 20 octets for
-    section 1, the length not included in the message.
-    GRIB code edition 0 has fixed length of 24 octets for
-    section 1, the length being included in the message.
-    GRIB code edition 1 can have different lengths for section
-    1, the minimum being 28 octets, length being included in
-    the message.
+  /*
+  // Perform a least square fit for the equation
+   */
 
-                                         Octet numbers for code
-                                                  editions
+  for( loop = ismin; loop <= ismax; loop++ ) {
 
-                 Contents.                   -1      0      1
-                 ---------                ----------------------
-       Letters GRIB                          1-4    1-4    1-4
-       Total length of GRIB message.          *      *     5-7
-       GRIB code edition number               *      *      8
-       Length of Section 1.                   *     5-7    9-11
-       Reserved octet (R).                    *      8(R)   *
-       Version no. of Code Table 2.           *      *     12
-       Identification of centre.              5      9     13
-       Generating process.                    6     10     14
-       Grid definition .                      7     11     15
-       Flag (Code Table 1).                   8     12     16
-       Indicator of parameter.                9     13     17
-       Indicator of type of level.           10     14     18
-       Height, pressure etc of levels.      11-12  15-16  19-20
-       Year of century.                      13     17     21
-       Month.                                14     18     22
-       Day.                                  15     19     23
-       Hour.                                 16     20     24
-       Minute.                               17     21     25
-       Indicator of unit of time.            18     22     26
-       P1 - Period of time.                  19     23     27
-       P2 - Period of time                  20(R)   24     28
-       or reserved octet (R).
-       Time range indicator.                21(R)   25     29
-       or reserved octet (R).
-       Number included in average.       22-23(R)  26-27  30-31
-       or reserved octet (R).
-       Number missing from average.         24(R)  28(R)   32
-       or reserved octet (R).
-       Century of data.                       *      *     33
-       Designates sub-centre if not 0.        *      *     34
-       Decimal scale factor.                  *      *    35-36
-       Reserved. Set to 0.                    *      *    37-48
-       (Need not be present)
-       For originating centre use only.       *      *    49-nn
-       (Need not be present)
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
 
-    Identify which GRIB code edition is being decoded.
+  Free(weights);
+  Free(norms);
 
-    In GRIB edition 1, the edition number is in octet 8.
-    In GRIB edition 0, octet 8 is reserved and set to 0.
-    In GRIB edition -1, octet 8 is a flag field and can have a
-    a valid value of 0, 1, 2 or 3.
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
 
-    However, GRIB edition number 0 has a fixed
-    length of 24, included in the message, for section 1, so
-    if the value extracted from octets 5-7 is 24 and that from
-    octet 8 is 0, it is safe to assume edition 0 of the code.
+  return pFactor;
+}
 
-  */
-  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
+void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
+{
+  double power;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
+
+  if ( scale == NULL ) SysError("No Memory!");
+
+  if ( pcScale < -10000 || pcScale > 10000 )
     {
-      /*
-	Set length of GRIB message to missing data value.
-      */
-      ISEC0_GRIB_Len = 0;
-    }
-  /*
-    If Grib Edition 1 and only length is required, go to section 9.
-  */
-  if ( dfunc == 'L' ) goto LABEL900;
+      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
+      return;
+   }
 
-  /*
-    ----------------------------------------------------------------
-    PDS Product Definition Section (Section 1)
-    ----------------------------------------------------------------
-  */ 
-  pds = is + isLen;
+  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
 
-  pdsLen = decodePDS(pds, isec0, isec1);
+  if ( pcScale == 0 ) return;
 
-  /*
-    ----------------------------------------------------------------
-    GDS Grid Description Section (Section 2)
-    ----------------------------------------------------------------
-  */
-  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  power = (double) pcScale / 1000.;
+  scale[0] = 1.0;
 
-  if ( gdsIncluded )
-    {
-      gds = is + isLen + pdsLen;
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
-      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
-    }
+  if ( inv )
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  /* Scale the values */
 
-  isec3[0] = 0;
-  if ( bmsIncluded )
-    {
-      bms = is + isLen + pdsLen + gdsLen;
+  size_t index = 0;
 
-      bmsLen = BMS_Len;
-      imaskSize = (bmsLen - 6)<<3;
-      bitmapSize = imaskSize - BMS_UnusedBits;
-      /*
-      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
-      */
-    }
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  /*
-    ----------------------------------------------------------------
-    BDS Binary Data Section (Section 4)
-    ----------------------------------------------------------------
-  */
-  bds = is + isLen + pdsLen + gdsLen + bmsLen;
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
+      {
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+      }
 
-  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
+  Free(scale);
+}
 
-  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
-				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
 
-  if ( *iret != 0 ) return;
+void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+{
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
+  int  m, n;
+  int  index, inext;
 
-  ISEC4_NumNonMissValues = ISEC4_NumValues;
+  if ( fphelp == NULL ) SysError("No Memory!");
 
-  if ( bitmapSize > 0 )
-    {
-      if ( dfunc != 'L' && dfunc != 'J' )
-	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+  index = inext = 0;
+
+  for ( m = 0;   m <= pcStart; m++ )
+    for ( n = m; n <= trunc; n++ )
+      {
+	if ( pcStart >= n )
 	  {
-	    lmissvalinfo = 0;
-	    FSEC3_MissVal = (T)GRIB_MISSVAL;
-	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	    fphelp[index  ] = fpdata[inext++];
+	    fphelp[index+1] = fpdata[inext++];
 	  }
+	index += 2;
+      }
 
-      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
-      ISEC4_NumValues        = bitmapSize;
-
-      if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
-	{
-	  GRIBPACK bitmap;
-	  /*
-	  unsigned char *bitmap;
-	  bitmap = BMS_Bitmap;
-	  int j = ISEC4_NumNonMissValues;
-	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
-	    {
-	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
-		fsec4[i] = fsec4[--j];
-	      else
-		fsec4[i] = FSEC3_MissVal;
-	    }
-	  */
+  index = 0;
+  for ( m = 0;   m <= trunc; m++ )
+    for ( n = m; n <= trunc; n++ )
+      {
+	if ( n > pcStart )
+	  {
+	    fphelp[index  ] = fpdata[inext++];
+	    fphelp[index+1] = fpdata[inext++];
+	  }
+	index += 2;
+      }
 
-	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
+  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-#if defined (VECTORCODE)
-	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  GRIBPACK *pbitmap = imask;
-#else
-	  GRIBPACK *pbitmap = BMS_Bitmap;
-#endif
+  Free(fphelp);
+}
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-	  for ( int i = imaskSize/8-1; i >= 0; i-- )
-	    {
-	      bitmap = pbitmap[i];
-	      imask[i*8+0] = 1 & (bitmap >> 7);
-	      imask[i*8+1] = 1 & (bitmap >> 6);
-	      imask[i*8+2] = 1 & (bitmap >> 5);
-	      imask[i*8+3] = 1 & (bitmap >> 4);
-	      imask[i*8+4] = 1 & (bitmap >> 3);
-	      imask[i*8+5] = 1 & (bitmap >> 2);
-	      imask[i*8+6] = 1 & (bitmap >> 1);
-	      imask[i*8+7] = 1 & (bitmap);
-	    }
 
-	  int j = 0;
-	  for ( int i = 0; i < ISEC4_NumValues; i++ )
-	    if ( imask[i] ) j++;
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
+{
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-	  if ( ISEC4_NumNonMissValues != j )
-	    {
-	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
-		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
-			j, ISEC4_NumNonMissValues);
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
+      {
+	if ( pcStart >= n )
+	  {
+	    fphelp[inext++] = fpdata[index];
+	    fphelp[inext++] = fpdata[index+1];
+	  }
+	index += 2;
+      }
 
-	      ISEC4_NumNonMissValues = j;
-	    }
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
+      {
+	if ( n > pcStart )
+	  {
+	    fphelp[inext++] = fpdata[index];
+	    fphelp[inext++] = fpdata[index+1];
+	  }
+	index += 2;
+      }
 
-	  if ( dfunc != 'J' )
-	    {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
-		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
-	    }
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-	  Free(imask);
-	}
-    }
+  Free(fphelp);
+}
 
-  if ( ISEC2_Reduced )
-    {
-      int nvalues = 0;
-      int nlat = ISEC2_NumLat;
-      int nlon = ISEC2_RowLonPtr[0];
-      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( int ilat = 1; ilat < nlat; ++ilat )
-	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
 
-      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
-      // if ( dlon < 0 ) dlon += 360000;
-	  
-      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
+{
+  /* System generated locals */
+  double r_1;
 
-      //printf("nlat %d  nlon %d \n", nlat, nlon);
-      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
+  /* Local variables */
+  int jl;
+  double zfac, zeps, zbeta;
+  double zalpha;
 
-      if ( dfunc == 'R' && *iret == -801 )
-	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
-		ISEC4_NumValues, nvalues);
-      
-      if ( dfunc == 'R' && *iret != -801 )
-	{
-	  ISEC2_Reduced = 0;
-	  ISEC2_NumLon = nlon;
-	  ISEC4_NumValues = nlon*nlat;
+  /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
+  /* output: */
+  /*   pdl   = the limited derivative at the left edge of the interval */
+  /*   pdr   = the limited derivative at the right edge of the interval */
+  /* inputs */
+  /*   pdl   = the original derivative at the left edge */
+  /*   pdr   = the original derivative at the right edge */
+  /*   pfl   = function value at the left edge of the interval */
+  /*   pfr   = function value at the right edge of the interval */
+  /*   klg   = number of intervals where the derivatives are limited */
 
-	  lsect3 = bitmapSize > 0;
-          int lperio = 1;
-	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
-                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
-                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
-                       (ISEC1_Parameter == 43));
-	
-	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
-	      
-	  if ( bitmapSize > 0 )
-	    {
-	      int j = 0;	      
-	      for ( int i = 0; i < ISEC4_NumValues; i++ )
-		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
-		  
-	      ISEC4_NumNonMissValues = j;
-	    }
-	}
-    }
+  /*  define constants */
 
+  zeps = 1.0e-12;
+  zfac = (1.0 - zeps) * 3.0;
 
-  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
-  esLen = 4;
+  for ( jl = 0; jl < klg; ++jl )
+    {
+      if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
+	{
+	  zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
+	  zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
+	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
+	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
+	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
+	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
+	}
+      else
+	{
+	  pdl[jl] = 0.0;
+	  pdr[jl] = 0.0;
+	}
+    }
+} /* scm0 */
 
-  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+static
+int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
+			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
+{
+  /*
+C---->
+C**** ROWINA3 - Interpolation of row of values.
+C
+C     Purpose.
+C     --------
+C
+C     Interpolate a row of values.
+C
+C
+C**   Interface.
+C     ----------
+C
+C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
+C
+C
+C     Input Parameters.
+C     -----------------
+C
+C     P      - Row of values to be interpolated.
+C              Dimension must be at least KO.
+C
+C     KO     - Number of values required.
+C
+C     KI     - Number of values in P on input.
+C
+C     PW     - Working array.
+C              Dimension must be at least (0:KO+2,3).
+C
+C     KCODE  - Interpolation required.
+C              1 , linear.
+C              3 , cubic.
+C
+C     PMSVAL - Value used for missing data indicator.
+C
+C     OMISNG - True if missing values are present in field.
+C
+C     OPERIO - True if input field is periodic.
+C
+C     OVEGGY - True if 'nearest neighbour' processing must be used
+C              for interpolation
+C
+C     Output Parameters.
+C     ------------------
+C
+C     P     - Now contains KO values.
+C     KRET  - Return code
+C             0, OK
+C             Non-zero, error
+C
+C
+C     Method.
+C     -------
+C
+C     Linear or cubic interpolation performed as required.
+C
+C     Comments.
+C     ---------
+C
+C     This is a version of ROWINA which allows for missing data
+C     values and hence for bitmapped fields.
+C
+C
+C     Author.
+C     -------
+C
+C     J.D.Chambers    ECMWF     22.07.94
+C
+C
+C     Modifications.
+C     --------------
+C
+C     J.D.Chambers    ECMWF     13.09.94
+C     Add return code KRET and remove calls to ABORT.
+C
+C     J. Clochard, Meteo France, for ECMWF - January 1998.
+C     Addition of OMISNG and OPERIO arguments.
+C
+C
+C     -----------------------------------------------------------------
+*/
+  /* System generated locals */
+  int pw_dim1, pw_offset, i_1;
 
-  if ( ISEC0_GRIB_Len )
-    if ( ISEC0_GRIB_Len < gribLen )
-      Warning("Length of GRIB message is inconsistent (grib_message_size=7867 < grib_record_size=9718)!", ISEC0_GRIB_Len, gribLen);
+  /* Local variables */
+  int jl, ip;
+  double zwt1, zrdi, zpos;
+  double zdo, zwt;
 
-  ISEC0_GRIB_Len = gribLen;
+  UNUSED(omisng);
 
-  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
+  /* Parameter adjustments */
+  --p;
+  pw_dim1 = ko + 3;
+  pw_offset = pw_dim1;
+  pw -= pw_offset;
 
-  /*
-    ----------------------------------------------------------------
-    Section 9 . Abort/return to calling routine.
-    ----------------------------------------------------------------
-  */
- LABEL900:;
+  *kret = 0;
 
-  if ( ldebug )
+  if ( kcode == 1 )
     {
-      gprintf(__func__, "Section 9.");
-      gprintf(__func__, "Output values set -");
-
-      gribPrintSec0(isec0);
-      gribPrintSec1(isec0, isec1);
-      /*
-	Print section 2 if present.
-      */
-      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
+      /*    Move input values to work array */
+      for ( jl = 1; jl <= ki; ++jl )
+	pw[jl + pw_dim1] = p[jl];
 
-      if ( ! l_iorj )
+      if ( operio )
 	{
-	  /*
-	    Print section 3 if present.
-	  */
-	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+	  /* Arrange wrap-around value in work array */
+	  pw[ki + 1 + pw_dim1] = p[1];
 
-	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
-	  /*
-	    Special print for 2D spectra wave field real values in
-	    section 4
-	  */
-	  if ( (isec1[ 0] ==  140) && 
-	       (isec1[ 1] ==   98) && 
-	       (isec1[23] ==    1) && 
-	       ((isec1[39] == 1045) || (isec1[39] == 1081))  && 
-	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
-	    gribPrintSec4Wave(isec4);
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) ki;
+	  zdo = 1.0 / (double) ko;
 	}
-    }
-}
-
-#endif /* T */
-
-/*
- * Local Variables:
- * mode: c
- * End:
- */
-
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
-
-static 
-int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
-{
-  /* int imisng = 0; */
-  int  ReducedGrid = FALSE, VertCoorTab = FALSE;
-#if defined (VECTORCODE)
-  unsigned char *igrib;
-  GRIBPACK *lgrib = NULL;
-  size_t lGribLen = 0;
-#endif
+      else
+	{
+	  /* Repeat last value, to cope with "implicit truncation" below */
+	  pw[ki + 1 + pw_dim1] = p[ki];
 
-  *numGridVals = 0;
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) (ki-1);
+	  zdo = 1.0 / (double) (ko-1);
+ 	}
 
-  memset(isec2, 0, 22*sizeof(int));
+      /*    Loop through the output points */
+      for ( jl = 1; jl <= ko; ++jl )
+	{
 
-  int gdsLen = GDS_Len;
+	  /* Calculate weight from the start of row */
+	  zpos = (jl - 1) * zdo;
+	  zwt = zpos * zrdi;
 
-  int ipvpl = GDS_PVPL;
-  if ( ipvpl == 0 ) ipvpl = 0xFF;
+	  /* Get the current array position(minus 1) from the weight - */
+	  /* note the implicit truncation. */
+	  ip = (int) zwt;
+		  
+	  /* Adjust the weight to range (0.0 to 1.0) */
+	  zwt -= ip;
 
-  if ( ipvpl != 0xFF )
-    { /* Either vct or reduced grid */
-      if ( GDS_NV != 0 )
-	{ /* we have vct */
-	  VertCoorTab = TRUE;
-	  int ipl =  4*GDS_NV + ipvpl - 1;
-	  if ( ipl < gdsLen )
+          /* If 'nearest neighbour' processing must be used */
+	  if ( oveggy )
 	    {
-	      ReducedGrid = TRUE;
+              if ( zwt < 0.5 )
+                p[jl] = pw[ip + 1 + pw_dim1];
+	      else
+		p[jl] = pw[ip + 2 + pw_dim1];
+	    }
+	  else
+	    {
+	      /*    If the left value is missing, use the right value */
+	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
+		{
+		  p[jl] = pw[ip + 2 + pw_dim1];
+		}
+	      /*    If the right value is missing, use the left value */
+	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
+		{
+		  p[jl] = pw[ip + 1 + pw_dim1];
+		}
+	      /*    If neither missing, interpolate ... */
+	      else
+		{
+		  /*  Interpolate using the weighted values on either side */
+		  /*  of the output point position */
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
+		}
 	    }
 	}
-      else
-	{
-	  VertCoorTab = FALSE;
-	  ReducedGrid = TRUE;
-	}
-      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
-    }
- 
-  if ( ISEC0_GRIB_Version == 0 )
-    {
-      VertCoorTab = (gdsLen - 32) > 0;
     }
-  
-  if ( ReducedGrid )
+  else if ( kcode == 3 )
     {
-      int locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
-      int jlenl = (gdsLen - locnl)  >> 1;
-      if ( jlenl == GDS_NumLat )
+      /*     *******************************    */
+      /*     Section 2.  Cubic interpolation .. */
+      /*     *******************************    */
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
 	{
-	  *numGridVals = 0;
-	  ISEC2_Reduced = TRUE;
-	  for ( int i = 0; i < jlenl; i++ )
+          if ( IS_EQUAL(p[jl], msval) )
 	    {
-	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
-	      *numGridVals += ISEC2_RowLon(i);
+	      fprintf(stderr," ROWINA3: ");
+	      fprintf(stderr," Cubic interpolation not supported");
+	      fprintf(stderr," for fields containing missing data.\n");
+	      *kret = 1;
+	      goto L900;
 	    }
+          pw[jl + pw_dim1] = p[jl];
 	}
-      else
+      pw[pw_dim1] = p[ki];
+      pw[ki + 1 + pw_dim1] = p[1];
+      pw[ki + 2 + pw_dim1] = p[2];
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
 	{
-	  ReducedGrid = FALSE;
+          pw[jl + (pw_dim1 << 1)] =
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
+          pw[jl + 1 + pw_dim1 * 3] =
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
-    }
 
-  ISEC2_GridType = GDS_GridType;
+      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
+		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
 
-  /*
-     Gaussian grid definition.
-  */
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
-       ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
-       ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-    {
-      ISEC2_NumLat    = GDS_NumLat;
-      if ( ! ReducedGrid )
+      zrdi = (double) ki;
+      zdo = 1.0 / (double) ko;
+      for ( jl = 1; jl <= ko; ++jl )
 	{
-	  ISEC2_NumLon = GDS_NumLon;
-	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+          zpos = (jl - 1) * zdo;
+          zwt = zpos * zrdi;
+          ip = (int) zwt + 1;
+          zwt = zwt + 1.0 - ip;
+          zwt1 = 1.0 - zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
 	}
-      ISEC2_FirstLat  = GDS_FirstLat;
-      ISEC2_FirstLon  = GDS_FirstLon;
-      ISEC2_ResFlag   = GDS_ResFlag;
-      ISEC2_LastLat   = GDS_LastLat;
-      ISEC2_LastLon   = GDS_LastLon;
-      ISEC2_LonIncr   = GDS_LonIncr;
 
-      ISEC2_NumPar    = GDS_NumPar;
-      ISEC2_ScanFlag  = GDS_ScanFlag;
-      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-	{
-	  ISEC2_LatSP     = GDS_LatSP;
-	  ISEC2_LonSP     = GDS_LonSP;
-	  FSEC2_RotAngle  = (T)GDS_RotAngle;
-	}
-      /*
-	if ( Lons != Longitudes || Lats != Latitudes )
-	Error("Latitude/Longitude Conflict");
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
-    {
-      /*
-      iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
-    {
-      /*
-      iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
-    {
-      ISEC2_NumLon    = GDS_NumLon;
-      ISEC2_NumLat    = GDS_NumLat;
-      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
-      ISEC2_FirstLat  = GDS_FirstLat;
-      ISEC2_FirstLon  = GDS_FirstLon;
-      ISEC2_ResFlag   = GDS_ResFlag;
-      ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
-      ISEC2_Lambert_dx    = GDS_Lambert_dx;
-      ISEC2_Lambert_dy    = GDS_Lambert_dy;
-      ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
-      ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
-      ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
-      ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
-      ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
-      ISEC2_ScanFlag      = GDS_ScanFlag;
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
-    {
-      ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
-      ISEC2_PentaK  = GDS_PentaK;
-      ISEC2_PentaM  = GDS_PentaM;
-      ISEC2_RepType = GDS_RepType;
-      ISEC2_RepMode = GDS_RepMode;
-      *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
-      isec2[ 6] = 0;
-      isec2[ 7] = 0;
-      isec2[ 8] = 0;
-      isec2[ 9] = 0;
-      isec2[10] = 0;
-      /*
-      iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
-      */
-    }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
-    {
-      ISEC2_GME_NI2    = GDS_GME_NI2;
-      ISEC2_GME_NI3    = GDS_GME_NI3;
-      ISEC2_GME_ND     = GDS_GME_ND;
-      ISEC2_GME_NI     = GDS_GME_NI;
-      ISEC2_GME_AFlag  = GDS_GME_AFlag;
-      ISEC2_GME_LatPP  = GDS_GME_LatPP;
-      ISEC2_GME_LonPP  = GDS_GME_LonPP;
-      ISEC2_GME_LonMPL = GDS_GME_LonMPL;
-      ISEC2_GME_BFlag  = GDS_GME_BFlag;
-      *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
-      /*
-      iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
-      */
     }
   else
     {
-      ISEC2_NumLon = GDS_NumLon;
-      ISEC2_NumLat = GDS_NumLat;
-      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
-      Message("Gridtype %d unsupported", ISEC2_GridType);
+      /*    **************************************    */
+      /*    Section 3.  Invalid interpolation code .. */
+      /*    **************************************    */
+      fprintf(stderr," ROWINA3:");
+      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
+      *kret = 2;
     }
 
-  /*    vertical coordinate parameters for hybrid levels.     */
-  /*    get number of vertical coordinate parameters, if any. */
-
-  ISEC2_NumVCP = 0;
-
-  isec2[17] = 0;
-  isec2[18] = 0;
-
-  if ( VertCoorTab == TRUE )
-    {
-      int locnv;
-      if ( ISEC0_GRIB_Version  == 0 )
-	{
-	  locnv = 32;
-	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
-	}
-      else
-	{
-	  locnv = GDS_PVPL - 1;
-	  ISEC2_NumVCP = GDS_NV;
-	}
-#if defined (SX)
-      lGribLen = 4*ISEC2_NumVCP;	      
-      lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
+L900:
+    return 0;
+} /* rowina3 */
 
-      igrib = &gds[locnv];
-      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  int iexp   = (lgrib[4*i  ]);
-	  int imant  =(((lgrib[4*i+1]) << 16) +
-                       ((lgrib[4*i+2]) <<  8) +
-                       ( lgrib[4*i+3]));
-	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
-	}
 
-      Free(lgrib);
-#else
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  int iexp   = (gds[locnv+4*i  ]);
-	  int imant  =(((gds[locnv+4*i+1]) << 16) +
-                       ((gds[locnv+4*i+2]) <<  8) +
-                       ( gds[locnv+4*i+3]));
-	  fsec2[10+i] = (T)decfp2(iexp,imant);
-	}
-#endif
-    }
+int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
+			T msval, int *kret, int omisng, int operio, int oveggy)
+{
+  /*
+C**** QU2REG3 - Convert quasi-regular grid data to regular.
+C
+C     Purpose.
+C     --------
+C
+C     Convert quasi-regular grid data to regular,
+C     using either a linear or cubic interpolation.
+C
+C
+C**   Interface.
+C     ----------
+C
+C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
+C    X            OVEGGY)
+C
+C
+C     Input Parameters.
+C     -----------------
+C
+C     PFIELD     - Array containing quasi-regular grid data.
+C
+C     KPOINT     - Array containing list of the number of
+C                  points on each latitude (or longitude) of
+C                  the quasi-regular grid.
+C
+C     KLAT       - Number of latitude lines
+C
+C     KLON       - Number of longitude lines
+C
+C     KCODE      - Interpolation required.
+C                  1 , linear - data quasi-regular on latitude lines.
+C                  3 , cubic -  data quasi-regular on latitude lines.
+C                  11, linear - data quasi-regular on longitude lines.
+C                  13, cubic -  data quasi-regular on longitude lines.
+C
+C     PMSVAL     - Value used for missing data indicator.
+C
+C     OMISNG     - True if missing values are present in field.
+C
+C     OPERIO     - True if input field is periodic.
+C
+C     OVEGGY     - True if 'nearest neighbour' processing must be used
+C                  for interpolation
+C
+C
+C     Output Parameters.
+C     ------------------
+C
+C     KRET       - return code
+C                  0 = OK
+C                  non-zero indicates fatal error
+C
+C
+C     Output Parameters.
+C     ------------------
+C
+C     PFIELD     - Array containing regular grid data.
+C
+C
+C     Method.
+C     -------
+C
+C     Data is interpolated and expanded into a temporary array,
+C     which is then copied back into the user's array.
+C     Returns an error code if an invalid interpolation is requested
+C     or field size exceeds array dimensions.
+C
+C     Comments.
+C     ---------
+C
+C     This routine is an adaptation of QU2REG to allow missing data
+C     values, and hence bit mapped fields.
+C
+C
+C     Author.
+C     -------
+C
+C     J.D.Chambers     ECMWF      22.07.94
+C
+C
+C     Modifications.
+C     --------------
+C
+C     J.D.Chambers     ECMWF      13.09.94
+C     Add return code KRET and remove calls to ABORT.
+C
+C     J.D.Chambers     ECMWF        Feb 1997
+C     Allow for 64-bit pointers
+C
+C     J. Clochard, Meteo France, for ECMWF - January 1998.
+C     Addition of OMISNG and OPERIO arguments.
+C     Fix message for longitude number out of bounds, and routine
+C     name in title and formats.
+C
+*/
+   /* System generated locals */
+   int i_1, i_2;
+   int kcode = 1;
 
-  return gdsLen;
-}
+   /* Local variables */
+   int ilii, ilio, icode;
+   int iregno, iquano, j210, j220, j230, j240, j225;
+   T *ztemp = NULL;
+   T *zline = NULL;
+   T *zwork = NULL;
 
-#define ldexp_double ldexp
-#define ldexp_float ldexpf
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-static
-int TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
-			  T *fsec4, int fsec4len, int dfunc, int bdsLenIn, int numGridVals, int llarge, int *iret)
-{
-  unsigned char *igrib;
-  int lspherc = FALSE, lcomplex = FALSE;
-  int lcompress;
-  int jup, kup, mup;
-  int locnd;
-  int bds_flag, jscale, imiss;
-  int bds_ubits;
-  int ioff = 0;
-  int iexp, imant;
-  int zoff;
-  int bds_head = 11;
-  T zscale = 0.;
-  T fmin = 0.;
-  T *fpdata = fsec4;
-  int bdsLen;
-  extern int CGRIBEX_Fix_ZSE;
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-  *iret = 0;
-  igrib = bds;
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
-  memset(isec4, 0, 42*sizeof(int));
+   /* Parameter adjustments */
+   --pfield;
+   --kpoint;
 
-  /* get length of binary data block. */
+/* ------------------------------ */
+/* Section 1. Set initial values. */
+/* ------------------------------ */
 
-  bdsLen = BDS_Len;
-  /*
-    If a very large product, the section 4 length field holds
-    the number of bytes in the product after section 4 upto
-    the end of the padding bytes.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  if ( llarge ) bdsLen = bdsLenIn - bdsLen;
+   *kret = 0;
 
-  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
+/* Check input parameters. */
 
-  bds_flag = BDS_Flag;
+   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
+      fprintf(stderr," QU2REG :");
+      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
+      *kret = 1;
+      goto L900;
+   }
 
-  /* 0------- grid point           */
-  /* 1------- spherical harmonics  */
+/* Set array indices to 0. */
 
-  lspherc = bds_flag >> 7;
+   ilii = 0;
+   ilio = 0;
 
-  if ( lspherc ) isec4[2] = 128;
-  else           isec4[2] = 0;
+/* Establish values of loop parameters. */
 
-  /* -0------  simple packing */
-  /* -1------ complex packing */
+   if (kcode > 10) {
 
-  lcomplex = (bds_flag >> 6)&1;
+/*    Quasi-regular along longitude lines. */
 
-  if ( lcomplex ) isec4[3] = 64;
-  else            isec4[3] =  0;
+      iquano = klon;
+      iregno = klat;
+      icode = kcode - 10;
+   } else {
 
-  /* ---0---- No additional flags */
-  /* ---1---- No additional flags */
+/*    Quasi-regular along latitude lines. */
 
-  lcompress = (bds_flag >> 4)&1; /* compress */
+      iquano = klat;
+      iregno = klon;
+      icode = kcode;
+   }
 
-  if ( lcompress )
-    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
-  else
-    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
+/*     -------------------------------------------------------- */
+/**    Section 2. Interpolate field from quasi to regular grid. */
+/*     -------------------------------------------------------- */
 
-  /* ----++++ number of unused bits at end of section) */
+   i_1 = iquano;
+   for (j230 = 1; j230 <= i_1; ++j230) {
 
-  bds_ubits = bds_flag & 0xF;
-  
-  /* scale factor (2 bytes) */;
+      if (iregno != kpoint[j230]) {
 
-  jscale = BDS_BinScale;
+/*       Line contains less values than required,so */
+/*       extract quasi-regular grid values for a line */
 
-  /* check for missing data indicators. */
+         i_2 = kpoint[j230];
+         for (j210 = 1; j210 <= i_2; ++j210) {
+            ++ilii;
+            zline[j210 - 1] = pfield[ilii];
+         }
 
-  iexp  = bds[ 6];
-  imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
+/*       and interpolate this line. */
 
-  imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
+         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
+         if (*kret != 0) goto L900;
 
-  /* convert reference value and scale factor. */
+/*       Add regular grid values for this line to the
+         temporary array. */
 
-  if ( ! (dfunc == 'J') && imiss == 0 )
-    {
-      fmin = (T)BDS_RefValue;
-      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
-    }
+         i_2 = iregno;
+         for (j220 = 1; j220 <= i_2; ++j220) {
+            ++ilio;
+            ztemp[ilio - 1] = zline[j220 - 1];
+         }
 
-  /* get number of bits in each data value. */
+      } else {
 
-  ISEC4_NumBits = BDS_NumBits;
+/*       Line contains the required number of values, so add */
+/*       this line to the temporary array. */
 
-  /* octet number of start of packed data */
-  /* calculated from start of block 4 - 1 */
+         i_2 = iregno;
+         for (j225 = 1; j225 <= i_2; ++j225) {
+            ++ilio;
+            ++ilii;
+            ztemp[ilio - 1] = pfield[ilii];
+         }
+      }
+   }
 
-  locnd = zoff + bds_head;
+/* Copy temporary array to user array. */
 
-  /* if data is in spherical harmonic form, distinguish   */
-  /* between simple/complex packing (lcomplex = 0/1)      */
+   i_1 = klon * klat;
+   for (j240 = 1; j240 <= i_1; ++j240) {
+      pfield[j240] = ztemp[j240 - 1];
+   }
 
-  if ( lspherc )
-    {
-      if ( !lcomplex )
-	{
-	  /*    no unpacked binary data present */
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
 
-	  //jup = kup = mup = 0;
+L900:
 
-	  /*    octet number of start of packed data */
-	  /*    calculated from start of block 4 - 1 */
+   Free(zwork);
+   Free(zline);
+   Free(ztemp);
 
-	  ioff   = 1;
-	  locnd += 4*ioff;  /* RealCoef */
+   return 0;
+} /* qu2reg3 */
 
-	  /*    get real (0,0) coefficient in grib format and     */
-	  /*    convert to floating point.                        */
+#endif /* T */
 
-	  if ( dfunc != 'J' )
-	    {
-	      if ( imiss ) *fpdata++ = 0.0;
-	      else         *fpdata++ = (T)BDS_RealCoef;
-	    }
-	}
-      else /* complex packed spherical harmonics */
-	{
-	  isec4[15] = BDS_PackData;
-	  /*    scaling factor */
-	  isec4[16] = BDS_Power;
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-	  /*    pentagonal resolution parameters of the */
-	  /*    unpacked section of data field          */
+#ifdef T
+#undef T
+#endif
+#define T float
+#ifdef T
 
-	  jup = bds[zoff+15];
-	  kup = bds[zoff+16];
-	  mup = bds[zoff+17];
+/* calculate_pfactor: source code from grib_api-1.8.0 */
+double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+{
+  /*long n_vals = ((fieldTruncation+1)*(fieldTruncation+2));*/
+  long loop, index, m, n = 0;
+  double pFactor, zeps = 1.0e-15;
+  long ismin = (subsetTruncation+1), ismax = (fieldTruncation+1);
+  double* weights, range, * norms;
+  double weightedSumOverX = 0.0, weightedSumOverY = 0.0, sumOfWeights = 0.0, x, y;
+  double numerator = 0.0, denominator = 0.0, slope;
 
-	  isec4[zoff+17] = jup;
-	  isec4[zoff+18] = kup;
-	  isec4[zoff+19] = mup;
+  /*
+  // Setup the weights
+   */
 
-	  /*    unpacked binary data */
+  range = (double) (ismax - ismin +1);
 
-	  locnd += 4; /* 2 + power */
-	  locnd += 3; /* j, k, m   */
-	  ioff   = (jup+1)*(jup+2);
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
+  /*
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
 
-	  if ( dfunc != 'J' )
-	    for ( int i = 0; i < ioff; i++ )
-	      {
-		if ( imiss )
-		  *fpdata++ = 0.0;
-		else
-		  {
-		    iexp   = (bds[locnd+4*i  ]);
-		    imant  =((bds[locnd+4*i+1]) << 16) +
-		            ((bds[locnd+4*i+2]) <<  8) +
-		             (bds[locnd+4*i+3]);
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
 
-		    *fpdata++ = (T)decfp2(iexp,imant);
-		  }
-	      }
-	  
-	  locnd += 4*ioff;  /* RealCoef */
-	}
-    }
-  else
-    {
-      if ( lcomplex )
-	{
-	  *iret = 1999;
-	  gprintf(__func__, " Second order packed grids unsupported!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
+  index = -2;
+  for( m = 0; m < subsetTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      index += 2;
+      if( n >= subsetTruncation ) {
+        double tval = spectralField[index];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+        tval = spectralField[index+1];
+        tval=tval<0?-tval:tval;
+        norms[n] = norms[n] > tval ? norms[n] : tval;
+      }
     }
+  /*
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
 
-  /* Decode data values to floating point and store in fsec4.  */
-  /* First calculate the number of data values.                */
-  /* Take into account that spherical harmonics can be packed  */
-  /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
-
-  int jlend = bdsLen - locnd;
-
-  if ( ISEC4_NumBits == 0 )
-    {
-      if ( jlend > 1 )
-	{
-	  *iret = 2001;
-	  gprintf(__func__, " Number of bits per data value = 0!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
-
-      if ( numGridVals == 0 )
-	{
-	  *iret = 2002;
-	  gprintf(__func__, " Constant field unsupported for this grid type!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
-
-      jlend = numGridVals;
-      jlend -= ioff;
-    }
-  else
-    {
-      jlend = (jlend*8 - bds_ubits) / ISEC4_NumBits;
+  for( m = subsetTruncation; m <= fieldTruncation; m++ )
+    for( n = m; n <= fieldTruncation; n++ ) {
+      double tval = spectralField[index];
+      index += 2;
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
+      tval = spectralField[index+1];
+      tval=tval<0?-tval:tval;
+      norms[n] = norms[n] > tval ? norms[n] : tval;
     }
 
-  ISEC4_NumValues        = jlend + ioff;
-  ISEC4_NumNonMissValues = 0;
-
-  if ( lcompress )
-    {
-      size_t len;
-
-      if ( gribrec_len(bds[14], bds[15], bds[16]) > JP23SET )
-	len = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
-      else
-        len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
-
-      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
 
-      if ( lspherc )
-	{
-	  if ( lcomplex )
-	    ISEC4_NumValues += ioff;
-	  else
-	    ISEC4_NumValues++;
-	}
-    }
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    norms[n] = norms[n] > zeps ? norms[n] : zeps;
+    if( IS_EQUAL(norms[n], zeps) ) weights[n] = 100.0 * zeps;
+  }
 
-  if ( dfunc == 'J' ) return bdsLen;
+  /*
+  // Do linear fit to find the slope
+   */
 
-  /* check length of output array. */
-  
-  if ( ISEC4_NumValues > fsec4len )
-    {
-      *iret = 710;
-      gprintf(__func__, " Output array too small. Length = %d", fsec4len);
-      gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
-      gprintf(__func__, " Return code =  %d", *iret);
-      return 0;
-    }
+  for( loop = ismin; loop <= ismax; loop++ ) {
+    x = log( (double) (loop*(loop+1)) );
+    y = log( norms[loop] );
+    weightedSumOverX = weightedSumOverX + x * weights[loop];
+    weightedSumOverY = weightedSumOverY + y * weights[loop];
+    sumOfWeights = sumOfWeights + weights[loop];
+  }
+  weightedSumOverX = weightedSumOverX / sumOfWeights;
+  weightedSumOverY = weightedSumOverY / sumOfWeights;
 
-  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
-  else
-    {
-      igrib += locnd;
+  /*
+  // Perform a least square fit for the equation
+   */
 
-      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
-    }
+  for( loop = ismin; loop <= ismax; loop++ ) {
 
-  if ( lspherc && lcomplex )
-    {
-      int pcStart = isec4[19], pcScale = isec4[16];
-      TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
-      TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
-    }
+    x = log( (double)(loop*(loop+1)) );
+    y = log( norms[loop] );
+    numerator =
+      numerator + weights[loop] * (y-weightedSumOverY) * (x-weightedSumOverX);
+    denominator =
+      denominator + weights[loop] * ((x-weightedSumOverX) * (x-weightedSumOverX));
+  }
+  slope = numerator / denominator;
 
-  if ( CGRIBEX_Fix_ZSE )  /* Fix ZeroShiftError of simple packed spherical harmonics */
-    if ( lspherc && !lcomplex )
-      {
-        /* 20100705: Fix ZeroShiftError - Edi Kirk */
-	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
-	  {
-	    T zserr = fsec4[1];
-	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
-	  }
-      }
+  Free(weights);
+  Free(norms);
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double)-decscale);
-      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
-    }
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
 
-  return bdsLen;
+  return pFactor;
 }
 
-
-void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
-			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
-			     int kleng, int *kword, int dfunc, int *iret)
+void TEMPLATE(scale_complex,T)(T *fpdata, int pcStart, int pcScale, int trunc, int inv)
 {
-  UCHAR *is = NULL, *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  int isLen = 0, pdsLen = 0, gdsLen = 0, bmsLen = 0, bdsLen = 0, esLen = 0;
-  int gdsIncluded = FALSE;
-  int bmsIncluded = FALSE;
-  int bitmapSize = 0;
-  int imaskSize = 0;
-  int ldebug = FALSE;
-  int llarge = FALSE, l_iorj = FALSE;
-  int lsect2 = FALSE, lsect3 = FALSE;
-  int numGridVals = 0;
-  static int lmissvalinfo = 1;
-
-  UNUSED(kleng);
-
-  *iret = 0;
-
-  grsdef();
-
-  ISEC2_Reduced = FALSE;
-
-  /*
-    ----------------------------------------------------------------
-    IS Indicator Section (Section 0)
-    ----------------------------------------------------------------
-  */
-  is = (unsigned char *) &kgrib[0];
+  double power;
+  double *scale = (double*) Malloc(((size_t)trunc+1)*sizeof(double));
 
-  isLen = decodeIS(is, isec0, iret);
+  if ( scale == NULL ) SysError("No Memory!");
 
-  /*
-    If count is negative, have to rescale by factor of -120.
-    This is a fixup to get round the restriction on product lengths
-    due to the count being only 24 bits. It is only possible because
-    the (default) rounding for GRIB products is 120 bytes.
-  */
-  if ( ISEC0_GRIB_Len < 0 )
+  if ( pcScale < -10000 || pcScale > 10000 )
     {
-      if ( ldebug )
-	gprintf(__func__, "Special case, negative length multiplied by -120");
-      llarge = TRUE;
-      ISEC0_GRIB_Len *= (-120);
-    }
-  /*
-    When decoding or calculating length, previous editions
-    of the GRIB code must be taken into account.
-
-    In the table below, covering sections 0 and 1 of the GRIB
-    code, octet numbering is from the beginning of the GRIB
-    message;
-    * indicates that the value is not available in the code edition;
-    R indicates reserved, should be set to 0;
-    Experimental edition is considered as edition -1.
-
-    GRIB code edition -1 has fixed length of 20 octets for
-    section 1, the length not included in the message.
-    GRIB code edition 0 has fixed length of 24 octets for
-    section 1, the length being included in the message.
-    GRIB code edition 1 can have different lengths for section
-    1, the minimum being 28 octets, length being included in
-    the message.
-
-                                         Octet numbers for code
-                                                  editions
-
-                 Contents.                   -1      0      1
-                 ---------                ----------------------
-       Letters GRIB                          1-4    1-4    1-4
-       Total length of GRIB message.          *      *     5-7
-       GRIB code edition number               *      *      8
-       Length of Section 1.                   *     5-7    9-11
-       Reserved octet (R).                    *      8(R)   *
-       Version no. of Code Table 2.           *      *     12
-       Identification of centre.              5      9     13
-       Generating process.                    6     10     14
-       Grid definition .                      7     11     15
-       Flag (Code Table 1).                   8     12     16
-       Indicator of parameter.                9     13     17
-       Indicator of type of level.           10     14     18
-       Height, pressure etc of levels.      11-12  15-16  19-20
-       Year of century.                      13     17     21
-       Month.                                14     18     22
-       Day.                                  15     19     23
-       Hour.                                 16     20     24
-       Minute.                               17     21     25
-       Indicator of unit of time.            18     22     26
-       P1 - Period of time.                  19     23     27
-       P2 - Period of time                  20(R)   24     28
-       or reserved octet (R).
-       Time range indicator.                21(R)   25     29
-       or reserved octet (R).
-       Number included in average.       22-23(R)  26-27  30-31
-       or reserved octet (R).
-       Number missing from average.         24(R)  28(R)   32
-       or reserved octet (R).
-       Century of data.                       *      *     33
-       Designates sub-centre if not 0.        *      *     34
-       Decimal scale factor.                  *      *    35-36
-       Reserved. Set to 0.                    *      *    37-48
-       (Need not be present)
-       For originating centre use only.       *      *    49-nn
-       (Need not be present)
-
-    Identify which GRIB code edition is being decoded.
-
-    In GRIB edition 1, the edition number is in octet 8.
-    In GRIB edition 0, octet 8 is reserved and set to 0.
-    In GRIB edition -1, octet 8 is a flag field and can have a
-    a valid value of 0, 1, 2 or 3.
+      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
+      return;
+   }
 
-    However, GRIB edition number 0 has a fixed
-    length of 24, included in the message, for section 1, so
-    if the value extracted from octets 5-7 is 24 and that from
-    octet 8 is 0, it is safe to assume edition 0 of the code.
+  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
 
-  */
-  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
-    {
-      /*
-	Set length of GRIB message to missing data value.
-      */
-      ISEC0_GRIB_Len = 0;
-    }
-  /*
-    If Grib Edition 1 and only length is required, go to section 9.
-  */
-  if ( dfunc == 'L' ) goto LABEL900;
+  if ( pcScale == 0 ) return;
 
-  /*
-    ----------------------------------------------------------------
-    PDS Product Definition Section (Section 1)
-    ----------------------------------------------------------------
-  */ 
-  pds = is + isLen;
+  power = (double) pcScale / 1000.;
+  scale[0] = 1.0;
 
-  pdsLen = decodePDS(pds, isec0, isec1);
+  if (pcScale != 1000)
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] = pow((double) (n*(n+1)), power);
+  else
+    for ( int n = 1; n <= trunc; n++ )
+      scale[n] =     (double) (n*(n+1));
 
-  /*
-    ----------------------------------------------------------------
-    GDS Grid Description Section (Section 2)
-    ----------------------------------------------------------------
-  */
-  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  if ( inv )
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
-  if ( gdsIncluded )
-    {
-      gds = is + isLen + pdsLen;
+  /* Scale the values */
 
-      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
-    }
+  size_t index = 0;
 
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  for ( int m = 0;   m < pcStart; m++ )
+    for ( int n = m; n <= trunc; n++, index += 2 )
+      if ( n >= pcStart )
+        {
+          fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+          fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+        }
 
-  isec3[0] = 0;
-  if ( bmsIncluded )
-    {
-      bms = is + isLen + pdsLen + gdsLen;
+  for ( int m = pcStart; m <= trunc; m++ )
+    for ( int n = m;     n <= trunc; n++, index += 2 )
+      {
+	fpdata[index  ] = (T)(fpdata[index  ] * scale[n]);
+	fpdata[index+1] = (T)(fpdata[index+1] * scale[n]);
+      }
 
-      bmsLen = BMS_Len;
-      imaskSize = (bmsLen - 6)<<3;
-      bitmapSize = imaskSize - BMS_UnusedBits;
-      /*
-      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
-      */
-    }
+  Free(scale);
+}
 
-  /*
-    ----------------------------------------------------------------
-    BDS Binary Data Section (Section 4)
-    ----------------------------------------------------------------
-  */
-  bds = is + isLen + pdsLen + gdsLen + bmsLen;
 
-  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
+void TEMPLATE(scatter_complex,T)(T *fpdata, int pcStart, int trunc, int nsp)
+{
+  T *fphelp = (T*) Malloc((size_t)nsp*sizeof(T));
+  int  m, n;
+  int  index, inext;
 
-  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
-				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
+  if ( fphelp == NULL ) SysError("No Memory!");
 
-  if ( *iret != 0 ) return;
+  index = inext = 0;
 
-  ISEC4_NumNonMissValues = ISEC4_NumValues;
+  for ( m = 0;   m <= pcStart; m++ )
+    for ( n = m; n <= trunc; n++ )
+      {
+	if ( pcStart >= n )
+	  {
+	    fphelp[index  ] = fpdata[inext++];
+	    fphelp[index+1] = fpdata[inext++];
+	  }
+	index += 2;
+      }
 
-  if ( bitmapSize > 0 )
-    {
-      if ( dfunc != 'L' && dfunc != 'J' )
-	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+  index = 0;
+  for ( m = 0;   m <= trunc; m++ )
+    for ( n = m; n <= trunc; n++ )
+      {
+	if ( n > pcStart )
 	  {
-	    lmissvalinfo = 0;
-	    FSEC3_MissVal = (T)GRIB_MISSVAL;
-	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	    fphelp[index  ] = fpdata[inext++];
+	    fphelp[index+1] = fpdata[inext++];
 	  }
+	index += 2;
+      }
 
-      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
-      ISEC4_NumValues        = bitmapSize;
+  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-      if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
-	{
-	  GRIBPACK bitmap;
-	  /*
-	  unsigned char *bitmap;
-	  bitmap = BMS_Bitmap;
-	  int j = ISEC4_NumNonMissValues;
-	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
-	    {
-	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
-		fsec4[i] = fsec4[--j];
-	      else
-		fsec4[i] = FSEC3_MissVal;
-	    }
-	  */
+  Free(fphelp);
+}
 
-	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
-#if defined (VECTORCODE)
-	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  GRIBPACK *pbitmap = imask;
-#else
-	  GRIBPACK *pbitmap = BMS_Bitmap;
-#endif
+void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
+{
+  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
+  size_t inext = 0;
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-	  for ( int i = imaskSize/8-1; i >= 0; i-- )
-	    {
-	      bitmap = pbitmap[i];
-	      imask[i*8+0] = 1 & (bitmap >> 7);
-	      imask[i*8+1] = 1 & (bitmap >> 6);
-	      imask[i*8+2] = 1 & (bitmap >> 5);
-	      imask[i*8+3] = 1 & (bitmap >> 4);
-	      imask[i*8+4] = 1 & (bitmap >> 3);
-	      imask[i*8+5] = 1 & (bitmap >> 2);
-	      imask[i*8+6] = 1 & (bitmap >> 1);
-	      imask[i*8+7] = 1 & (bitmap);
-	    }
+  for ( size_t m = 0, index = 0;   m <= pcStart; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
+      {
+	if ( pcStart >= n )
+	  {
+	    fphelp[inext++] = fpdata[index];
+	    fphelp[inext++] = fpdata[index+1];
+	  }
+	index += 2;
+      }
 
-	  int j = 0;
-	  for ( int i = 0; i < ISEC4_NumValues; i++ )
-	    if ( imask[i] ) j++;
+  for ( size_t m = 0, index = 0; m <= trunc; m++ )
+    for ( size_t n = m; n <= trunc; n++ )
+      {
+	if ( n > pcStart )
+	  {
+	    fphelp[inext++] = fpdata[index];
+	    fphelp[inext++] = fpdata[index+1];
+	  }
+	index += 2;
+      }
 
-	  if ( ISEC4_NumNonMissValues != j )
-	    {
-	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
-		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
-			j, ISEC4_NumNonMissValues);
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-	      ISEC4_NumNonMissValues = j;
-	    }
+  Free(fphelp);
+}
 
-	  if ( dfunc != 'J' )
-	    {
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
-		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
-	    }
 
-	  Free(imask);
-	}
-    }
+void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
+{
+  /* System generated locals */
+  double r_1;
 
-  if ( ISEC2_Reduced )
-    {
-      int nvalues = 0;
-      int nlat = ISEC2_NumLat;
-      int nlon = ISEC2_RowLonPtr[0];
-      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
-      for ( int ilat = 1; ilat < nlat; ++ilat )
-	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
+  /* Local variables */
+  int jl;
+  double zfac, zeps, zbeta;
+  double zalpha;
 
-      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
-      // if ( dlon < 0 ) dlon += 360000;
-	  
-      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+  /* **** SCM0   - Apply SCM0 limiter to derivative estimates. */
+  /* output: */
+  /*   pdl   = the limited derivative at the left edge of the interval */
+  /*   pdr   = the limited derivative at the right edge of the interval */
+  /* inputs */
+  /*   pdl   = the original derivative at the left edge */
+  /*   pdr   = the original derivative at the right edge */
+  /*   pfl   = function value at the left edge of the interval */
+  /*   pfr   = function value at the right edge of the interval */
+  /*   klg   = number of intervals where the derivatives are limited */
 
-      //printf("nlat %d  nlon %d \n", nlat, nlon);
-      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
+  /*  define constants */
 
-      if ( dfunc == 'R' && *iret == -801 )
-	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
-		ISEC4_NumValues, nvalues);
-      
-      if ( dfunc == 'R' && *iret != -801 )
-	{
-	  ISEC2_Reduced = 0;
-	  ISEC2_NumLon = nlon;
-	  ISEC4_NumValues = nlon*nlat;
+  zeps = 1.0e-12;
+  zfac = (1.0 - zeps) * 3.0;
 
-	  lsect3 = bitmapSize > 0;
-          int lperio = 1;
-	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
-                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
-                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
-                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
-                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
-                       (ISEC1_Parameter == 43));
-	
-	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
-	      
-	  if ( bitmapSize > 0 )
-	    {
-	      int j = 0;	      
-	      for ( int i = 0; i < ISEC4_NumValues; i++ )
-		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
-		  
-	      ISEC4_NumNonMissValues = j;
-	    }
+  for ( jl = 0; jl < klg; ++jl )
+    {
+      if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
+	{
+	  zalpha = pdl[jl] / (pfr[jl] - pfl[jl]);
+	  zbeta  = pdr[jl] / (pfr[jl] - pfl[jl]);
+	  if ( zalpha <= 0.0 ) pdl[jl] = 0.0;
+	  if ( zbeta  <= 0.0 ) pdr[jl] = 0.0;
+	  if ( zalpha > zfac ) pdl[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
+	  if ( zbeta  > zfac ) pdr[jl] = (T)(zfac * (pfr[jl] - pfl[jl]));
+	}
+      else
+	{
+	  pdl[jl] = 0.0;
+	  pdr[jl] = 0.0;
 	}
     }
+} /* scm0 */
 
+static
+int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
+			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
+{
+  /*
+C---->
+C**** ROWINA3 - Interpolation of row of values.
+C
+C     Purpose.
+C     --------
+C
+C     Interpolate a row of values.
+C
+C
+C**   Interface.
+C     ----------
+C
+C     CALL ROWINA3( P, KO, KI, PW, KCODE, PMSVAL, KRET, OMISNG, OPERIO)
+C
+C
+C     Input Parameters.
+C     -----------------
+C
+C     P      - Row of values to be interpolated.
+C              Dimension must be at least KO.
+C
+C     KO     - Number of values required.
+C
+C     KI     - Number of values in P on input.
+C
+C     PW     - Working array.
+C              Dimension must be at least (0:KO+2,3).
+C
+C     KCODE  - Interpolation required.
+C              1 , linear.
+C              3 , cubic.
+C
+C     PMSVAL - Value used for missing data indicator.
+C
+C     OMISNG - True if missing values are present in field.
+C
+C     OPERIO - True if input field is periodic.
+C
+C     OVEGGY - True if 'nearest neighbour' processing must be used
+C              for interpolation
+C
+C     Output Parameters.
+C     ------------------
+C
+C     P     - Now contains KO values.
+C     KRET  - Return code
+C             0, OK
+C             Non-zero, error
+C
+C
+C     Method.
+C     -------
+C
+C     Linear or cubic interpolation performed as required.
+C
+C     Comments.
+C     ---------
+C
+C     This is a version of ROWINA which allows for missing data
+C     values and hence for bitmapped fields.
+C
+C
+C     Author.
+C     -------
+C
+C     J.D.Chambers    ECMWF     22.07.94
+C
+C
+C     Modifications.
+C     --------------
+C
+C     J.D.Chambers    ECMWF     13.09.94
+C     Add return code KRET and remove calls to ABORT.
+C
+C     J. Clochard, Meteo France, for ECMWF - January 1998.
+C     Addition of OMISNG and OPERIO arguments.
+C
+C
+C     -----------------------------------------------------------------
+*/
+  /* System generated locals */
+  int pw_dim1, pw_offset, i_1;
 
-  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
-  esLen = 4;
-
-  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
-
-  if ( ISEC0_GRIB_Len )
-    if ( ISEC0_GRIB_Len < gribLen )
-      Warning("Length of GRIB message is inconsistent (grib_message_size=7867 < grib_record_size=9718)!", ISEC0_GRIB_Len, gribLen);
+  /* Local variables */
+  int jl, ip;
+  double zwt1, zrdi, zpos;
+  double zdo, zwt;
 
-  ISEC0_GRIB_Len = gribLen;
+  UNUSED(omisng);
 
-  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
+  /* Parameter adjustments */
+  --p;
+  pw_dim1 = ko + 3;
+  pw_offset = pw_dim1;
+  pw -= pw_offset;
 
-  /*
-    ----------------------------------------------------------------
-    Section 9 . Abort/return to calling routine.
-    ----------------------------------------------------------------
-  */
- LABEL900:;
+  *kret = 0;
 
-  if ( ldebug )
+  if ( kcode == 1 )
     {
-      gprintf(__func__, "Section 9.");
-      gprintf(__func__, "Output values set -");
-
-      gribPrintSec0(isec0);
-      gribPrintSec1(isec0, isec1);
-      /*
-	Print section 2 if present.
-      */
-      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
+      /*    Move input values to work array */
+      for ( jl = 1; jl <= ki; ++jl )
+	pw[jl + pw_dim1] = p[jl];
 
-      if ( ! l_iorj )
+      if ( operio )
 	{
-	  /*
-	    Print section 3 if present.
-	  */
-	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+	  /* Arrange wrap-around value in work array */
+	  pw[ki + 1 + pw_dim1] = p[1];
 
-	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
-	  /*
-	    Special print for 2D spectra wave field real values in
-	    section 4
-	  */
-	  if ( (isec1[ 0] ==  140) && 
-	       (isec1[ 1] ==   98) && 
-	       (isec1[23] ==    1) && 
-	       ((isec1[39] == 1045) || (isec1[39] == 1081))  && 
-	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
-	    gribPrintSec4Wave(isec4);
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) ki;
+	  zdo = 1.0 / (double) ko;
 	}
-    }
-}
-
-#endif /* T */
-
-/*
- * Local Variables:
- * mode: c
- * End:
- */
-
-/* GRIB block 0 - indicator block */
-static
-void encodeIS(GRIBPACK *lGrib, long *gribLen)
-{
-  long z;
-  // z = *gribLen;
-
-  lGrib[0] = 'G';
-  lGrib[1] = 'R';
-  lGrib[2] = 'I';
-  lGrib[3] = 'B';
-
-  /* 
-   * lGrib[4]-lGrib[6] contains full length of grib record. 
-   * included before finished CODEGB
-   */
+      else
+	{
+	  /* Repeat last value, to cope with "implicit truncation" below */
+	  pw[ki + 1 + pw_dim1] = p[ki];
 
-  z = 7;   
-  Put1Byte(1); /* grib version */
-  z = 8;
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) (ki-1);
+	  zdo = 1.0 / (double) (ko-1);
+ 	}
 
-  *gribLen = z;
-}
+      /*    Loop through the output points */
+      for ( jl = 1; jl <= ko; ++jl )
+	{
 
-/* GRIB block 5 - end block */
-static
-void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
-{
-  long z = *gribLen;
+	  /* Calculate weight from the start of row */
+	  zpos = (jl - 1) * zdo;
+	  zwt = zpos * zrdi;
 
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
+	  /* Get the current array position(minus 1) from the weight - */
+	  /* note the implicit truncation. */
+	  ip = (int) zwt;
+		  
+	  /* Adjust the weight to range (0.0 to 1.0) */
+	  zwt -= ip;
 
-  if ( z > JP23SET )
+          /* If 'nearest neighbour' processing must be used */
+	  if ( oveggy )
+	    {
+              if ( zwt < 0.5 )
+                p[jl] = pw[ip + 1 + pw_dim1];
+	      else
+		p[jl] = pw[ip + 2 + pw_dim1];
+	    }
+	  else
+	    {
+	      /*    If the left value is missing, use the right value */
+	      if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
+		{
+		  p[jl] = pw[ip + 2 + pw_dim1];
+		}
+	      /*    If the right value is missing, use the left value */
+	      else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
+		{
+		  p[jl] = pw[ip + 1 + pw_dim1];
+		}
+	      /*    If neither missing, interpolate ... */
+	      else
+		{
+		  /*  Interpolate using the weighted values on either side */
+		  /*  of the output point position */
+		  p[jl] = (T)((1.0 - zwt) * pw[ip+1 + pw_dim1]
+                              + zwt * pw[ip+2 + pw_dim1]);
+		}
+	    }
+	}
+    }
+  else if ( kcode == 3 )
     {
-      long itemp;
-      long bdslen = z - 4;
-      /*
-      fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET);
-      exit(1);
-      */
-      /*
-	If a very large product, the section 4 length field holds
-	the number of bytes in the product after section 4 upto
-	the end of the padding bytes.
-	This is a fixup to get round the restriction on product lengths
-	due to the count being only 24 bits. It is only possible because
-	the (default) rounding for GRIB products is 120 bytes.
-      */
-      while ( z%120 ) lGrib[z++] = 0;
-
-      if ( z > JP23SET*120 )
+      /*     *******************************    */
+      /*     Section 2.  Cubic interpolation .. */
+      /*     *******************************    */
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
 	{
-	  fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET*120);
-	  exit(1);
+          if ( IS_EQUAL(p[jl], msval) )
+	    {
+	      fprintf(stderr," ROWINA3: ");
+	      fprintf(stderr," Cubic interpolation not supported");
+	      fprintf(stderr," for fields containing missing data.\n");
+	      *kret = 1;
+	      goto L900;
+	    }
+          pw[jl + pw_dim1] = p[jl];
+	}
+      pw[pw_dim1] = p[ki];
+      pw[ki + 1 + pw_dim1] = p[1];
+      pw[ki + 2 + pw_dim1] = p[2];
+      i_1 = ki;
+      for ( jl = 1; jl <= i_1; ++jl )
+	{
+          pw[jl + (pw_dim1 << 1)] =
+            (T)(- pw[jl - 1 + pw_dim1] / 3.0 -
+                pw[jl     + pw_dim1] * 0.5 +
+                pw[jl + 1 + pw_dim1] - pw[jl + 2 + pw_dim1] / 6.0);
+          pw[jl + 1 + pw_dim1 * 3] =
+            (T)(pw[jl - 1 + pw_dim1] / 6.0 -
+                pw[jl     + pw_dim1] +
+                pw[jl + 1 + pw_dim1] * 0.5 +
+                pw[jl + 2 + pw_dim1] / 3.0);
 	}
 
-      itemp = z / (-120);
-      itemp = JP23SET - itemp + 1;
+      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
+		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
 
-      lGrib[4] = (GRIBPACK)(itemp >> 16);
-      lGrib[5] = (GRIBPACK)(itemp >>  8);
-      lGrib[6] = (GRIBPACK)itemp;
+      zrdi = (double) ki;
+      zdo = 1.0 / (double) ko;
+      for ( jl = 1; jl <= ko; ++jl )
+	{
+          zpos = (jl - 1) * zdo;
+          zwt = zpos * zrdi;
+          ip = (int) zwt + 1;
+          zwt = zwt + 1.0 - ip;
+          zwt1 = 1.0 - zwt;
+          p[jl] = (T)(((3.0 - zwt1 * 2.0) * pw[ip + pw_dim1] +
+                       zwt * pw[ip + (pw_dim1 << 1)]) * zwt1 * zwt1 +
+                      ((3.0 - zwt * 2.0) * pw[ip + 1 + pw_dim1] -
+                       zwt1 * pw[ip + 1 + pw_dim1 * 3]) * zwt * zwt);
+	}
 
-      bdslen = z - bdslen;
-      lGrib[bdsstart  ] = (GRIBPACK)(bdslen >> 16);
-      lGrib[bdsstart+1] = (GRIBPACK)(bdslen >>  8);
-      lGrib[bdsstart+2] = (GRIBPACK)bdslen;
     }
   else
     {
-      lGrib[4] = (GRIBPACK)(z >> 16);
-      lGrib[5] = (GRIBPACK)(z >>  8);
-      lGrib[6] = (GRIBPACK)z;
-
-      while ( z%8 ) lGrib[z++] = 0;
+      /*    **************************************    */
+      /*    Section 3.  Invalid interpolation code .. */
+      /*    **************************************    */
+      fprintf(stderr," ROWINA3:");
+      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
+      *kret = 2;
     }
 
-  *gribLen = z;
-}
-
-/* GRIB block 1 - product definition block. */
+L900:
+    return 0;
+} /* rowina3 */
 
-#define DWD_extension_253_len 38
-#define DWD_extension_254_len 26
-#define ECMWF_extension_1_len 24
-#define MPIM_extension_1_len  18
 
-static
-long getLocalExtLen(int *isec1)
+int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
+			T msval, int *kret, int omisng, int operio, int oveggy)
 {
-  long extlen = 0;
+  /*
+C**** QU2REG3 - Convert quasi-regular grid data to regular.
+C
+C     Purpose.
+C     --------
+C
+C     Convert quasi-regular grid data to regular,
+C     using either a linear or cubic interpolation.
+C
+C
+C**   Interface.
+C     ----------
+C
+C     CALL QU2REG3(PFIELD,KPOINT,KLAT,KLON,KCODE,PMSVAL,OMISNG,OPERIO,
+C    X            OVEGGY)
+C
+C
+C     Input Parameters.
+C     -----------------
+C
+C     PFIELD     - Array containing quasi-regular grid data.
+C
+C     KPOINT     - Array containing list of the number of
+C                  points on each latitude (or longitude) of
+C                  the quasi-regular grid.
+C
+C     KLAT       - Number of latitude lines
+C
+C     KLON       - Number of longitude lines
+C
+C     KCODE      - Interpolation required.
+C                  1 , linear - data quasi-regular on latitude lines.
+C                  3 , cubic -  data quasi-regular on latitude lines.
+C                  11, linear - data quasi-regular on longitude lines.
+C                  13, cubic -  data quasi-regular on longitude lines.
+C
+C     PMSVAL     - Value used for missing data indicator.
+C
+C     OMISNG     - True if missing values are present in field.
+C
+C     OPERIO     - True if input field is periodic.
+C
+C     OVEGGY     - True if 'nearest neighbour' processing must be used
+C                  for interpolation
+C
+C
+C     Output Parameters.
+C     ------------------
+C
+C     KRET       - return code
+C                  0 = OK
+C                  non-zero indicates fatal error
+C
+C
+C     Output Parameters.
+C     ------------------
+C
+C     PFIELD     - Array containing regular grid data.
+C
+C
+C     Method.
+C     -------
+C
+C     Data is interpolated and expanded into a temporary array,
+C     which is then copied back into the user's array.
+C     Returns an error code if an invalid interpolation is requested
+C     or field size exceeds array dimensions.
+C
+C     Comments.
+C     ---------
+C
+C     This routine is an adaptation of QU2REG to allow missing data
+C     values, and hence bit mapped fields.
+C
+C
+C     Author.
+C     -------
+C
+C     J.D.Chambers     ECMWF      22.07.94
+C
+C
+C     Modifications.
+C     --------------
+C
+C     J.D.Chambers     ECMWF      13.09.94
+C     Add return code KRET and remove calls to ABORT.
+C
+C     J.D.Chambers     ECMWF        Feb 1997
+C     Allow for 64-bit pointers
+C
+C     J. Clochard, Meteo France, for ECMWF - January 1998.
+C     Addition of OMISNG and OPERIO arguments.
+C     Fix message for longitude number out of bounds, and routine
+C     name in title and formats.
+C
+*/
+   /* System generated locals */
+   int i_1, i_2;
+   int kcode = 1;
 
-  if ( ISEC1_LocalFLag )
-    {
-      if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
-	{
-	  if      ( isec1[36] == 254 ) extlen = DWD_extension_254_len;
-	  else if ( isec1[36] == 253 ) extlen = DWD_extension_253_len;
-	}
-      else if ( ISEC1_CenterID == 98 )
-        {
-	  if ( isec1[36] == 1 )   extlen = ECMWF_extension_1_len;
-        }
-      else if ( ISEC1_CenterID == 252 )
-        {
-	  if ( isec1[36] == 1 ) extlen = MPIM_extension_1_len;
-        }
-    }
+   /* Local variables */
+   int ilii, ilio, icode;
+   int iregno, iquano, j210, j220, j230, j240, j225;
+   T *ztemp = NULL;
+   T *zline = NULL;
+   T *zwork = NULL;
 
-  return (extlen);
-}
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-static
-long getPdsLen(int *isec1)
-{
-  long pdslen = 28;
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-  pdslen += getLocalExtLen(isec1);
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
-  return (pdslen);
-}
+   /* Parameter adjustments */
+   --pfield;
+   --kpoint;
 
-static
-void encodePDS_DWD_local_Extension_254(GRIBPACK *lGrib, long *zs, int *isec1)
-{
-  int isvn;
-  long localextlen, i;
-  long z = *zs;
+/* ------------------------------ */
+/* Section 1. Set initial values. */
+/* ------------------------------ */
 
-  localextlen = getLocalExtLen(isec1);
-  for ( i = 0; i < localextlen-2; i++ )
-    {
-      Put1Byte(isec1[24+i]);
-    }
+   *kret = 0;
 
-  isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
-  Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
+/* Check input parameters. */
 
-  *zs = z;
-}
+   if (kcode != 1 && kcode != 3 && kcode != 11 && kcode != 13) {
+      fprintf(stderr," QU2REG :");
+      fprintf(stderr," Invalid interpolation type code = %2d\n",kcode);
+      *kret = 1;
+      goto L900;
+   }
 
-static
-void encodePDS_DWD_local_Extension_253(GRIBPACK *lGrib, long *zs, int *isec1)
-{
-  int isvn;
-  long localextlen, i;
-  long z = *zs;
+/* Set array indices to 0. */
 
-  localextlen = DWD_extension_254_len;
-  for ( i = 0; i < localextlen-2; i++ )
-    {
-      Put1Byte(isec1[24+i]);
-    }
+   ilii = 0;
+   ilio = 0;
 
-  isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
-  Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
-  Put1Byte(isec1[50]);        /* 55 User id, specified by table       */
-  Put2Byte(isec1[51]);        /* 56 Experiment identifier             */
-  Put2Byte(isec1[52]);        /* 58 Ensemble identification by table  */
-  Put2Byte(isec1[53]);        /* 60 Number of ensemble members        */
-  Put2Byte(isec1[54]);        /* 62 Actual number of ensemble member  */
-  Put1Byte(isec1[55]);        /* 64 Model major version number        */ 
-  Put1Byte(isec1[56]);        /* 65 Model minor version number        */ 
-  Put1Byte(0);                /* 66 Blank for even buffer length      */
+/* Establish values of loop parameters. */
 
-  *zs = z;
-}
+   if (kcode > 10) {
 
-static
-void encodePDS_ECMWF_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
-{
-  // int isvn;
-  long localextlen, i;
-  long z = *zs;
+/*    Quasi-regular along longitude lines. */
 
-  localextlen = getLocalExtLen(isec1);
-  for ( i = 0; i < localextlen-12; i++ )
-    {
-      Put1Byte(isec1[24+i]);
-    }
-                              /* 12 bytes explicitly encoded below:         */
-  Put1Byte(isec1[36]);        /* ECMWF local GRIB use definition identifier */
-                              /*    1=MARS labelling or ensemble fcst. data */
-  Put1Byte(isec1[37]);        /* Class                                      */
-  Put1Byte(isec1[38]);        /* Type                                       */
-  Put2Byte(isec1[39]);        /* Stream                                     */
+      iquano = klon;
+      iregno = klat;
+      icode = kcode - 10;
+   } else {
 
-  /* Version number or experiment identifier    */
-  Put1Byte(((unsigned char*) &isec1[40])[0]);
-  Put1Byte(((unsigned char*) &isec1[40])[1]);
-  Put1Byte(((unsigned char*) &isec1[40])[2]);
-  Put1Byte(((unsigned char*) &isec1[40])[3]);
+/*    Quasi-regular along latitude lines. */
 
-  Put1Byte(isec1[41]);        /* Ensemble forecast number                   */
-  Put1Byte(isec1[42]);        /* Total number of forecasts in ensemble      */
-  Put1Byte(0);                /* (Spare)                                    */
+      iquano = klat;
+      iregno = klon;
+      icode = kcode;
+   }
 
-  *zs = z;
-}
+/*     -------------------------------------------------------- */
+/**    Section 2. Interpolate field from quasi to regular grid. */
+/*     -------------------------------------------------------- */
 
-static
-void encodePDS_MPIM_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
-{
-  // int isvn;
-  long localextlen, i;
-  long z = *zs;
+   i_1 = iquano;
+   for (j230 = 1; j230 <= i_1; ++j230) {
 
-  localextlen = getLocalExtLen(isec1);
-  for ( i = 0; i < localextlen-6; i++ )
-    {
-      Put1Byte(isec1[24+i]);
-    }
-                              /* 6 bytes explicitly encoded below:          */
-  Put1Byte(isec1[36]);        /* MPIM local GRIB use definition identifier  */
-                              /*    (extension identifier)                  */
-  Put1Byte(isec1[37]);        /* type of ensemble forecast                  */
-  Put2Byte(isec1[38]);        /* individual ensemble member                 */
-  Put2Byte(isec1[39]);        /* number of forecasts in ensemble            */
+      if (iregno != kpoint[j230]) {
 
-  *zs = z;
-}
+/*       Line contains less values than required,so */
+/*       extract quasi-regular grid values for a line */
 
-/* GRIB BLOCK 1 - PRODUCT DESCRIPTION SECTION */
-static
-void encodePDS(GRIBPACK *lpds, long pdsLen, int *isec1)
-{
-  GRIBPACK *lGrib = lpds;
-  long z = 0;
-  int ival, century, year;
+         i_2 = kpoint[j230];
+         for (j210 = 1; j210 <= i_2; ++j210) {
+            ++ilii;
+            zline[j210 - 1] = pfield[ilii];
+         }
 
-  century = ISEC1_Century;
-  year    = ISEC1_Year;
+/*       and interpolate this line. */
 
-  if ( century < 0 )
-    {
-      century = -century;
-      year    = -year;
-    }
+         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
+         if (*kret != 0) goto L900;
 
-  Put3Byte(pdsLen);               /*  0 Length of Block 1        */
-  Put1Byte(ISEC1_CodeTable);      /*  3 Local table number       */
-  Put1Byte(ISEC1_CenterID);       /*  4 Identification of centre */
-  Put1Byte(ISEC1_ModelID);        /*  5 Identification of model  */
-  Put1Byte(ISEC1_GridDefinition); /*  6 Grid definition          */
-  Put1Byte(ISEC1_Sec2Or3Flag);    /*  7 Block 2 included         */
-  Put1Byte(ISEC1_Parameter);      /*  8 Parameter Code           */
-  Put1Byte(ISEC1_LevelType);      /*  9 Type of level            */
-  if ( (ISEC1_LevelType !=  20) &&
-       (ISEC1_LevelType != GRIB1_LTYPE_99)         &&
-       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)   &&
-       (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)   &&
-       (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)     &&
-       (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)      &&
-       (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)     &&
-       (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH)  &&
-       (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC) &&
-       (ISEC1_LevelType != 115) &&
-       (ISEC1_LevelType != 117) &&
-       (ISEC1_LevelType != 125) &&
-       (ISEC1_LevelType != 127) &&
-       (ISEC1_LevelType != 160) &&
-       (ISEC1_LevelType != 210) )
-    {
-      Put1Byte(ISEC1_Level1);
-      Put1Byte(ISEC1_Level2);
-    }
-  else
-    {
-      Put2Byte(ISEC1_Level1);     /* 10 Level                    */    
-    }
+/*       Add regular grid values for this line to the
+         temporary array. */
 
-  Put1Int(year);                  /* 12 Year of Century          */
-  Put1Byte(ISEC1_Month);          /* 13 Month                    */
-  Put1Byte(ISEC1_Day);            /* 14 Day                      */
-  Put1Byte(ISEC1_Hour);           /* 15 Hour                     */
-  Put1Byte(ISEC1_Minute);         /* 16 Minute                   */
+         i_2 = iregno;
+         for (j220 = 1; j220 <= i_2; ++j220) {
+            ++ilio;
+            ztemp[ilio - 1] = zline[j220 - 1];
+         }
 
-  Put1Byte(ISEC1_TimeUnit);       /* 17 Time unit                */
-  if ( ISEC1_TimeRange == 10 )
-    {
-      Put1Byte(ISEC1_TimePeriod1);
-      Put1Byte(ISEC1_TimePeriod2);
-    }
-  else if ( ISEC1_TimeRange == 113 || ISEC1_TimeRange ==   0 )
-    {
-      Put1Byte(ISEC1_TimePeriod1);
-      Put1Byte(0);
-    }
-  else if ( ISEC1_TimeRange ==   5 || ISEC1_TimeRange ==   4 || 
-	    ISEC1_TimeRange ==   3 || ISEC1_TimeRange ==   2 )
-    {
-      Put1Byte(0);
-      Put1Byte(ISEC1_TimePeriod2);
-    }
-  else
-    {
-      Put1Byte(0);
-      Put1Byte(0); 
-    }
-  Put1Byte(ISEC1_TimeRange);      /* 20 Timerange flag           */
-  Put2Byte(ISEC1_AvgNum);         /* 21 Average                  */
+      } else {
 
-  Put1Byte(ISEC1_AvgMiss);        /* 23 Missing from averages    */
-  Put1Byte(century);              /* 24 Century                  */
-  Put1Byte(ISEC1_SubCenterID);    /* 25 Subcenter                */
-  Put2Byte(ISEC1_DecScaleFactor); /* 26 Decimal scale factor     */
+/*       Line contains the required number of values, so add */
+/*       this line to the temporary array. */
 
-  if ( ISEC1_LocalFLag )
-    {
-      if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
-	{
-	  if      ( isec1[36] == 254 ) encodePDS_DWD_local_Extension_254(lGrib, &z, isec1);
-	  else if ( isec1[36] == 253 ) encodePDS_DWD_local_Extension_253(lGrib, &z, isec1);
-	}
-      else if ( ISEC1_CenterID == 98 )
-	{
-	  if ( isec1[36] == 1 ) encodePDS_ECMWF_local_Extension_1(lGrib, &z, isec1);
-	}
-      else if ( ISEC1_CenterID == 252 )
-	{
-	  if ( isec1[36] == 1 ) encodePDS_MPIM_local_Extension_1(lGrib, &z, isec1);
-	}
-      else
-	{
-	  long i, localextlen;
-	  localextlen = getLocalExtLen(isec1);
-	  for ( i = 0; i < localextlen; i++ )
-	    {
-	      Put1Byte(isec1[24+i]);
-	    }
-	}
-    }
-}
+         i_2 = iregno;
+         for (j225 = 1; j225 <= i_2; ++j225) {
+            ++ilio;
+            ++ilii;
+            ztemp[ilio - 1] = pfield[ilii];
+         }
+      }
+   }
 
+/* Copy temporary array to user array. */
 
+   i_1 = klon * klat;
+   for (j240 = 1; j240 <= i_1; ++j240) {
+      pfield[j240] = ztemp[j240 - 1];
+   }
 
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
+L900:
 
+   Free(zwork);
+   Free(zline);
+   Free(ztemp);
 
-static
-void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
-				     const T *data, T zref, T factor, size_t *gz)
+   return 0;
+} /* qu2reg3 */
+
+#endif /* T */
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+#include <string.h>
+
+
+
+int gribVersion(unsigned char *is, size_t buffersize)
 {
-  size_t i, z = *gz;
-  unsigned int ival;
-  int cbits, jbits;
-  unsigned int c;
-  static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-    
-  /* code from gribw routine flist2bitstream */
+  if ( buffersize < 8 )
+    Error("Buffer too small (current size %d)!", (int) buffersize);
 
-  cbits = 8;
-  c = 0;
-  for ( i = packStart; i < datasize; i++ )
-    {
-      /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
-      /*
-	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
-	if ( ival < 0 ) ival = 0;
-      */
-      jbits = numBits;
-      while ( cbits <= jbits ) 
-	{
-	  if ( cbits == 8 )
-	    {
-	      jbits -= 8;
-	      lGrib[z++] = (ival >> jbits) & 0xFF;
-	    }
-	  else
-	    {
-	      jbits -= cbits;
-	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
-	      cbits = 8;
-	      c = 0;
-	    }
-	}
-      /* now jbits < cbits */
-      if ( jbits )
-	{
-	  c = (c << jbits) + (ival & mask[jbits]);
-	  cbits -= jbits;
-	}
-    }
-  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
+  return GRIB_EDITION(is);
+}
+
+static 
+double GET_Real(unsigned char *grib)
+{
+  int iexp  = GET_UINT1(grib[0]);
+  int imant = GET_UINT3(grib[1], grib[2], grib[3]);
 
-  *gz = z;
+  return decfp2(iexp, imant);
 }
 
-
-static
-void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
-				    const T *restrict data, T zref, T factor, size_t *gz)
+static 
+int decodeIS(unsigned char *is, int *isec0, int *iret)
 {
-  U_BYTEORDER;
-  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+  // Octets 1 - 4 : The letters G R I B. Four 8 bit fields.
 
-  if ( IS_BIGENDIAN() )
+  // Check letters -> GRIB, BUDG or TIDE.
+
+  // Check that 'GRIB' is found where expected.
+  bool lgrib = GRIB_START(is);
+
+  // ECMWF pseudo-grib data uses 'BUDG' and 'TIDE'.
+  bool lbudg = BUDG_START(is);
+  bool ltide = TIDE_START(is);
+
+  // Data is not GRIB or pseudo-grib.
+  if ( lgrib == false && lbudg == false && ltide == false )
     {
-      for ( size_t i = 0; i < datasize; i++ )
-        {
-          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
-        }
+      *iret = 305;
+      gprintf(__func__, "Input data is not GRIB or pseudo-grib.");
+      gprintf(__func__, "Return code = %d", *iret);
     }
-  else
+  if ( lbudg || ltide )
     {
-      uint16_t ui16;
-      for ( size_t i = 0; i < datasize; i++ )
-        {
-          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
-          sgrib[i] = gribSwapByteOrder_uint16(ui16);
-        }
+      *iret = 305;
+      gprintf(__func__, "Pseudo-grib data unsupported.");
+      gprintf(__func__, "Return code = %d", *iret);
     }
 
-  *gz += 2*datasize;
-}
-/*
-static
-void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
-				    const T *restrict data, T zref, T factor, size_t *gz)
-{
-  size_t i, z = *gz;
-  uint16_t ui16;
-  T tmp;
+  // Octets 5 - 7 : Length of message. One 24 bit field.
+  ISEC0_GRIB_Len = GRIB1_SECLEN(is);
 
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-  for ( i = 0; i < datasize; i++ )
-    {
-      tmp = ((data[i] - zref) * factor + (T)0.5);
-      ui16 = (uint16_t) tmp;
-      lGrib[z  ] = ui16 >>  8;
-      lGrib[z+1] = ui16;
-      z += 2;
-    }
+  // Octet 8 : GRIB Edition Number. One 8 bit field.
+  ISEC0_GRIB_Version = GRIB_EDITION(is);
 
-  *gz = z;
+  if ( ISEC0_GRIB_Version > 1 )
+    Error("GRIB version %d unsupported!", ISEC0_GRIB_Version);
+
+  int grib1offset = ISEC0_GRIB_Version * 4;
+
+  int isLen = 4 + grib1offset;
+
+  return isLen;
 }
-*/
-static
-void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
-			      GRIBPACK *restrict lGrib,
-			      const T *restrict data, 
-			      T zref, T factor, size_t *gz)
-{
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
-  uint64_t start_minmax, end_minmax;
-#endif
-  uint32_t ui32;
-  size_t i, z = *gz;
-  T tmp;
 
-  data += packStart;
-  datasize -= packStart;
+static 
+void decodePDS_ECMWF_local_Extension_1(unsigned char *pds, int *isec1)
+{
+  isec1[36] = GET_UINT1(pds[40]);         /* extension identifier       */
+  isec1[37] = GET_UINT1(pds[41]);         /* Class                      */
+  isec1[38] = GET_UINT1(pds[42]);         /* Type                       */
+  isec1[39] = GET_UINT2(pds[43],pds[44]); /* Stream                     */
+  /* isec1[40] = GET_UINT4(pds[45],pds[46],pds[47],pds[48]); */
+  memcpy((char*) &isec1[40], &pds[45], 4);
+  isec1[41] = GET_UINT1(pds[49]);         /* Forecast number            */
+  isec1[42] = GET_UINT1(pds[50]);         /* Total number of forecasts  */
+}
 
-  if      ( numBits ==  8 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(2, "pack 8 bit base");
-#endif
+static 
+void decodePDS_DWD_local_Extension_254(unsigned char *pds, int *isec1)
+{
+  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
+  for ( int i = 0; i < 11; i++ ) 
+    isec1[37+i] =  GET_UINT1(pds[41+i]);
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
-	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-	  lGrib[z  ] = (GRIBPACK)tmp;
-          z++;
-	}
+  int isvn = GET_UINT2(pds[52],pds[53]);
+  
+  isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
+  isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
+}
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
-    }
-  else if ( numBits == 16 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(3, "pack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_minmax = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_minmax = mach_absolute_time();
-#endif
-      if ( sizeof(T) == sizeof(double) )
-      	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
-        }
-      else
-        {
-          TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
-        }
+static 
+void decodePDS_DWD_local_Extension_253(unsigned char *pds, int *isec1)
+{
+  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
+  for ( int i = 0; i < 11; i++ ) 
+    isec1[37+i] =  GET_UINT1(pds[41+i]);
 
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_minmax = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_minmax = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(3);
-#endif
-    }
-  else if ( numBits == 24 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(4, "pack 24 bit base");
-#endif
+  int isvn = GET_UINT2(pds[52],pds[53]);
+  
+  isec1[48] =  isvn % 0x8000;              /* DWD experiment identifier            */
+  isec1[49] =  isvn >> 15;                 /* DWD run type (0=main, 2=ass, 3=test) */
+  isec1[50] =  GET_UINT1(pds[54]);         /* User id, specified by table          */
+  isec1[51] =  GET_UINT2(pds[55],pds[56]); /* Experiment identifier                */
+  isec1[52] =  GET_UINT2(pds[57],pds[58]); /* Ensemble identification by table     */
+  isec1[53] =  GET_UINT2(pds[59],pds[60]); /* Number of ensemble members           */
+  isec1[54] =  GET_UINT2(pds[61],pds[62]); /* Actual number of ensemble member     */
+  isec1[55] =  GET_UINT1(pds[63]);         /* Model major version number           */
+  isec1[56] =  GET_UINT1(pds[64]);         /* Model minor version number           */
+}
 
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
-	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-          ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
-          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
-          lGrib[z+2] =  (GRIBPACK)ui32;
-          z += 3;
-	}
+static 
+void decodePDS_MPIM_local_Extension_1(unsigned char *pds, int *isec1)
+{
+  isec1[36] = GET_UINT1(pds[40]);         /* extension identifier            */
+  isec1[37] = GET_UINT1(pds[41]);         /* type of ensemble forecast       */
+  isec1[38] = GET_UINT2(pds[42],pds[43]); /* individual ensemble member      */
+  isec1[39] = GET_UINT2(pds[44],pds[45]); /* number of forecasts in ensemble */
+}
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
-    }
-  else if ( numBits == 32 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit base");
-#endif
+static 
+int decodePDS(unsigned char *pds, int *isec0, int *isec1)
+{
+  int pdsLen = PDS_Len;
 
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
-	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-          ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
-          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
-          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
-          lGrib[z+3] =  (GRIBPACK)ui32;
-          z += 4;
-	}
+  ISEC1_CodeTable      = PDS_CodeTable;
+  ISEC1_CenterID       = PDS_CenterID;
+  ISEC1_ModelID        = PDS_ModelID;
+  ISEC1_GridDefinition = PDS_GridDefinition;
+  ISEC1_Sec2Or3Flag    = PDS_Sec2Or3Flag;
+  ISEC1_Parameter      = PDS_Parameter;
+  ISEC1_LevelType      = PDS_LevelType;
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
-    }
-  else if ( numBits > 0 && numBits <= 32 )
-    {
-      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
-    }
-  else if ( numBits == 0 )
+  if ( (ISEC1_LevelType !=  20) && 
+       (ISEC1_LevelType != GRIB1_LTYPE_99)           && 
+       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)     && 
+       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC_PA)  && 
+       (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)     && 
+       (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)       && 
+       (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)        && 
+       (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)       && 
+       (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH)    && 
+       (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC)   && 
+       (ISEC1_LevelType != 115) && 
+       (ISEC1_LevelType != 117) && 
+       (ISEC1_LevelType != 125) && 
+       (ISEC1_LevelType != 127) && 
+       (ISEC1_LevelType != GRIB1_LTYPE_SEADEPTH)     && 
+       (ISEC1_LevelType != 210) )
     {
+      ISEC1_Level1 = PDS_Level1;
+      ISEC1_Level2 = PDS_Level2;
     }
   else
     {
-      Error("Unimplemented packing factor %d!", numBits);
+      ISEC1_Level1 = PDS_Level;
+      ISEC1_Level2 = 0;
     }
 
-  *gz = z;
-}
-
-static
-void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize, 
-				       GRIBPACK *restrict lGrib,
-				       const T *restrict data, 
-				       T zref, T factor, size_t *gz)
-{
-  U_BYTEORDER;
-  size_t i, j, z = *gz;
-#ifdef _ARCH_PWR6
-#define __UNROLL_DEPTH_2 8
-#else
-#define __UNROLL_DEPTH_2 128
-#endif
-  size_t residual;
-  size_t ofs;
-  T dval[__UNROLL_DEPTH_2];
-
-  data += packStart;
-  datasize -= packStart;
-  residual =  datasize % __UNROLL_DEPTH_2;
-  ofs = datasize - residual;
-
-  // reducing FP operations to single FMA is slowing down on pwr6 ...
+  /* ISEC1_Year        = PDS_Year; */
+  ISEC1_Month          = PDS_Month;
+  ISEC1_Day            = PDS_Day;
+  ISEC1_Hour           = PDS_Hour;
+  ISEC1_Minute         = PDS_Minute;
+  ISEC1_TimeUnit       = PDS_TimeUnit;
+  ISEC1_TimePeriod1    = PDS_TimePeriod1;
+  ISEC1_TimePeriod2    = PDS_TimePeriod2;
+  ISEC1_TimeRange      = PDS_TimeRange;
+  ISEC1_AvgNum         = PDS_AvgNum;
+  ISEC1_AvgMiss        = PDS_AvgMiss;
 
-  if      ( numBits ==  8 )
+  if ( ISEC0_GRIB_Version == 1 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(2, "pack 8 bit unrolled");
-#endif
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *cgrib++ =  (unsigned long) dval[j];
-#else
-	      *cgrib++ =  (unsigned char) dval[j];
-#endif
-	    }
-	  z += __UNROLL_DEPTH_2;
-	}
-      for (j = 0; j < residual; j++) 
-	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
-	}
-      for (j = 0; j < residual; j++) 
-	{
-#ifdef _ARCH_PWR6
-	  *cgrib++ = (unsigned long) dval[j];
-#else
-	  *cgrib++ = (unsigned char) dval[j];
-#endif
-	}
-      z += residual;
-
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
+      ISEC1_Year           = PDS_Year;
+      ISEC1_Century        = PDS_Century;
+      ISEC1_SubCenterID    = PDS_Subcenter;
+      ISEC1_DecScaleFactor = PDS_DecimalScale;
     }
-  else if ( numBits == 16 )
+  else
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(3, "pack 16 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint16_t ival;
-#endif
-      uint16_t *sgrib = (uint16_t *) (lGrib+z);
-
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  if ( IS_BIGENDIAN() )
-	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-#ifdef _ARCH_PWR6
-		  *sgrib++ = (unsigned long) dval[j];
-#else
-		  *sgrib++ = (uint16_t) dval[j];
-#endif
-		}
-	      z += 2*__UNROLL_DEPTH_2;
-	    }
-	  else
-	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-		  ival = (uint16_t) dval[j];
-                  *sgrib++ = gribSwapByteOrder_uint16(ival);
-		}
-	      z += 2*__UNROLL_DEPTH_2;
-	    }
-	}
-      for (j = 0; j < residual; j++) 
-	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
-	}
-      if ( IS_BIGENDIAN() )
+      int year             = GET_UINT1(pds[12]);
+      if ( year <= 100 )
 	{
-	  for (j = 0; j < residual; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *sgrib++ = (unsigned long) dval[j];
-#else
-              *sgrib++ = (uint16_t) dval[j];
-#endif
-	    }
-	  z += 2*residual;
+	  ISEC1_Year       = year;
+	  ISEC1_Century    = 1;
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
-	    {
-              ival = (uint16_t) dval[j];
-	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
-	      lGrib[z+1] = (GRIBPACK)ival;
-	      z += 2;
-	    }
+	  ISEC1_Year       = year%100;
+	  ISEC1_Century    = 1 + (year-ISEC1_Year)/100;
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(3);
-#endif
+      ISEC1_SubCenterID    = 0;
+      ISEC1_DecScaleFactor = 0;
     }
-  else if ( numBits == 24 )
+
+  if ( ISEC1_Year < 0 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(4, "pack 24 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint32_t ival;
-#endif
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      ival = (unsigned long) dval[j];
-#else
-	      ival = (uint32_t) dval[j];
-#endif
-	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
-	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
-	      lGrib[z+2] =  (GRIBPACK)ival;
-	      z += 3;
-	    }
-	}
-      for (j = 0; j < residual; j++) 
+      ISEC1_Year    = -ISEC1_Year;
+      ISEC1_Century = -ISEC1_Century;
+    }
+
+  ISEC1_LocalFLag = 0;
+  if ( pdsLen > 28 )
+    {
+      int localextlen = pdsLen-28;
+
+      if ( localextlen > 4000 )
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	  Warning("PDS larger than 4000 bytes not supported!");
 	}
-      for (j = 0; j < residual; j++) 
+      else
 	{
-	  ival = (uint32_t) dval[j];
-	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
-	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
-	  lGrib[z+2] =  (GRIBPACK)ival;
-	  z += 3;
-	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
-    }
-  else if ( numBits == 32 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint32_t ival;
-#endif
-      unsigned int *igrib = (unsigned int *) (lGrib + z);
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
- {
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  if ( IS_BIGENDIAN() )
+	  ISEC1_LocalFLag = 1;
+
+	  if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
 	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-#ifdef _ARCH_PWR6
-		  *igrib = (unsigned long) dval[j];
-#else
-		  *igrib = (uint32_t) dval[j];
-#endif
-		  igrib++;
-		  z += 4;
-		}
+	      if ( pds[40] == 254 ) 
+                decodePDS_DWD_local_Extension_254(pds, isec1);
+	      else if ( pds[40] == 253 )
+                decodePDS_DWD_local_Extension_253(pds, isec1);
 	    }
-	  else
+	  else if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
+		    (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
+		    (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
 	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-                  ival = (uint32_t) dval[j];
-		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
-		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
-		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
-		  lGrib[z+3] =  (GRIBPACK)ival;
-		  z += 4;
-		}
+	      if ( pds[40] == 1 )
+		decodePDS_ECMWF_local_Extension_1(pds, isec1);
 	    }
-	}
-      for (j = 0; j < residual; j++) 
-	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
-	}
-      if ( IS_BIGENDIAN() )
-	{
-	  for (j = 0; j < residual; j++) 
+	  else if ( ISEC1_CenterID    == 252 && ISEC1_LocalFLag ==  1 )
 	    {
-#ifdef _ARCH_PWR6
-	      *igrib = (unsigned long) dval[j];
-#else
-	      *igrib = (uint32_t) dval[j];
-#endif
-	      igrib++;
-	      z += 4;
+	      if ( pds[40] == 1 )
+		decodePDS_MPIM_local_Extension_1(pds, isec1);	      
 	    }
-	}
-      else
-	{
-          for (j = 0; j < residual; j++) 
+	  else
 	    {
-	      ival = (uint32_t) dval[j];
-	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
-	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
-	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
-	      lGrib[z+3] =  (GRIBPACK)ival;
-	      z += 4;
+	      for ( int i = 0; i < localextlen; i++ )
+                isec1[24+i] = pds[28+i];
 	    }
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
-    }
-  else if ( numBits > 0 && numBits <= 32 )
-    {
-      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
-    }
-  else if ( numBits == 0 )
-    {
-    }
-  else
-    {
-      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  *gz = z;
-#undef __UNROLL_DEPTH_2
+  return pdsLen;
 }
 
-#endif /* T */
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+void gribPrintSec2_double(int *isec0, int *isec2, double *fsec2) {gribPrintSec2DP(isec0, isec2, fsec2);}
+void gribPrintSec3_double(int *isec0, int *isec3, double *fsec3) {gribPrintSec3DP(isec0, isec3, fsec3);}
+void gribPrintSec4_double(int *isec0, int *isec4, double *fsec4) {gribPrintSec4DP(isec0, isec4, fsec4);}
+void gribPrintSec2_float(int *isec0, int *isec2, float *fsec2) {gribPrintSec2SP(isec0, isec2, fsec2);}
+void gribPrintSec3_float(int *isec0, int *isec3, float *fsec3) {gribPrintSec3SP(isec0, isec3, fsec3);}
+void gribPrintSec4_float(int *isec0, int *isec4, float *fsec4) {gribPrintSec4SP(isec0, isec4, fsec4);}
+
 
 #ifdef T
 #undef T
 #endif
-#define T float
+#define T double
 #ifdef T
 
+#include <inttypes.h>
+
+static 
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
+{
+  /* code from wgrib routine BDS_unpack */
+  const unsigned char *bits = igrib;
+  long i;
+  unsigned int tbits = 0;
+  int n_bits = NumBits;
+  int t_bits = 0;
+
+  unsigned jmask = (1U << n_bits) - 1U;
+  for ( i = 0; i < jlend; i++ )
+    {
+      if (n_bits - t_bits > 8)
+	{
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
+	  bits += 2;
+	  t_bits += 16;
+	}
+
+      while ( t_bits < n_bits )
+	{
+	  tbits = (tbits * 256) + *bits++;
+	  t_bits += 8;
+	}
+      t_bits -= n_bits;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
+    }
+  /* at least this vectorizes :) */
+  for ( i = 0; i < jlend; i++ )
+    fpdata[i] = fmin + zscale*fpdata[i];
+}
 
 static
-void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
-				     const T *data, T zref, T factor, size_t *gz)
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
-  size_t i, z = *gz;
-  unsigned int ival;
-  int cbits, jbits;
-  unsigned int c;
-  static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
-    
-  /* code from gribw routine flist2bitstream */
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
 
-  cbits = 8;
-  c = 0;
-  for ( i = packStart; i < datasize; i++ )
+  /* code from wgrib routine BDS_unpack */
+  const unsigned char *bits = igrib;
+  long i;
+  int n_bits = NumBits;
+  int c_bits, j_bits;
+
+  /* older unoptimized code, not often used */
+  c_bits = 8;
+  for ( i = 0; i < jlend; i++ )
     {
-      /* note float -> unsigned int .. truncate */
-      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
-      /*
-	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
-	if ( ival < 0 ) ival = 0;
-      */
-      jbits = numBits;
-      while ( cbits <= jbits ) 
+      double jj = 0.0;
+      j_bits = n_bits;
+      while (c_bits <= j_bits)
 	{
-	  if ( cbits == 8 )
+	  if (c_bits == 8)
 	    {
-	      jbits -= 8;
-	      lGrib[z++] = (ival >> jbits) & 0xFF;
+	      jj = jj * 256.0  + (double) (*bits++);
+	      j_bits -= 8;
 	    }
 	  else
 	    {
-	      jbits -= cbits;
-	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
-	      cbits = 8;
-	      c = 0;
+	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
+	      bits++;
+	      j_bits -= c_bits;
+	      c_bits = 8;
 	    }
 	}
-      /* now jbits < cbits */
-      if ( jbits )
+
+      if (j_bits)
 	{
-	  c = (c << jbits) + (ival & mask[jbits]);
-	  cbits -= jbits;
+	  c_bits -= j_bits;
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
+      fpdata[i] = (T)(fmin + zscale*jj);
     }
-  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
-
-  *gz = z;
 }
 
-
 static
-void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
-				    const T *restrict data, T zref, T factor, size_t *gz)
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
 {
   U_BYTEORDER;
-  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
 
   if ( IS_BIGENDIAN() )
     {
-      for ( size_t i = 0; i < datasize; i++ )
+      for ( size_t i = 0; i < jlend; i++ )
         {
-          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          fpdata[i] = fmin + zscale * sgrib[i];
         }
     }
   else
     {
       uint16_t ui16;
-      for ( size_t i = 0; i < datasize; i++ )
+      for ( size_t i = 0; i < jlend; i++ )
         {
-          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
-          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
         }
     }
-
-  *gz += 2*datasize;
 }
-/*
-static
-void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
-				    const T *restrict data, T zref, T factor, size_t *gz)
-{
-  size_t i, z = *gz;
-  uint16_t ui16;
-  T tmp;
-
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-  for ( i = 0; i < datasize; i++ )
-    {
-      tmp = ((data[i] - zref) * factor + (T)0.5);
-      ui16 = (uint16_t) tmp;
-      lGrib[z  ] = ui16 >>  8;
-      lGrib[z+1] = ui16;
-      z += 2;
-    }
 
-  *gz = z;
-}
-*/
-static
-void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
-			      GRIBPACK *restrict lGrib,
-			      const T *restrict data, 
-			      T zref, T factor, size_t *gz)
+static 
+void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
+			      T fmin, T zscale, T *restrict fpdata)
 {
 #if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
-  uint64_t start_minmax, end_minmax;
+  uint64_t start_decode, end_decode;
 #endif
-  uint32_t ui32;
-  size_t i, z = *gz;
-  T tmp;
 
-  data += packStart;
-  datasize -= packStart;
+  long i;
+#if defined (VECTORCODE)
+  GRIBPACK *lgrib = NULL;
 
-  if      ( numBits ==  8 )
+  if ( numBits%8 == 0 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(2, "pack 8 bit base");
-#endif
-
-#if defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
+      long jlenc = jlend * numBits / 8;
+      if ( jlenc > 0 ) 
 	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-	  lGrib[z  ] = (GRIBPACK)tmp;
-          z++;
-	}
+	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
+	  if ( lgrib == NULL ) SysError("No Memory!");
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
+	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
+	}
     }
-  else if ( numBits == 16 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(3, "pack 16 bit base");
-#elif defined _GET_X86_COUNTER 
-      start_minmax = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      start_minmax = mach_absolute_time();
-#endif
-      if ( sizeof(T) == sizeof(double) )
-      	{
-          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
-        }
-      else
-        {
-          TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
-        }
 
-#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
-#if defined _GET_X86_COUNTER 
-      end_minmax = _rdtsc();
-#elif defined _GET_MACH_COUNTER 
-      end_minmax = mach_absolute_time();
-#endif
-#if defined _ENABLE_AVX
-      printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#elif defined _ENABLE_SSE4_1
-      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#else
-      printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
-#endif  
-#endif
-      
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(3);
-#endif
-    }
-  else if ( numBits == 24 )
+  if ( numBits ==  0 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(4, "pack 24 bit base");
-#endif
-
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
-	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-          ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
-          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
-          lGrib[z+2] =  (GRIBPACK)ui32;
-          z += 3;
-	}
-
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
     }
+  else if ( numBits ==  8 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (int)lgrib[i];
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 16 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 24 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	  	 (int)lgrib[3*i+2]);
+	fpdata[i] = fmin + zscale * dval;
+      }
   else if ( numBits == 32 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits <= 25 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit base");
-#endif
-
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
-#endif
-      for ( i = 0; i < datasize; i++ )
-	{
-	  tmp = ((data[i] - zref) * factor + (T)0.5);
-          ui32 = (uint32_t) tmp;
-          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
-          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
-          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
-          lGrib[z+3] =  (GRIBPACK)ui32;
-          z += 4;
-	}
-
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
-    }
-  else if ( numBits > 0 && numBits <= 32 )
-    {
-      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
     }
-  else if ( numBits == 0 )
+  else if ( numBits > 25 && numBits < 32 )
     {
+      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
     }
   else
     {
       Error("Unimplemented packing factor %d!", numBits);
     }
 
-  *gz = z;
-}
+  if ( lgrib ) Free(lgrib);
 
-static
-void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize, 
-				       GRIBPACK *restrict lGrib,
-				       const T *restrict data, 
-				       T zref, T factor, size_t *gz)
-{
-  U_BYTEORDER;
-  size_t i, j, z = *gz;
-#ifdef _ARCH_PWR6
-#define __UNROLL_DEPTH_2 8
 #else
-#define __UNROLL_DEPTH_2 128
-#endif
-  size_t residual;
-  size_t ofs;
-  T dval[__UNROLL_DEPTH_2];
-
-  data += packStart;
-  datasize -= packStart;
-  residual =  datasize % __UNROLL_DEPTH_2;
-  ofs = datasize - residual;
-
-  // reducing FP operations to single FMA is slowing down on pwr6 ...
-
-  if      ( numBits ==  8 )
+  if ( numBits ==  0 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(2, "pack 8 bit unrolled");
-#endif
-      unsigned char *cgrib = (unsigned char *) (lGrib + z);
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *cgrib++ =  (unsigned long) dval[j];
-#else
-	      *cgrib++ =  (unsigned char) dval[j];
-#endif
-	    }
-	  z += __UNROLL_DEPTH_2;
-	}
-      for (j = 0; j < residual; j++) 
-	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
-	}
-      for (j = 0; j < residual; j++) 
-	{
-#ifdef _ARCH_PWR6
-	  *cgrib++ = (unsigned long) dval[j];
-#else
-	  *cgrib++ = (unsigned char) dval[j];
-#endif
-	}
-      z += residual;
-
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
     }
+  else if ( numBits ==  8 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (int)igrib[i];
+	fpdata[i] = fmin + zscale * dval;
+      }
   else if ( numBits == 16 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(3, "pack 16 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint16_t ival;
-#endif
-      uint16_t *sgrib = (uint16_t *) (lGrib+z);
-
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  if ( IS_BIGENDIAN() )
-	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-#ifdef _ARCH_PWR6
-		  *sgrib++ = (unsigned long) dval[j];
-#else
-		  *sgrib++ = (uint16_t) dval[j];
-#endif
-		}
-	      z += 2*__UNROLL_DEPTH_2;
-	    }
-	  else
-	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-		  ival = (uint16_t) dval[j];
-                  *sgrib++ = gribSwapByteOrder_uint16(ival);
-		}
-	      z += 2*__UNROLL_DEPTH_2;
-	    }
-	}
-      for (j = 0; j < residual; j++) 
-	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
-	}
-      if ( IS_BIGENDIAN() )
-	{
-	  for (j = 0; j < residual; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *sgrib++ = (unsigned long) dval[j];
-#else
-              *sgrib++ = (uint16_t) dval[j];
-#endif
-	    }
-	  z += 2*residual;
-	}
-      else
-	{
-	  for (j = 0; j < residual; j++) 
-	    {
-              ival = (uint16_t) dval[j];
-	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
-	      lGrib[z+1] = (GRIBPACK)ival;
-	      z += 2;
-	    }
-	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(3);
-#endif
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
   else if ( numBits == 24 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 32 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits <= 25 )
+    {
+      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+    }
+  else if ( numBits > 25 && numBits < 32 )
+    {
+      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+    }
+  else
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(4, "pack 24 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint32_t ival;
+      Error("Unimplemented packing factor %d!", numBits);
+    }
 #endif
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      ival = (unsigned long) dval[j];
-#else
-	      ival = (uint32_t) dval[j];
+}
+
+#endif /* T */
+
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+
+#ifdef T
+#undef T
 #endif
-	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
-	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
-	      lGrib[z+2] =  (GRIBPACK)ival;
-	      z += 3;
-	    }
-	}
-      for (j = 0; j < residual; j++) 
+#define T float
+#ifdef T
+
+#include <inttypes.h>
+
+static 
+void TEMPLATE(decode_array_common,T)(const unsigned char *restrict igrib, long jlend, int NumBits, 
+				     T fmin, T zscale, T *restrict fpdata)
+{
+  /* code from wgrib routine BDS_unpack */
+  const unsigned char *bits = igrib;
+  long i;
+  unsigned int tbits = 0;
+  int n_bits = NumBits;
+  int t_bits = 0;
+
+  unsigned jmask = (1U << n_bits) - 1U;
+  for ( i = 0; i < jlend; i++ )
+    {
+      if (n_bits - t_bits > 8)
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
+	  bits += 2;
+	  t_bits += 16;
 	}
-      for (j = 0; j < residual; j++) 
+
+      while ( t_bits < n_bits )
 	{
-	  ival = (uint32_t) dval[j];
-	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
-	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
-	  lGrib[z+2] =  (GRIBPACK)ival;
-	  z += 3;
+	  tbits = (tbits * 256) + *bits++;
+	  t_bits += 8;
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
+      t_bits -= n_bits;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
-  else if ( numBits == 32 )
+  /* at least this vectorizes :) */
+  for ( i = 0; i < jlend; i++ )
+    fpdata[i] = fmin + zscale*fpdata[i];
+}
+
+static
+void TEMPLATE(decode_array_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
+{
+  static const unsigned mask[] = {0,1,3,7,15,31,63,127,255};
+  static const double shift[9]
+    = {1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0};
+
+  /* code from wgrib routine BDS_unpack */
+  const unsigned char *bits = igrib;
+  long i;
+  int n_bits = NumBits;
+  int c_bits, j_bits;
+
+  /* older unoptimized code, not often used */
+  c_bits = 8;
+  for ( i = 0; i < jlend; i++ )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit unrolled");
-#endif
-#ifdef _ARCH_PWR6
-      unsigned long ival;
-#else
-      uint32_t ival;
-#endif
-      unsigned int *igrib = (unsigned int *) (lGrib + z);
-      for ( i = 0; i < datasize - residual; i += __UNROLL_DEPTH_2 ) 
- {
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
-	    }
-	  if ( IS_BIGENDIAN() )
+      double jj = 0.0;
+      j_bits = n_bits;
+      while (c_bits <= j_bits)
+	{
+	  if (c_bits == 8)
 	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-#ifdef _ARCH_PWR6
-		  *igrib = (unsigned long) dval[j];
-#else
-		  *igrib = (uint32_t) dval[j];
-#endif
-		  igrib++;
-		  z += 4;
-		}
+	      jj = jj * 256.0  + (double) (*bits++);
+	      j_bits -= 8;
 	    }
 	  else
 	    {
-	      for (j = 0; j < __UNROLL_DEPTH_2; j++) 
-		{
-                  ival = (uint32_t) dval[j];
-		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
-		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
-		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
-		  lGrib[z+3] =  (GRIBPACK)ival;
-		  z += 4;
-		}
+	      jj = (jj * shift[c_bits]) + (double) (*bits & mask[c_bits]);
+	      bits++;
+	      j_bits -= c_bits;
+	      c_bits = 8;
 	    }
 	}
-      for (j = 0; j < residual; j++) 
+
+      if (j_bits)
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	  c_bits -= j_bits;
+	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
 	}
-      if ( IS_BIGENDIAN() )
-	{
-	  for (j = 0; j < residual; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *igrib = (unsigned long) dval[j];
-#else
-	      *igrib = (uint32_t) dval[j];
+      fpdata[i] = (T)(fmin + zscale*jj);
+    }
+}
+
+static
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
+{
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
+
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
+        }
+    }
+}
+
+static 
+void TEMPLATE(decode_array,T)(const unsigned char *restrict igrib, long jlend, int numBits, 
+			      T fmin, T zscale, T *restrict fpdata)
+{
+#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
+  uint64_t start_decode, end_decode;
 #endif
-	      igrib++;
-	      z += 4;
-	    }
-	}
-      else
+
+  long i;
+#if defined (VECTORCODE)
+  GRIBPACK *lgrib = NULL;
+
+  if ( numBits%8 == 0 )
+    {
+      long jlenc = jlend * numBits / 8;
+      if ( jlenc > 0 ) 
 	{
-          for (j = 0; j < residual; j++) 
-	    {
-	      ival = (uint32_t) dval[j];
-	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
-	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
-	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
-	      lGrib[z+3] =  (GRIBPACK)ival;
-	      z += 4;
-	    }
+	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
+	  if ( lgrib == NULL ) SysError("No Memory!");
+
+	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
     }
-  else if ( numBits > 0 && numBits <= 32 )
+
+  if ( numBits ==  0 )
     {
-      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
     }
-  else if ( numBits == 0 )
+  else if ( numBits ==  8 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (int)lgrib[i];
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 16 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((int)lgrib[2*i  ] <<  8) +  (int)lgrib[2*i+1]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 24 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
+	  	 (int)lgrib[3*i+2]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 32 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (((unsigned int)lgrib[4*i  ] << 24) + ((unsigned int)lgrib[4*i+1] << 16) +
+		((unsigned int)lgrib[4*i+2] <<  8) +  (unsigned int)lgrib[4*i+3]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits <= 25 )
+    {
+      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+    }
+  else if ( numBits > 25 && numBits < 32 )
     {
+      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
     }
   else
     {
       Error("Unimplemented packing factor %d!", numBits);
     }
 
-  *gz = z;
-#undef __UNROLL_DEPTH_2
+  if ( lgrib ) Free(lgrib);
+
+#else
+  if ( numBits ==  0 )
+    {
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
+    }
+  else if ( numBits ==  8 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (int)igrib[i];
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 16 )
+    {
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
+    }
+  else if ( numBits == 24 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
+                     (int)igrib[3*i+2]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits == 32 )
+    for ( i = 0; i < jlend; i++ )
+      {
+	T dval = (T)(((unsigned int)igrib[4*i  ] << 24) + ((unsigned int)igrib[4*i+1] << 16) +
+                     ((unsigned int)igrib[4*i+2] <<  8) +  (unsigned int)igrib[4*i+3]);
+	fpdata[i] = fmin + zscale * dval;
+      }
+  else if ( numBits <= 25 )
+    {
+      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+    }
+  else if ( numBits > 25 && numBits < 32 )
+    {
+      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+    }
+  else
+    {
+      Error("Unimplemented packing factor %d!", numBits);
+    }
+#endif
 }
 
 #endif /* T */
@@ -18254,599 +15976,818 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #define T double
 #ifdef T
 
-/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
-static
-void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
+static 
+int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
 {
-  long z = *gribLen;
-  int exponent, mantissa;
-  long i;
-  int ival;
-  int pvoffset = 0xFF;
-  int gdslen = 32;
-  unsigned lonIncr, latIncr;
+  // int imisng = 0;
+  bool ReducedGrid = false, VertCoorTab = false;
+#if defined (VECTORCODE)
+  unsigned char *igrib;
+  GRIBPACK *lgrib = NULL;
+  size_t lGribLen = 0;
+#endif
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
+  *numGridVals = 0;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
+  memset(isec2, 0, 22*sizeof(int));
 
-  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
+  unsigned gdsLen = GDS_Len;
 
-  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
+  unsigned ipvpl = GDS_PVPL;
+  if ( ipvpl == 0 ) ipvpl = 0xFF;
 
-  gdslen += ISEC2_NumVCP * 4;
+  if ( ipvpl != 0xFF )
+    { /* Either vct or reduced grid */
+      if ( GDS_NV != 0 )
+	{ /* we have vct */
+	  VertCoorTab = true;
+	  unsigned ipl =  4*GDS_NV + ipvpl - 1;
+	  if ( ipl < gdsLen ) ReducedGrid = true;
+	}
+      else
+	{
+	  VertCoorTab = false;
+	  ReducedGrid = true;
+	}
+      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
+    }
+ 
+  if ( ISEC0_GRIB_Version == 0 )
+    {
+      VertCoorTab = (gdsLen - 32) > 0;
+    }
+  
+  if ( ReducedGrid )
+    {
+      unsigned locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
+      unsigned jlenl = (gdsLen - locnl)  >> 1;
+      if ( jlenl == GDS_NumLat )
+	{
+	  *numGridVals = 0;
+	  ISEC2_Reduced = true;
+	  for ( unsigned i = 0; i < jlenl; i++ )
+	    {
+	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
+	      *numGridVals += ISEC2_RowLon(i);
+	    }
+	}
+      else
+	{
+	  ReducedGrid = false;
+	}
+    }
 
-  Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
-  Put1Byte(ISEC2_NumVCP);       /*  3    NV */
-  Put1Byte(pvoffset);           /*  4    PV */
-  Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
+  ISEC2_GridType = GDS_GridType;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
+  /*
+     Gaussian grid definition.
+  */
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
+       ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
+       ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
     {
-      Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
-      Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
-      Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
-      Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
-      Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
-      PutnZero(18);             /* 14-31 reserved                 */
+      ISEC2_NumLat    = GDS_NumLat;
+      if ( ! ReducedGrid )
+	{
+	  ISEC2_NumLon = GDS_NumLon;
+	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+	}
+      ISEC2_FirstLat  = GDS_FirstLat;
+      ISEC2_FirstLon  = GDS_FirstLon;
+      ISEC2_ResFlag   = GDS_ResFlag;
+      ISEC2_LastLat   = GDS_LastLat;
+      ISEC2_LastLon   = GDS_LastLon;
+      ISEC2_LonIncr   = GDS_LonIncr;
+
+      ISEC2_NumPar    = GDS_NumPar;
+      ISEC2_ScanFlag  = GDS_ScanFlag;
+      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+	{
+	  ISEC2_LatSP     = GDS_LatSP;
+	  ISEC2_LonSP     = GDS_LonSP;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
+	}
+      /*
+	if ( Lons != Longitudes || Lats != Latitudes )
+	Error("Latitude/Longitude Conflict");
+      */
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
     {
-      Put2Byte(ISEC2_GME_NI2);
-      Put2Byte(ISEC2_GME_NI3);
-      Put3Byte(ISEC2_GME_ND);
-      Put3Byte(ISEC2_GME_NI);
-      Put1Byte(ISEC2_GME_AFlag);
-      Put3Int(ISEC2_GME_LatPP);
-      Put3Int(ISEC2_GME_LonPP);
-      Put3Int(ISEC2_GME_LonMPL);
-      Put1Byte(ISEC2_GME_BFlag);
-      PutnZero(5);
+      // iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
+    {
+      // iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
     }
   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
     {
-      Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
-
-      Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
-      Put3Int(ISEC2_FirstLat);
-      Put3Int(ISEC2_FirstLon);
-      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
-      Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
-      Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
-      Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
-      Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
-      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
-      Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */  
-      Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
-      Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */  
-      Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
-      PutnZero(2);                     /* 34-41 */
+      ISEC2_NumLon    = GDS_NumLon;
+      ISEC2_NumLat    = GDS_NumLat;
+      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+      ISEC2_FirstLat  = GDS_FirstLat;
+      ISEC2_FirstLon  = GDS_FirstLon;
+      ISEC2_ResFlag   = GDS_ResFlag;
+      ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
+      ISEC2_Lambert_dx    = GDS_Lambert_dx;
+      ISEC2_Lambert_dy    = GDS_Lambert_dy;
+      ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
+      ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
+      ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
+      ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
+      ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
+      ISEC2_ScanFlag      = GDS_ScanFlag;
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
     {
-      int numlon;
-      if ( ISEC2_Reduced )
-	numlon = 0xFFFF;
-      else
-	numlon = ISEC2_NumLon;
+      ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
+      ISEC2_PentaK  = GDS_PentaK;
+      ISEC2_PentaM  = GDS_PentaM;
+      ISEC2_RepType = GDS_RepType;
+      ISEC2_RepMode = GDS_RepMode;
+      *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
+      isec2[ 6] = 0;
+      isec2[ 7] = 0;
+      isec2[ 8] = 0;
+      isec2[ 9] = 0;
+      isec2[10] = 0;
+      // iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+    {
+      ISEC2_GME_NI2    = GDS_GME_NI2;
+      ISEC2_GME_NI3    = GDS_GME_NI3;
+      ISEC2_GME_ND     = GDS_GME_ND;
+      ISEC2_GME_NI     = GDS_GME_NI;
+      ISEC2_GME_AFlag  = GDS_GME_AFlag;
+      ISEC2_GME_LatPP  = GDS_GME_LatPP;
+      ISEC2_GME_LonPP  = GDS_GME_LonPP;
+      ISEC2_GME_LonMPL = GDS_GME_LonMPL;
+      ISEC2_GME_BFlag  = GDS_GME_BFlag;
+      *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
+      // iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
+    }
+  else
+    {
+      static bool lwarn = true;
+      ISEC2_NumLon = GDS_NumLon;
+      ISEC2_NumLat = GDS_NumLat;
+      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+      if ( lwarn )
+        {
+          lwarn = false;
+          Message("GRIB gridtype %d unsupported", ISEC2_GridType);
+        }
+    }
 
-      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
+  /*    vertical coordinate parameters for hybrid levels.     */
+  /*    get number of vertical coordinate parameters, if any. */
 
-      Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
-      Put3Int(ISEC2_FirstLat);
-      Put3Int(ISEC2_FirstLon);
-      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
-      Put3Int(ISEC2_LastLat);
-      Put3Int(ISEC2_LastLon);
-      if ( ISEC2_ResFlag == 0 )
+  ISEC2_NumVCP = 0;
+
+  isec2[17] = 0;
+  isec2[18] = 0;
+
+  if ( VertCoorTab )
+    {
+      int locnv;
+      if ( ISEC0_GRIB_Version  == 0 )
 	{
-	  lonIncr = 0xFFFF;
-	  latIncr = 0xFFFF;
+	  locnv = 32;
+	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
 	}
       else
 	{
-	  lonIncr = (unsigned)ISEC2_LonIncr;
-	  latIncr = (unsigned)ISEC2_LatIncr;
+	  locnv = GDS_PVPL - 1;
+	  ISEC2_NumVCP = GDS_NV;
 	}
-      Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
-      if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
-	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
-      else
-	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
-
-      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
-      PutnZero(4);                     /* 28-31 reserved                 */
+#if defined (SX)
+      lGribLen = 4*ISEC2_NumVCP;	      
+      lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
 
-      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+      igrib = &gds[locnv];
+      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
-	  Put3Int(ISEC2_LatSP);
-	  Put3Int(ISEC2_LonSP);
-	  Put1Real((double)(FSEC2_RotAngle));
+	  int iexp  = lgrib[4*i];
+	  int imant = GET_UINT3(lgrib[4*i+1], lgrib[4*i+2], lgrib[4*i+3]);
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
 	}
-    }
-  else
-    {
-      Error("Unsupported grid type %d", ISEC2_GridType);
-    }
 
-#if defined (SX)
-#pragma vdir novector     /* vectorization gives wrong results on NEC */
+      Free(lgrib);
+#else
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
+	{
+	  int iexp  = gds[locnv+4*i];
+	  int imant = GET_UINT3(gds[locnv+4*i+1], gds[locnv+4*i+2], gds[locnv+4*i+3]);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
+	}
 #endif
-  for ( i = 0; i < ISEC2_NumVCP; ++i )
-    {
-      Put1Real((double)(fsec2[10+i]));
     }
 
-  if ( ISEC2_Reduced )
-    for ( i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
-
-  *gribLen = z;
+  return gdsLen;
 }
 
-/* GRIB BLOCK 3 - BIT MAP SECTION */
+#define ldexp_double ldexp
+#define ldexp_float  ldexpf
+
 static
-void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
+void TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
+                           T *fsec4, int fsec4len, int dfunc, int bdsLen, int numGridVals, int *iret)
 {
-  GRIBPACK *bitmap;
-  long bitmapSize;
-  long imaskSize;
-  long i;
-  long bmsLen, bmsUnusedBits;
-  long fsec4size;
-  long z = *gribLen;
-#if defined (VECTORCODE)
-  unsigned int *imask;
-#endif
-  static int lmissvalinfo = 1;
-  /*  unsigned int c, imask; */
+  int ioff = 0;
+  unsigned zoff;
+  unsigned bds_head = 11;
+  T zscale = 0.;
+  T fmin = 0.;
+  T *fpdata = fsec4;
+  extern int CGRIBEX_Fix_ZSE;
 
-  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
-    {
-      lmissvalinfo = 0;
-      Message("Missing value = NaN is unsupported!");
-    }
+  *iret = 0;
+  unsigned char *igrib = bds;
 
-  bitmapSize = ISEC4_NumValues;
-  imaskSize = ((bitmapSize+7)>>3)<<3;
-  bitmap = &lGrib[z+6];
-  fsec4size = 0;
+  memset(isec4, 0, 42*sizeof(int));
 
-#if defined (VECTORCODE)
-  imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
-  memset(imask, 0, imaskSize*sizeof(int));
+  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-  for ( i = 0; i < bitmapSize; i++ )
-    {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
-	{
-	  data[fsec4size++] = data[i];
-	  imask[i] = 1;
-	}
-    }
+  int bds_flag = BDS_Flag;
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-  for ( i = 0; i < imaskSize/8; i++ )
-    {
-      bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
-	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
-	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
-	          (imask[i*8+6] << 1) | (imask[i*8+7]);
-    }
+  /* 0------- grid point           */
+  /* 1------- spherical harmonics  */
 
-  Free(imask);
-#else
-  for ( i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
+  bool lspherc = (bds_flag >> 7)&1;
 
-  for ( i = 0; i < bitmapSize; i++ )
-    {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
-	{
-	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
-	}
-    }
-#endif
+  if ( lspherc ) isec4[2] = 128;
+  else           isec4[2] = 0;
 
-  bmsLen = imaskSize/8 + 6;
-  bmsUnusedBits = imaskSize - bitmapSize;
+  /* -0------  simple packing */
+  /* -1------ complex packing */
 
-  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
-  Put1Byte(bmsUnusedBits);
-  Put2Byte(0);
+  bool lcomplex = (bds_flag >> 6)&1;
 
-  *gribLen += bmsLen;
+  if ( lcomplex ) isec4[3] = 64;
+  else            isec4[3] =  0;
 
-  *datasize = fsec4size;
-}
+  /* ---0---- No additional flags */
+  /* ---1---- No additional flags */
 
-/* GRIB BLOCK 4 - BINARY DATA SECTION */
-static
-int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
-			  long *datstart, long *datsize, int code)
-{
-  /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
-  /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
+  bool lcompress = (bds_flag >> 4)&1;
 
-  size_t z = (size_t)*gribLen;
-  long i;
-  int numBits;
-  int ival;
-  long PackStart = 0, Flag = 0;
-  int binscale = 0;
-  int bds_head = 11;
-  int bds_ext = 0;
-  /* ibits = BitsPerInt; */
-  int exponent, mantissa;
-  int lspherc = FALSE;
-  int isubset = 0, itemp = 0, itrunc = 0;
-  T factor = 1, fmin, fmax;
-  const double jpepsln = 1.0e-12; /* -----> tolerance used to check equality     */
-                                  /*        of floating point numbers - needed   */
-		                  /*        on some platforms (eg vpp700, linux) */
-  extern int CGRIBEX_Const;       /* 1: Don't pack constant fields on regular grids */
+  if ( lcompress )
+    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
+  else
+    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
 
-  if ( isec2 )
-    {
-      /* If section 2 is present, it says if data is spherical harmonic */
+  /* ----++++ number of unused bits at end of section) */
 
-      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
-                   isec2[0] == 70 || isec2[0] == 80 );
+  int bds_ubits = bds_flag & 0xF;
+  
+  /* scale factor (2 bytes) */;
 
-      if ( lspherc )
-	isec4[2] = 128;
-      else
-	isec4[2] = 0;
-    }
-  else
-    {
-      /* Section 4 says if it's spherical harmonic data.. */
+  int jscale = BDS_BinScale;
 
-      lspherc = ( isec4[2] == 128 );
-    }
+  /* check for missing data indicators. */
 
-  /* Complex packing supported for spherical harmonics. */
+  int iexp  = bds[ 6];
+  int imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
 
-  int lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
-                 ( lspherc && isec2 && ( isec2[5] == 2 ) );
+  int imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
 
-  /* Check input specification is consistent */
+  /* convert reference value and scale factor. */
 
-  if ( lcomplex && isec2 )
+  if ( ! (dfunc == 'J') && imiss == 0 )
     {
-      if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
-	{
-	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
-	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
-	  return (807);
-	}
-      else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
-	{
-	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
-	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
-	  return (807);
-        }
-      else if ( lcomplex )
-	{
-	  /*
-	    Truncation of full spectrum, which is supposed triangular,
-	    has to be diagnosed. Define also sub-set truncation.
-	  */
-	  isubset = isec4[17];
-	  /* When encoding, use the total number of data. */
-	  itemp   = isec4[0];
-	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
-	}
+      fmin = (T)BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
     }
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double) decscale);
-      for ( i = 0; i < datasize; ++i ) data[i] *= scale;
-    }
+  /* get number of bits in each data value. */
+
+  ISEC4_NumBits = BDS_NumBits;
+
+  /* octet number of start of packed data */
+  /* calculated from start of block 4 - 1 */
+
+  unsigned locnd = zoff + bds_head;
+
+  /* if data is in spherical harmonic form, distinguish   */
+  /* between simple/complex packing (lcomplex = 0/1)      */
 
   if ( lspherc )
     {
-      if ( lcomplex )
+      if ( !lcomplex )
 	{
-	  int jup, ioff;
-	  jup  = isubset;
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
-	  PackStart = ioff;
-	  Flag = 192;
+	  /*    no unpacked binary data present */
+	  /*    octet number of start of packed data */
+	  /*    calculated from start of block 4 - 1 */
+
+	  ioff   = 1;
+	  locnd += 4*ioff;  /* RealCoef */
+
+	  /*    get real (0,0) coefficient in grib format and     */
+	  /*    convert to floating point.                        */
+
+	  if ( dfunc != 'J' )
+	    {
+	      if ( imiss ) *fpdata++ = 0.0;
+	      else         *fpdata++ = (T)BDS_RealCoef;
+	    }
 	}
-      else
+      else /* complex packed spherical harmonics */
 	{
-	  bds_ext = 4;
-	  PackStart = 1;
-	  Flag = 128;
-	}
-    }
+	  isec4[15] = BDS_PackData;
+	  /*    scaling factor */
+	  isec4[16] = BDS_Power;
 
-  *datstart = bds_head + bds_ext;
+	  /*    pentagonal resolution parameters of the */
+	  /*    unpacked section of data field          */
 
-  int nbpv = numBits = ISEC4_NumBits;
+	  int jup = bds[zoff+15];
+	  int kup = bds[zoff+16];
+	  int mup = bds[zoff+17];
 
-  if ( lspherc && lcomplex )
+	  isec4[zoff+17] = jup;
+	  isec4[zoff+18] = kup;
+	  isec4[zoff+19] = mup;
+
+	  /*    unpacked binary data */
+
+	  locnd += 4; /* 2 + power */
+	  locnd += 3; /* j, k, m   */
+	  ioff   = (jup+1)*(jup+2);
+
+	  if ( dfunc != 'J' )
+	    for ( int i = 0; i < ioff; i++ )
+	      {
+		if ( imiss )
+		  *fpdata++ = 0.0;
+		else
+		  {
+		    int iexp  = (bds[locnd+4*i]);
+		    int imant = GET_UINT3(bds[locnd+4*i+1], bds[locnd+4*i+2], bds[locnd+4*i+3]);
+		    *fpdata++ = (T)decfp2(iexp,imant);
+		  }
+	      }
+	  
+	  locnd += 4*ioff;  /* RealCoef */
+	}
+    }
+  else
     {
-      int pcStart, pcScale;
-      pcStart = isubset;
-      pcScale = isec4[16];
-      TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
+      if ( lcomplex )
+	{
+	  *iret = 1999;
+	  gprintf(__func__, " Second order packed grids unsupported!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
+	}
     }
 
-  fmin = fmax = data[PackStart];
+  /* Decode data values to floating point and store in fsec4.  */
+  /* First calculate the number of data values.                */
+  /* Take into account that spherical harmonics can be packed  */
+  /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
+  int jlend = bdsLen - locnd;
 
-  double zref = (double)fmin;
+  if ( ISEC4_NumBits == 0 )
+    {
+      if ( jlend > 1 )
+	{
+	  *iret = 2001;
+	  gprintf(__func__, " Number of bits per data value = 0!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
+	}
 
+      if ( numGridVals == 0 )
+	{
+	  *iret = 2002;
+	  gprintf(__func__, " Constant field unsupported for this grid type!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
+	}
 
-  if ( CGRIBEX_Const && !lspherc )
+      jlend = numGridVals;
+      jlend -= ioff;
+    }
+  else
     {
-      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
+      jlend = (int) (((long)jlend*8 - bds_ubits) / ISEC4_NumBits);
     }
 
+  ISEC4_NumValues        = jlend + ioff;
+  ISEC4_NumNonMissValues = 0;
 
-  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  blockLength += blockLength & 1;
-
-  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  if ( lcompress )
+    {
+      size_t len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-  Flag += unused_bits;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
+      if ( lspherc ) ISEC4_NumValues += lcomplex ? ioff : 1;
+    }
 
-  /*
-    Adjust number of bits per value if full integer length to
-    avoid hitting most significant bit (sign bit).
-  */
-  /* if( nbpv == ibits ) nbpv = nbpv - 1; */
-  /*
-    Calculate the binary scaling factor to spread the range of
-    values over the number of bits per value.
-    Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floats
-    as a guideline).           
-  */
-  double range = fabs(fmax - fmin);
+  if ( dfunc == 'J' ) return;
 
-  if ( fabs(fmin) < FLT_MIN ) fmin = 0;
-  /*
-    Have to allow tolerance in comparisons on some platforms
-    (eg vpp700 and linux), such as 0.9999999999999999 = 1.0,
-    to avoid clipping ranges which are a power of 2.
-  */
-  if ( range <= jpepsln )
-    {
-      binscale = 0;
-    }
-  else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
+  /* check length of output array. */
+  
+  if ( ISEC4_NumValues > fsec4len )
     {
-      binscale = 0;
+      *iret = 710;
+      gprintf(__func__, " Output array too small. Length = %d", fsec4len);
+      gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
+      gprintf(__func__, " Return code =  %d", *iret);
+      return;
     }
-  else if ( fabs(range-1.0) <= jpepsln )
+
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
+  else
     {
-      binscale = 1 - nbpv;
+      igrib += locnd;
+
+      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
     }
-  else if ( range > 1.0 )
+
+  if ( lspherc && lcomplex )
     {
-      double rangec = range + jpepsln,
-        p2 = 2.0;
-      int jloop = 1;
-      while ( jloop < 128 && p2 <= rangec )
-        {
-          p2 *= 2.0;
-          ++jloop;
-        }
-      if (jloop < 128)
-        binscale = jloop - nbpv;
-      else
-        {
-          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-          return (707);
-        }
+      int pcStart = isec4[19], pcScale = isec4[16];
+      TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
+      TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
     }
-  else
+
+  if ( CGRIBEX_Fix_ZSE )  /* Fix ZeroShiftError of simple packed spherical harmonics */
+    if ( lspherc && !lcomplex )
+      {
+        /* 20100705: Fix ZeroShiftError - Edi Kirk */
+	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
+	  {
+	    T zserr = fsec4[1];
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	  }
+      }
+
+  if ( decscale )
     {
-      double rangec = range - jpepsln, p05 = 0.5;
-      int jloop = 1;
-      while ( jloop < 127 && p05 >= rangec )
-	{
-          p05 *= 0.5;
-          jloop++;
-	}
-      if ( jloop < 127 )
-	{
-	  binscale = 1 - jloop - nbpv;
-	}
-      else
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
+      T scale = (T) pow(10.0, (double)-decscale);
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
+}
 
-  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
-  if ( binscale != 0 )
-    {
-      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
+void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
+			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
+			     int kleng, int *kword, int dfunc, int *iret)
+{
+  UCHAR *gds = NULL, *bms = NULL;
+  int gdsLen = 0, bmsLen = 0;
+  int bitmapSize = 0;
+  int imaskSize = 0;
+  bool ldebug = false, l_iorj = false;
+  bool lsect2 = false, lsect3 = false;
+  int numGridVals = 0;
+  static bool lmissvalinfo = true;
 
-      factor = (T)intpow2(-binscale);
-    }
+  UNUSED(kleng);
 
-  ref2ibm(&zref, BitsPerInt);
+  *iret = 0;
 
-  Put3Byte(blockLength);      /*  0-2 Length of Block 4        */
-  Put1Byte(Flag);             /*  3   Flag & Unused bits       */
-  if ( binscale < 0 ) binscale = 32768 - binscale;
-  Put2Byte(binscale);         /*  4-5 Scale factor             */
-  Put1Real(zref);             /*  6-9 Reference value          */
-  Put1Byte(nbpv);             /*   10 Packing size             */
+  grsdef();
 
-  if ( lspherc )
-    {
-      if ( lcomplex )
-	{
-	  int jup = isubset;
-	  int ioff = (int)z + bds_ext;
-	  if ( ioff > 0xFFFF ) ioff = 0;
-	  Put2Byte(ioff);
-	  Put2Int(isec4[16]);
-	  Put1Byte(jup);
-	  Put1Byte(jup);
-	  Put1Byte(jup);
-	  for ( i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
-	}
-      else
-	{
-	  Put1Real((double)(data[0]));
-	}
-    }
+  ISEC2_Reduced = false;
+
+  // ----------------------------------------------------------------
+  // IS Indicator Section (Section 0)
+  // ----------------------------------------------------------------
+  UCHAR *is = (UCHAR *) &kgrib[0];
+  int isLen = decodeIS(is, isec0, iret);
+
+  int gribLen = ISEC0_GRIB_Len;
+
+  /*
+    When decoding or calculating length, previous editions
+    of the GRIB code must be taken into account.
+
+    In the table below, covering sections 0 and 1 of the GRIB
+    code, octet numbering is from the beginning of the GRIB
+    message;
+    * indicates that the value is not available in the code edition;
+    R indicates reserved, should be set to 0;
+    Experimental edition is considered as edition -1.
+
+    GRIB code edition -1 has fixed length of 20 octets for
+    section 1, the length not included in the message.
+    GRIB code edition 0 has fixed length of 24 octets for
+    section 1, the length being included in the message.
+    GRIB code edition 1 can have different lengths for section
+    1, the minimum being 28 octets, length being included in
+    the message.
+
+                                         Octet numbers for code
+                                                  editions
+
+                 Contents.                   -1      0      1
+                 ---------                ----------------------
+       Letters GRIB                          1-4    1-4    1-4
+       Total length of GRIB message.          *      *     5-7
+       GRIB code edition number               *      *      8
+       Length of Section 1.                   *     5-7    9-11
+       Reserved octet (R).                    *      8(R)   *
+       Version no. of Code Table 2.           *      *     12
+       Identification of centre.              5      9     13
+       Generating process.                    6     10     14
+       Grid definition .                      7     11     15
+       Flag (Code Table 1).                   8     12     16
+       Indicator of parameter.                9     13     17
+       Indicator of type of level.           10     14     18
+       Height, pressure etc of levels.      11-12  15-16  19-20
+       Year of century.                      13     17     21
+       Month.                                14     18     22
+       Day.                                  15     19     23
+       Hour.                                 16     20     24
+       Minute.                               17     21     25
+       Indicator of unit of time.            18     22     26
+       P1 - Period of time.                  19     23     27
+       P2 - Period of time                  20(R)   24     28
+       or reserved octet (R).
+       Time range indicator.                21(R)   25     29
+       or reserved octet (R).
+       Number included in average.       22-23(R)  26-27  30-31
+       or reserved octet (R).
+       Number missing from average.         24(R)  28(R)   32
+       or reserved octet (R).
+       Century of data.                       *      *     33
+       Designates sub-centre if not 0.        *      *     34
+       Decimal scale factor.                  *      *    35-36
+       Reserved. Set to 0.                    *      *    37-48
+       (Need not be present)
+       For originating centre use only.       *      *    49-nn
+       (Need not be present)
 
-  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
+    Identify which GRIB code edition is being decoded.
 
-#if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
-#else
-  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
-#endif
+    In GRIB edition 1, the edition number is in octet 8.
+    In GRIB edition 0, octet 8 is reserved and set to 0.
+    In GRIB edition -1, octet 8 is a flag field and can have a
+    a valid value of 0, 1, 2 or 3.
 
-  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
+    However, GRIB edition number 0 has a fixed
+    length of 24, included in the message, for section 1, so
+    if the value extracted from octets 5-7 is 24 and that from
+    octet 8 is 0, it is safe to assume edition 0 of the code.
 
-  *gribLen = (long)z;
+  */
+  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
+    {
+      // Set length of GRIB message to missing data value.
+      ISEC0_GRIB_Len = 0;
+    }
 
-  return (0);
-}
+  // ----------------------------------------------------------------
+  // PDS Product Definition Section (Section 1)
+  // ----------------------------------------------------------------
+  UCHAR *pds = is + isLen;
+  int pdsLen = decodePDS(pds, isec0, isec1);
 
+  // ----------------------------------------------------------------
+  // GDS Grid Description Section (Section 2)
+  // ----------------------------------------------------------------
+  bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  if ( gdsIncluded )
+    {
+      gds = is + isLen + pdsLen;
+      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
+    }
 
-void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
-			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
-			     int kleng, int *kword, int efunc, int *kret)
-{
-  long gribLen = 0; /* Counter of GRIB length for output */
-  long isLen, pdsLen;
-  GRIBPACK *lpds;
-  unsigned char *CGrib;
-  long fsec4size = 0;
-  int bmsIncluded;
-  GRIBPACK *lGrib;
-  long datstart, datsize, bdsstart;
-  int status = 0;
+  // ----------------------------------------------------------------
+  // BMS Bit-Map Section Section (Section 3)
+  // ----------------------------------------------------------------
+  isec3[0] = 0;
+  bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  if ( bmsIncluded )
+    {
+      bms = is + isLen + pdsLen + gdsLen;
+      bmsLen = BMS_Len;
 
-  UNUSED(isec3);
-  UNUSED(efunc);
+      imaskSize = (bmsLen - 6)<<3;
+      bitmapSize = imaskSize - BMS_UnusedBits;
+    }
 
-  grsdef();
+  // ----------------------------------------------------------------
+  // BDS Binary Data Section (Section 4)
+  // ----------------------------------------------------------------
+  UCHAR *bds = is + isLen + pdsLen + gdsLen + bmsLen;
+  int bdsLen = BDS_Len;
+  /*
+    If a very large product, the section 4 length field holds
+    the number of bytes in the product after section 4 upto
+    the end of the padding bytes.
+    This is a fixup to get round the restriction on product lengths
+    due to the count being only 24 bits. It is only possible because
+    the (default) rounding for GRIB products is 120 bytes.
+  */
+  if ( gribLen > JP23SET && bdsLen <= 120 )
+    {
+      gribLen &= JP23SET;
+      gribLen *= 120;
+      ISEC0_GRIB_Len = gribLen;
+      bdsLen = correct_bdslen(bdsLen, gribLen, isLen+pdsLen+gdsLen+bmsLen);
+    }
+  TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
+                        fsec4, fsec4len, dfunc, bdsLen, numGridVals, iret);
 
-  CGrib = (unsigned char *) kgrib;
+  if ( *iret != 0 ) return;
 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  ISEC4_NumNonMissValues = ISEC4_NumValues;
 
-  /* set max header len */
-  size_t len = 16384;
+  if ( bitmapSize > 0 )
+    {
+      if ( dfunc != 'L' && dfunc != 'J' )
+	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+	  {
+	    lmissvalinfo = false;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
+	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	  }
 
-  /* add data len */
-  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
+      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
+      ISEC4_NumValues = bitmapSize;
 
-  len += numBytes*(size_t)klenp;
+      if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
+	{
+	  GRIBPACK bitmap;
+	  /*
+	  unsigned char *bitmap;
+	  bitmap = BMS_Bitmap;
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
+	    {
+	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
+		fsec4[i] = fsec4[--j];
+	      else
+		fsec4[i] = FSEC3_MissVal;
+	    }
+	  */
 
-  /* add bitmap len */
-  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
-  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
-  if ( lGrib == NULL ) SysError("No Memory!");
+	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
+	  GRIBPACK *pbitmap = imask;
 #else
-  lGrib = CGrib;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
-  isLen = 8;
-  encodeIS(lGrib, &gribLen);
-  lpds = &lGrib[isLen];
-  pdsLen = getPdsLen(isec1);
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
+	    {
+	      bitmap = pbitmap[i];
+	      imask[i*8+0] = 1 & (bitmap >> 7);
+	      imask[i*8+1] = 1 & (bitmap >> 6);
+	      imask[i*8+2] = 1 & (bitmap >> 5);
+	      imask[i*8+3] = 1 & (bitmap >> 4);
+	      imask[i*8+4] = 1 & (bitmap >> 3);
+	      imask[i*8+5] = 1 & (bitmap >> 2);
+	      imask[i*8+6] = 1 & (bitmap >> 1);
+	      imask[i*8+7] = 1 & (bitmap);
+	    }
 
-  encodePDS(lpds, pdsLen,  isec1);
-  gribLen += pdsLen;
-  /*
-  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
-    {
-      static int lwarn_cplx = TRUE;
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
+	    if ( imask[i] ) j++;
 
-      if ( lwarn_cplx )
-	Message("Complex packing of spectral data unsupported, using simple packing!");
+	  if ( ISEC4_NumNonMissValues != j )
+	    {
+	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
+		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
+			j, ISEC4_NumNonMissValues);
 
-      isec2[5] = 1;
-      isec4[3] = 0;
+	      ISEC4_NumNonMissValues = j;
+	    }
 
-      lwarn_cplx = FALSE;
-    }
-  */
-  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  if ( bmsIncluded )
-    {
-      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
-    }
-  else
-    {
-      fsec4size = ISEC4_NumValues;
+	  if ( dfunc != 'J' )
+	    {
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
+		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
+	    }
+
+	  Free(imask);
+	}
     }
 
-  bdsstart = gribLen;
-  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
-				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
-  if ( status )
+  if ( ISEC2_Reduced )
     {
-      *kret = status;
-      return;
+      int nvalues = 0;
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
+	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
+
+      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
+      // if ( dlon < 0 ) dlon += 360000;
+	  
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
+      //printf("nlat %d  nlon %d \n", nlat, nlon);
+      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
+
+      if ( dfunc == 'R' && *iret == -801 )
+	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
+		ISEC4_NumValues, nvalues);
+      
+      if ( dfunc == 'R' && *iret != -801 )
+	{
+	  ISEC2_Reduced = 0;
+	  ISEC2_NumLon = nlon;
+	  ISEC4_NumValues = nlon*nlat;
+
+	  lsect3 = bitmapSize > 0;
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
+	
+	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
+	      
+	  if ( bitmapSize > 0 )
+	    {
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
+		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
+		  
+	      ISEC4_NumNonMissValues = j;
+	    }
+	}
     }
 
-  encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
-    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
+  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
+  int esLen = 4;
+  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
-#if defined (VECTORCODE)
-  if ( (size_t) gribLen > len )
-    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
+  if ( ISEC0_GRIB_Len )
+    if ( ISEC0_GRIB_Len < gribLen )
+      Warning("Inconsistent length of GRIB message (grib_message_size=%d < grib_record_size=%d)!", ISEC0_GRIB_Len, gribLen);
 
-  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
+  ISEC0_GRIB_Len = gribLen;
 
-  Free(lGrib);
-#endif
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
-  ISEC0_GRIB_Len     = (int)gribLen;
-  ISEC0_GRIB_Version = 1;
+  // ----------------------------------------------------------------
+  // Section 9 . Abort/return to calling routine.
+  // ----------------------------------------------------------------
+  if ( ldebug )
+    {
+      gprintf(__func__, "Section 9.");
+      gprintf(__func__, "Output values set -");
 
-  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
+      gribPrintSec0(isec0);
+      gribPrintSec1(isec0, isec1);
+      // Print section 2 if present.
+      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
 
-  *kret = status;
+      if ( ! l_iorj )
+	{
+	  // Print section 3 if present.
+	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+
+	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
+	  // Special print for 2D spectra wave field real values in section 4
+	  if ( (isec1[ 0] ==  140) && 
+	       (isec1[ 1] ==   98) && 
+	       (isec1[23] ==    1) && 
+	       ((isec1[39] == 1045) || (isec1[39] == 1081))  && 
+	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
+	    gribPrintSec4Wave(isec4);
+	}
+    }
 }
 
 #endif /* T */
@@ -18863,599 +16804,818 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
 #define T float
 #ifdef T
 
-/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
-static
-void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
+static 
+int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
 {
-  long z = *gribLen;
-  int exponent, mantissa;
-  long i;
-  int ival;
-  int pvoffset = 0xFF;
-  int gdslen = 32;
-  unsigned lonIncr, latIncr;
+  // int imisng = 0;
+  bool ReducedGrid = false, VertCoorTab = false;
+#if defined (VECTORCODE)
+  unsigned char *igrib;
+  GRIBPACK *lgrib = NULL;
+  size_t lGribLen = 0;
+#endif
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
+  *numGridVals = 0;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
+  memset(isec2, 0, 22*sizeof(int));
 
-  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
+  unsigned gdsLen = GDS_Len;
 
-  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
+  unsigned ipvpl = GDS_PVPL;
+  if ( ipvpl == 0 ) ipvpl = 0xFF;
 
-  gdslen += ISEC2_NumVCP * 4;
+  if ( ipvpl != 0xFF )
+    { /* Either vct or reduced grid */
+      if ( GDS_NV != 0 )
+	{ /* we have vct */
+	  VertCoorTab = true;
+	  unsigned ipl =  4*GDS_NV + ipvpl - 1;
+	  if ( ipl < gdsLen ) ReducedGrid = true;
+	}
+      else
+	{
+	  VertCoorTab = false;
+	  ReducedGrid = true;
+	}
+      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
+    }
+ 
+  if ( ISEC0_GRIB_Version == 0 )
+    {
+      VertCoorTab = (gdsLen - 32) > 0;
+    }
+  
+  if ( ReducedGrid )
+    {
+      unsigned locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
+      unsigned jlenl = (gdsLen - locnl)  >> 1;
+      if ( jlenl == GDS_NumLat )
+	{
+	  *numGridVals = 0;
+	  ISEC2_Reduced = true;
+	  for ( unsigned i = 0; i < jlenl; i++ )
+	    {
+	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
+	      *numGridVals += ISEC2_RowLon(i);
+	    }
+	}
+      else
+	{
+	  ReducedGrid = false;
+	}
+    }
 
-  Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
-  Put1Byte(ISEC2_NumVCP);       /*  3    NV */
-  Put1Byte(pvoffset);           /*  4    PV */
-  Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
+  ISEC2_GridType = GDS_GridType;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
+  /*
+     Gaussian grid definition.
+  */
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
+       ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
+       ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
     {
-      Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
-      Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
-      Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
-      Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
-      Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
-      PutnZero(18);             /* 14-31 reserved                 */
+      ISEC2_NumLat    = GDS_NumLat;
+      if ( ! ReducedGrid )
+	{
+	  ISEC2_NumLon = GDS_NumLon;
+	  *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+	}
+      ISEC2_FirstLat  = GDS_FirstLat;
+      ISEC2_FirstLon  = GDS_FirstLon;
+      ISEC2_ResFlag   = GDS_ResFlag;
+      ISEC2_LastLat   = GDS_LastLat;
+      ISEC2_LastLon   = GDS_LastLon;
+      ISEC2_LonIncr   = GDS_LonIncr;
+
+      ISEC2_NumPar    = GDS_NumPar;
+      ISEC2_ScanFlag  = GDS_ScanFlag;
+      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+	{
+	  ISEC2_LatSP     = GDS_LatSP;
+	  ISEC2_LonSP     = GDS_LonSP;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
+	}
+      /*
+	if ( Lons != Longitudes || Lats != Latitudes )
+	Error("Latitude/Longitude Conflict");
+      */
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN     ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROT ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_STR ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN_ROTSTR )
     {
-      Put2Byte(ISEC2_GME_NI2);
-      Put2Byte(ISEC2_GME_NI3);
-      Put3Byte(ISEC2_GME_ND);
-      Put3Byte(ISEC2_GME_NI);
-      Put1Byte(ISEC2_GME_AFlag);
-      Put3Int(ISEC2_GME_LatPP);
-      Put3Int(ISEC2_GME_LonPP);
-      Put3Int(ISEC2_GME_LonMPL);
-      Put1Byte(ISEC2_GME_BFlag);
-      PutnZero(5);
+      // iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON     ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_STR ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROTSTR )
+    {
+      // iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
     }
   else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
     {
-      Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
-
-      Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
-      Put3Int(ISEC2_FirstLat);
-      Put3Int(ISEC2_FirstLon);
-      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
-      Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
-      Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
-      Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
-      Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
-      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
-      Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */  
-      Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
-      Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */  
-      Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
-      PutnZero(2);                     /* 34-41 */
+      ISEC2_NumLon    = GDS_NumLon;
+      ISEC2_NumLat    = GDS_NumLat;
+      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+      ISEC2_FirstLat  = GDS_FirstLat;
+      ISEC2_FirstLon  = GDS_FirstLon;
+      ISEC2_ResFlag   = GDS_ResFlag;
+      ISEC2_Lambert_Lov   = GDS_Lambert_Lov;
+      ISEC2_Lambert_dx    = GDS_Lambert_dx;
+      ISEC2_Lambert_dy    = GDS_Lambert_dy;
+      ISEC2_Lambert_LatS1 = GDS_Lambert_LatS1;
+      ISEC2_Lambert_LatS2 = GDS_Lambert_LatS2;
+      ISEC2_Lambert_LatSP = GDS_Lambert_LatSP;
+      ISEC2_Lambert_LonSP = GDS_Lambert_LonSP;
+      ISEC2_Lambert_ProjFlag = GDS_Lambert_ProjFlag;
+      ISEC2_ScanFlag      = GDS_ScanFlag;
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
+    {
+      ISEC2_PentaJ  = GDS_PentaJ; /* Truncation */
+      ISEC2_PentaK  = GDS_PentaK;
+      ISEC2_PentaM  = GDS_PentaM;
+      ISEC2_RepType = GDS_RepType;
+      ISEC2_RepMode = GDS_RepMode;
+      *numGridVals  = (ISEC2_PentaJ+1)*(ISEC2_PentaJ+2);
+      isec2[ 6] = 0;
+      isec2[ 7] = 0;
+      isec2[ 8] = 0;
+      isec2[ 9] = 0;
+      isec2[10] = 0;
+      // iret = decodeGDS_SH(gds, gdspos, isec0, isec2, imisng);
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+    {
+      ISEC2_GME_NI2    = GDS_GME_NI2;
+      ISEC2_GME_NI3    = GDS_GME_NI3;
+      ISEC2_GME_ND     = GDS_GME_ND;
+      ISEC2_GME_NI     = GDS_GME_NI;
+      ISEC2_GME_AFlag  = GDS_GME_AFlag;
+      ISEC2_GME_LatPP  = GDS_GME_LatPP;
+      ISEC2_GME_LonPP  = GDS_GME_LonPP;
+      ISEC2_GME_LonMPL = GDS_GME_LonMPL;
+      ISEC2_GME_BFlag  = GDS_GME_BFlag;
+      *numGridVals  = (ISEC2_GME_NI+1)*(ISEC2_GME_NI+1)*10;
+      // iret = decodeGDS_TR(gds, gdspos, isec0, isec2, imisng);
+    }
+  else
+    {
+      static bool lwarn = true;
+      ISEC2_NumLon = GDS_NumLon;
+      ISEC2_NumLat = GDS_NumLat;
+      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+      if ( lwarn )
+        {
+          lwarn = false;
+          Message("GRIB gridtype %d unsupported", ISEC2_GridType);
+        }
+    }
+
+  /*    vertical coordinate parameters for hybrid levels.     */
+  /*    get number of vertical coordinate parameters, if any. */
+
+  ISEC2_NumVCP = 0;
+
+  isec2[17] = 0;
+  isec2[18] = 0;
+
+  if ( VertCoorTab )
     {
-      int numlon;
-      if ( ISEC2_Reduced )
-	numlon = 0xFFFF;
+      int locnv;
+      if ( ISEC0_GRIB_Version  == 0 )
+	{
+	  locnv = 32;
+	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
+	}
       else
-	numlon = ISEC2_NumLon;
+	{
+	  locnv = GDS_PVPL - 1;
+	  ISEC2_NumVCP = GDS_NV;
+	}
+#if defined (SX)
+      lGribLen = 4*ISEC2_NumVCP;	      
+      lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
+
+      igrib = &gds[locnv];
+      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
+	{
+	  int iexp  = lgrib[4*i];
+	  int imant = GET_UINT3(lgrib[4*i+1], lgrib[4*i+2], lgrib[4*i+3]);
+	  fsec2[10+i] = POW_2_M24 * imant * ldexp(1.0, 4 * (iexp - 64));
+	}
+
+      Free(lgrib);
+#else
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
+	{
+	  int iexp  = gds[locnv+4*i];
+	  int imant = GET_UINT3(gds[locnv+4*i+1], gds[locnv+4*i+2], gds[locnv+4*i+3]);
+	  fsec2[10+i] = (T)decfp2(iexp,imant);
+	}
+#endif
+    }
+
+  return gdsLen;
+}
+
+#define ldexp_double ldexp
+#define ldexp_float  ldexpf
+
+static
+void TEMPLATE(decodeBDS,T)(int decscale, unsigned char *bds, int *isec2, int *isec4, 
+                           T *fsec4, int fsec4len, int dfunc, int bdsLen, int numGridVals, int *iret)
+{
+  int ioff = 0;
+  unsigned zoff;
+  unsigned bds_head = 11;
+  T zscale = 0.;
+  T fmin = 0.;
+  T *fpdata = fsec4;
+  extern int CGRIBEX_Fix_ZSE;
+
+  *iret = 0;
+  unsigned char *igrib = bds;
+
+  memset(isec4, 0, 42*sizeof(int));
+
+  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
+
+  int bds_flag = BDS_Flag;
+
+  /* 0------- grid point           */
+  /* 1------- spherical harmonics  */
+
+  bool lspherc = (bds_flag >> 7)&1;
 
-      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
+  if ( lspherc ) isec4[2] = 128;
+  else           isec4[2] = 0;
 
-      Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
-      Put3Int(ISEC2_FirstLat);
-      Put3Int(ISEC2_FirstLon);
-      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
-      Put3Int(ISEC2_LastLat);
-      Put3Int(ISEC2_LastLon);
-      if ( ISEC2_ResFlag == 0 )
-	{
-	  lonIncr = 0xFFFF;
-	  latIncr = 0xFFFF;
-	}
-      else
-	{
-	  lonIncr = (unsigned)ISEC2_LonIncr;
-	  latIncr = (unsigned)ISEC2_LatIncr;
-	}
-      Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
-      if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
-	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
-      else
-	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
+  /* -0------  simple packing */
+  /* -1------ complex packing */
 
-      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
-      PutnZero(4);                     /* 28-31 reserved                 */
+  bool lcomplex = (bds_flag >> 6)&1;
 
-      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-	{
-	  Put3Int(ISEC2_LatSP);
-	  Put3Int(ISEC2_LonSP);
-	  Put1Real((double)(FSEC2_RotAngle));
-	}
-    }
+  if ( lcomplex ) isec4[3] = 64;
+  else            isec4[3] =  0;
+
+  /* ---0---- No additional flags */
+  /* ---1---- No additional flags */
+
+  bool lcompress = (bds_flag >> 4)&1;
+
+  if ( lcompress )
+    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
   else
-    {
-      Error("Unsupported grid type %d", ISEC2_GridType);
-    }
+    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
 
-#if defined (SX)
-#pragma vdir novector     /* vectorization gives wrong results on NEC */
-#endif
-  for ( i = 0; i < ISEC2_NumVCP; ++i )
-    {
-      Put1Real((double)(fsec2[10+i]));
-    }
+  /* ----++++ number of unused bits at end of section) */
 
-  if ( ISEC2_Reduced )
-    for ( i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
+  int bds_ubits = bds_flag & 0xF;
+  
+  /* scale factor (2 bytes) */;
 
-  *gribLen = z;
-}
+  int jscale = BDS_BinScale;
 
-/* GRIB BLOCK 3 - BIT MAP SECTION */
-static
-void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
-{
-  GRIBPACK *bitmap;
-  long bitmapSize;
-  long imaskSize;
-  long i;
-  long bmsLen, bmsUnusedBits;
-  long fsec4size;
-  long z = *gribLen;
-#if defined (VECTORCODE)
-  unsigned int *imask;
-#endif
-  static int lmissvalinfo = 1;
-  /*  unsigned int c, imask; */
+  /* check for missing data indicators. */
 
-  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
-    {
-      lmissvalinfo = 0;
-      Message("Missing value = NaN is unsupported!");
-    }
+  int iexp  = bds[ 6];
+  int imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
 
-  bitmapSize = ISEC4_NumValues;
-  imaskSize = ((bitmapSize+7)>>3)<<3;
-  bitmap = &lGrib[z+6];
-  fsec4size = 0;
+  int imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
 
-#if defined (VECTORCODE)
-  imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
-  memset(imask, 0, imaskSize*sizeof(int));
+  /* convert reference value and scale factor. */
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-  for ( i = 0; i < bitmapSize; i++ )
+  if ( ! (dfunc == 'J') && imiss == 0 )
     {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
-	{
-	  data[fsec4size++] = data[i];
-	  imask[i] = 1;
-	}
+      fmin = (T)BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
     }
 
-#if defined (CRAY)
-#pragma _CRI ivdep
-#endif
-#if defined (SX)
-#pragma vdir nodep
-#endif
-#ifdef __uxpch__
-#pragma loop novrec
-#endif
-  for ( i = 0; i < imaskSize/8; i++ )
-    {
-      bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
-	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
-	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
-	          (imask[i*8+6] << 1) | (imask[i*8+7]);
-    }
+  /* get number of bits in each data value. */
 
-  Free(imask);
-#else
-  for ( i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
+  ISEC4_NumBits = BDS_NumBits;
+
+  /* octet number of start of packed data */
+  /* calculated from start of block 4 - 1 */
+
+  unsigned locnd = zoff + bds_head;
+
+  /* if data is in spherical harmonic form, distinguish   */
+  /* between simple/complex packing (lcomplex = 0/1)      */
 
-  for ( i = 0; i < bitmapSize; i++ )
+  if ( lspherc )
     {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+      if ( !lcomplex )
 	{
-	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
-	}
-    }
-#endif
+	  /*    no unpacked binary data present */
+	  /*    octet number of start of packed data */
+	  /*    calculated from start of block 4 - 1 */
 
-  bmsLen = imaskSize/8 + 6;
-  bmsUnusedBits = imaskSize - bitmapSize;
+	  ioff   = 1;
+	  locnd += 4*ioff;  /* RealCoef */
 
-  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
-  Put1Byte(bmsUnusedBits);
-  Put2Byte(0);
+	  /*    get real (0,0) coefficient in grib format and     */
+	  /*    convert to floating point.                        */
 
-  *gribLen += bmsLen;
+	  if ( dfunc != 'J' )
+	    {
+	      if ( imiss ) *fpdata++ = 0.0;
+	      else         *fpdata++ = (T)BDS_RealCoef;
+	    }
+	}
+      else /* complex packed spherical harmonics */
+	{
+	  isec4[15] = BDS_PackData;
+	  /*    scaling factor */
+	  isec4[16] = BDS_Power;
 
-  *datasize = fsec4size;
-}
+	  /*    pentagonal resolution parameters of the */
+	  /*    unpacked section of data field          */
 
-/* GRIB BLOCK 4 - BINARY DATA SECTION */
-static
-int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
-			  long *datstart, long *datsize, int code)
-{
-  /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
-  /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
+	  int jup = bds[zoff+15];
+	  int kup = bds[zoff+16];
+	  int mup = bds[zoff+17];
 
-  size_t z = (size_t)*gribLen;
-  long i;
-  int numBits;
-  int ival;
-  long PackStart = 0, Flag = 0;
-  int binscale = 0;
-  int bds_head = 11;
-  int bds_ext = 0;
-  /* ibits = BitsPerInt; */
-  int exponent, mantissa;
-  int lspherc = FALSE;
-  int isubset = 0, itemp = 0, itrunc = 0;
-  T factor = 1, fmin, fmax;
-  const double jpepsln = 1.0e-12; /* -----> tolerance used to check equality     */
-                                  /*        of floating point numbers - needed   */
-		                  /*        on some platforms (eg vpp700, linux) */
-  extern int CGRIBEX_Const;       /* 1: Don't pack constant fields on regular grids */
+	  isec4[zoff+17] = jup;
+	  isec4[zoff+18] = kup;
+	  isec4[zoff+19] = mup;
 
-  if ( isec2 )
-    {
-      /* If section 2 is present, it says if data is spherical harmonic */
+	  /*    unpacked binary data */
 
-      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
-                   isec2[0] == 70 || isec2[0] == 80 );
+	  locnd += 4; /* 2 + power */
+	  locnd += 3; /* j, k, m   */
+	  ioff   = (jup+1)*(jup+2);
 
-      if ( lspherc )
-	isec4[2] = 128;
-      else
-	isec4[2] = 0;
+	  if ( dfunc != 'J' )
+	    for ( int i = 0; i < ioff; i++ )
+	      {
+		if ( imiss )
+		  *fpdata++ = 0.0;
+		else
+		  {
+		    int iexp  = (bds[locnd+4*i]);
+		    int imant = GET_UINT3(bds[locnd+4*i+1], bds[locnd+4*i+2], bds[locnd+4*i+3]);
+		    *fpdata++ = (T)decfp2(iexp,imant);
+		  }
+	      }
+	  
+	  locnd += 4*ioff;  /* RealCoef */
+	}
     }
   else
     {
-      /* Section 4 says if it's spherical harmonic data.. */
-
-      lspherc = ( isec4[2] == 128 );
+      if ( lcomplex )
+	{
+	  *iret = 1999;
+	  gprintf(__func__, " Second order packed grids unsupported!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
+	}
     }
 
-  /* Complex packing supported for spherical harmonics. */
-
-  int lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
-                 ( lspherc && isec2 && ( isec2[5] == 2 ) );
+  /* Decode data values to floating point and store in fsec4.  */
+  /* First calculate the number of data values.                */
+  /* Take into account that spherical harmonics can be packed  */
+  /* simple (lcomplex = 0) or complex (lcomplex = 1)           */
 
-  /* Check input specification is consistent */
+  int jlend = bdsLen - locnd;
 
-  if ( lcomplex && isec2 )
+  if ( ISEC4_NumBits == 0 )
     {
-      if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
+      if ( jlend > 1 )
 	{
-	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
-	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
-	  return (807);
+	  *iret = 2001;
+	  gprintf(__func__, " Number of bits per data value = 0!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
 	}
-      else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
-	{
-	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
-	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
-	  return (807);
-        }
-      else if ( lcomplex )
+
+      if ( numGridVals == 0 )
 	{
-	  /*
-	    Truncation of full spectrum, which is supposed triangular,
-	    has to be diagnosed. Define also sub-set truncation.
-	  */
-	  isubset = isec4[17];
-	  /* When encoding, use the total number of data. */
-	  itemp   = isec4[0];
-	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
+	  *iret = 2002;
+	  gprintf(__func__, " Constant field unsupported for this grid type!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return;
 	}
-    }
 
-  if ( decscale )
+      jlend = numGridVals;
+      jlend -= ioff;
+    }
+  else
     {
-      T scale = (T) pow(10.0, (double) decscale);
-      for ( i = 0; i < datasize; ++i ) data[i] *= scale;
+      jlend = (int) (((long)jlend*8 - bds_ubits) / ISEC4_NumBits);
     }
 
-  if ( lspherc )
+  ISEC4_NumValues        = jlend + ioff;
+  ISEC4_NumNonMissValues = 0;
+
+  if ( lcompress )
     {
-      if ( lcomplex )
-	{
-	  int jup, ioff;
-	  jup  = isubset;
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
-	  PackStart = ioff;
-	  Flag = 192;
-	}
-      else
-	{
-	  bds_ext = 4;
-	  PackStart = 1;
-	  Flag = 128;
-	}
-    }
+      size_t len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-  *datstart = bds_head + bds_ext;
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
-  int nbpv = numBits = ISEC4_NumBits;
+      if ( lspherc ) ISEC4_NumValues += lcomplex ? ioff : 1;
+    }
 
-  if ( lspherc && lcomplex )
+  if ( dfunc == 'J' ) return;
+
+  /* check length of output array. */
+  
+  if ( ISEC4_NumValues > fsec4len )
     {
-      int pcStart, pcScale;
-      pcStart = isubset;
-      pcScale = isec4[16];
-      TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
-      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
+      *iret = 710;
+      gprintf(__func__, " Output array too small. Length = %d", fsec4len);
+      gprintf(__func__, " Number of values = %d", ISEC4_NumValues);
+      gprintf(__func__, " Return code =  %d", *iret);
+      return;
     }
 
-  fmin = fmax = data[PackStart];
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
+  else
+    {
+      igrib += locnd;
 
-  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
+      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
+    }
 
-  double zref = (double)fmin;
+  if ( lspherc && lcomplex )
+    {
+      int pcStart = isec4[19], pcScale = isec4[16];
+      TEMPLATE(scatter_complex,T)(fsec4, pcStart, ISEC2_PentaJ, ISEC4_NumValues);
+      TEMPLATE(scale_complex,T)(fsec4, pcStart, pcScale, ISEC2_PentaJ, 1);
+    }
 
+  if ( CGRIBEX_Fix_ZSE )  /* Fix ZeroShiftError of simple packed spherical harmonics */
+    if ( lspherc && !lcomplex )
+      {
+        /* 20100705: Fix ZeroShiftError - Edi Kirk */
+	if ( IS_NOT_EQUAL(fsec4[1], 0.0) )
+	  {
+	    T zserr = fsec4[1];
+	    for ( int i = 1; i < ISEC4_NumValues; i++ ) fsec4[i] -= zserr;
+	  }
+      }
 
-  if ( CGRIBEX_Const && !lspherc )
+  if ( decscale )
     {
-      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
+      T scale = (T) pow(10.0, (double)-decscale);
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
     }
+}
 
 
-  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  blockLength += blockLength & 1;
+void TEMPLATE(grib_decode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
+			     T *fsec3, int *isec4, T *fsec4, int fsec4len, int *kgrib,
+			     int kleng, int *kword, int dfunc, int *iret)
+{
+  UCHAR *gds = NULL, *bms = NULL;
+  int gdsLen = 0, bmsLen = 0;
+  int bitmapSize = 0;
+  int imaskSize = 0;
+  bool ldebug = false, l_iorj = false;
+  bool lsect2 = false, lsect3 = false;
+  int numGridVals = 0;
+  static bool lmissvalinfo = true;
 
-  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+  UNUSED(kleng);
 
-  Flag += unused_bits;
+  *iret = 0;
 
+  grsdef();
 
-  /*
-    Adjust number of bits per value if full integer length to
-    avoid hitting most significant bit (sign bit).
-  */
-  /* if( nbpv == ibits ) nbpv = nbpv - 1; */
-  /*
-    Calculate the binary scaling factor to spread the range of
-    values over the number of bits per value.
-    Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floats
-    as a guideline).           
-  */
-  double range = fabs(fmax - fmin);
+  ISEC2_Reduced = false;
 
-  if ( fabs(fmin) < FLT_MIN ) fmin = 0;
-  /*
-    Have to allow tolerance in comparisons on some platforms
-    (eg vpp700 and linux), such as 0.9999999999999999 = 1.0,
-    to avoid clipping ranges which are a power of 2.
-  */
-  if ( range <= jpepsln )
-    {
-      binscale = 0;
-    }
-  else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
-    {
-      binscale = 0;
-    }
-  else if ( fabs(range-1.0) <= jpepsln )
-    {
-      binscale = 1 - nbpv;
-    }
-  else if ( range > 1.0 )
-    {
-      double rangec = range + jpepsln,
-        p2 = 2.0;
-      int jloop = 1;
-      while ( jloop < 128 && p2 <= rangec )
-        {
-          p2 *= 2.0;
-          ++jloop;
-        }
-      if (jloop < 128)
-        binscale = jloop - nbpv;
-      else
-        {
-          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-          return (707);
-        }
-    }
-  else
-    {
-      double rangec = range - jpepsln, p05 = 0.5;
-      int jloop = 1;
-      while ( jloop < 127 && p05 >= rangec )
-	{
-          p05 *= 0.5;
-          jloop++;
-	}
-      if ( jloop < 127 )
-	{
-	  binscale = 1 - jloop - nbpv;
-	}
-      else
-	{
-	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
-	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
-	  return (707);
-	}
-    }
+  // ----------------------------------------------------------------
+  // IS Indicator Section (Section 0)
+  // ----------------------------------------------------------------
+  UCHAR *is = (UCHAR *) &kgrib[0];
+  int isLen = decodeIS(is, isec0, iret);
 
-  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
+  int gribLen = ISEC0_GRIB_Len;
 
-  if ( binscale != 0 )
-    {
-      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
+  /*
+    When decoding or calculating length, previous editions
+    of the GRIB code must be taken into account.
 
-      factor = (T)intpow2(-binscale);
-    }
+    In the table below, covering sections 0 and 1 of the GRIB
+    code, octet numbering is from the beginning of the GRIB
+    message;
+    * indicates that the value is not available in the code edition;
+    R indicates reserved, should be set to 0;
+    Experimental edition is considered as edition -1.
 
-  ref2ibm(&zref, BitsPerInt);
+    GRIB code edition -1 has fixed length of 20 octets for
+    section 1, the length not included in the message.
+    GRIB code edition 0 has fixed length of 24 octets for
+    section 1, the length being included in the message.
+    GRIB code edition 1 can have different lengths for section
+    1, the minimum being 28 octets, length being included in
+    the message.
 
-  Put3Byte(blockLength);      /*  0-2 Length of Block 4        */
-  Put1Byte(Flag);             /*  3   Flag & Unused bits       */
-  if ( binscale < 0 ) binscale = 32768 - binscale;
-  Put2Byte(binscale);         /*  4-5 Scale factor             */
-  Put1Real(zref);             /*  6-9 Reference value          */
-  Put1Byte(nbpv);             /*   10 Packing size             */
+                                         Octet numbers for code
+                                                  editions
 
-  if ( lspherc )
-    {
-      if ( lcomplex )
-	{
-	  int jup = isubset;
-	  int ioff = (int)z + bds_ext;
-	  if ( ioff > 0xFFFF ) ioff = 0;
-	  Put2Byte(ioff);
-	  Put2Int(isec4[16]);
-	  Put1Byte(jup);
-	  Put1Byte(jup);
-	  Put1Byte(jup);
-	  for ( i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
-	}
-      else
-	{
-	  Put1Real((double)(data[0]));
-	}
-    }
+                 Contents.                   -1      0      1
+                 ---------                ----------------------
+       Letters GRIB                          1-4    1-4    1-4
+       Total length of GRIB message.          *      *     5-7
+       GRIB code edition number               *      *      8
+       Length of Section 1.                   *     5-7    9-11
+       Reserved octet (R).                    *      8(R)   *
+       Version no. of Code Table 2.           *      *     12
+       Identification of centre.              5      9     13
+       Generating process.                    6     10     14
+       Grid definition .                      7     11     15
+       Flag (Code Table 1).                   8     12     16
+       Indicator of parameter.                9     13     17
+       Indicator of type of level.           10     14     18
+       Height, pressure etc of levels.      11-12  15-16  19-20
+       Year of century.                      13     17     21
+       Month.                                14     18     22
+       Day.                                  15     19     23
+       Hour.                                 16     20     24
+       Minute.                               17     21     25
+       Indicator of unit of time.            18     22     26
+       P1 - Period of time.                  19     23     27
+       P2 - Period of time                  20(R)   24     28
+       or reserved octet (R).
+       Time range indicator.                21(R)   25     29
+       or reserved octet (R).
+       Number included in average.       22-23(R)  26-27  30-31
+       or reserved octet (R).
+       Number missing from average.         24(R)  28(R)   32
+       or reserved octet (R).
+       Century of data.                       *      *     33
+       Designates sub-centre if not 0.        *      *     34
+       Decimal scale factor.                  *      *    35-36
+       Reserved. Set to 0.                    *      *    37-48
+       (Need not be present)
+       For originating centre use only.       *      *    49-nn
+       (Need not be present)
 
-  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
+    Identify which GRIB code edition is being decoded.
 
-#if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
-#else
-  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
-#endif
+    In GRIB edition 1, the edition number is in octet 8.
+    In GRIB edition 0, octet 8 is reserved and set to 0.
+    In GRIB edition -1, octet 8 is a flag field and can have a
+    a valid value of 0, 1, 2 or 3.
 
-  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
+    However, GRIB edition number 0 has a fixed
+    length of 24, included in the message, for section 1, so
+    if the value extracted from octets 5-7 is 24 and that from
+    octet 8 is 0, it is safe to assume edition 0 of the code.
 
-  *gribLen = (long)z;
+  */
+  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
+    {
+      // Set length of GRIB message to missing data value.
+      ISEC0_GRIB_Len = 0;
+    }
 
-  return (0);
-}
+  // ----------------------------------------------------------------
+  // PDS Product Definition Section (Section 1)
+  // ----------------------------------------------------------------
+  UCHAR *pds = is + isLen;
+  int pdsLen = decodePDS(pds, isec0, isec1);
 
+  // ----------------------------------------------------------------
+  // GDS Grid Description Section (Section 2)
+  // ----------------------------------------------------------------
+  bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  if ( gdsIncluded )
+    {
+      gds = is + isLen + pdsLen;
+      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
+    }
 
-void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
-			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
-			     int kleng, int *kword, int efunc, int *kret)
-{
-  long gribLen = 0; /* Counter of GRIB length for output */
-  long isLen, pdsLen;
-  GRIBPACK *lpds;
-  unsigned char *CGrib;
-  long fsec4size = 0;
-  int bmsIncluded;
-  GRIBPACK *lGrib;
-  long datstart, datsize, bdsstart;
-  int status = 0;
+  // ----------------------------------------------------------------
+  // BMS Bit-Map Section Section (Section 3)
+  // ----------------------------------------------------------------
+  isec3[0] = 0;
+  bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  if ( bmsIncluded )
+    {
+      bms = is + isLen + pdsLen + gdsLen;
+      bmsLen = BMS_Len;
 
-  UNUSED(isec3);
-  UNUSED(efunc);
+      imaskSize = (bmsLen - 6)<<3;
+      bitmapSize = imaskSize - BMS_UnusedBits;
+    }
 
-  grsdef();
+  // ----------------------------------------------------------------
+  // BDS Binary Data Section (Section 4)
+  // ----------------------------------------------------------------
+  UCHAR *bds = is + isLen + pdsLen + gdsLen + bmsLen;
+  int bdsLen = BDS_Len;
+  /*
+    If a very large product, the section 4 length field holds
+    the number of bytes in the product after section 4 upto
+    the end of the padding bytes.
+    This is a fixup to get round the restriction on product lengths
+    due to the count being only 24 bits. It is only possible because
+    the (default) rounding for GRIB products is 120 bytes.
+  */
+  if ( gribLen > JP23SET && bdsLen <= 120 )
+    {
+      gribLen &= JP23SET;
+      gribLen *= 120;
+      ISEC0_GRIB_Len = gribLen;
+      bdsLen = correct_bdslen(bdsLen, gribLen, isLen+pdsLen+gdsLen+bmsLen);
+    }
+  TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
+                        fsec4, fsec4len, dfunc, bdsLen, numGridVals, iret);
 
-  CGrib = (unsigned char *) kgrib;
+  if ( *iret != 0 ) return;
 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  ISEC4_NumNonMissValues = ISEC4_NumValues;
 
-  /* set max header len */
-  size_t len = 16384;
+  if ( bitmapSize > 0 )
+    {
+      if ( dfunc != 'L' && dfunc != 'J' )
+	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+	  {
+	    lmissvalinfo = false;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
+	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	  }
 
-  /* add data len */
-  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
+      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
+      ISEC4_NumValues = bitmapSize;
 
-  len += numBytes*(size_t)klenp;
+      if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
+	{
+	  GRIBPACK bitmap;
+	  /*
+	  unsigned char *bitmap;
+	  bitmap = BMS_Bitmap;
+	  int j = ISEC4_NumNonMissValues;
+	  for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
+	    {
+	      if ( (bitmap[i/8]>>(7-(i&7)))&1 )
+		fsec4[i] = fsec4[--j];
+	      else
+		fsec4[i] = FSEC3_MissVal;
+	    }
+	  */
 
-  /* add bitmap len */
-  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
 #if defined (VECTORCODE)
-  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
-  if ( lGrib == NULL ) SysError("No Memory!");
+	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
+	  GRIBPACK *pbitmap = imask;
 #else
-  lGrib = CGrib;
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
-  isLen = 8;
-  encodeIS(lGrib, &gribLen);
-  lpds = &lGrib[isLen];
-  pdsLen = getPdsLen(isec1);
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+	  for ( int i = imaskSize/8-1; i >= 0; i-- )
+	    {
+	      bitmap = pbitmap[i];
+	      imask[i*8+0] = 1 & (bitmap >> 7);
+	      imask[i*8+1] = 1 & (bitmap >> 6);
+	      imask[i*8+2] = 1 & (bitmap >> 5);
+	      imask[i*8+3] = 1 & (bitmap >> 4);
+	      imask[i*8+4] = 1 & (bitmap >> 3);
+	      imask[i*8+5] = 1 & (bitmap >> 2);
+	      imask[i*8+6] = 1 & (bitmap >> 1);
+	      imask[i*8+7] = 1 & (bitmap);
+	    }
 
-  encodePDS(lpds, pdsLen,  isec1);
-  gribLen += pdsLen;
-  /*
-  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
-    {
-      static int lwarn_cplx = TRUE;
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
+	    if ( imask[i] ) j++;
 
-      if ( lwarn_cplx )
-	Message("Complex packing of spectral data unsupported, using simple packing!");
+	  if ( ISEC4_NumNonMissValues != j )
+	    {
+	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
+		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
+			j, ISEC4_NumNonMissValues);
 
-      isec2[5] = 1;
-      isec4[3] = 0;
+	      ISEC4_NumNonMissValues = j;
+	    }
 
-      lwarn_cplx = FALSE;
-    }
-  */
-  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  if ( bmsIncluded )
-    {
-      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
-    }
-  else
-    {
-      fsec4size = ISEC4_NumValues;
+	  if ( dfunc != 'J' )
+	    {
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+	      for ( int i = ISEC4_NumValues-1; i >= 0; i-- )
+		fsec4[i] = imask[i] ? fsec4[--j] : FSEC3_MissVal;
+	    }
+
+	  Free(imask);
+	}
     }
 
-  bdsstart = gribLen;
-  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
-				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
-  if ( status )
+  if ( ISEC2_Reduced )
     {
-      *kret = status;
-      return;
+      int nvalues = 0;
+      int nlat = ISEC2_NumLat;
+      int nlon = ISEC2_RowLonPtr[0];
+      for ( int ilat = 0; ilat < nlat; ++ilat ) nvalues += ISEC2_RowLon(ilat);
+      for ( int ilat = 1; ilat < nlat; ++ilat )
+	if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
+
+      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
+      // if ( dlon < 0 ) dlon += 360000;
+	  
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+
+      //printf("nlat %d  nlon %d \n", nlat, nlon);
+      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
+
+      if ( dfunc == 'R' && *iret == -801 )
+	gprintf(__func__, "Number of values (%d) and sum of lons per row (%d) differ, abort conversion to regular Gaussian grid!",
+		ISEC4_NumValues, nvalues);
+      
+      if ( dfunc == 'R' && *iret != -801 )
+	{
+	  ISEC2_Reduced = 0;
+	  ISEC2_NumLon = nlon;
+	  ISEC4_NumValues = nlon*nlat;
+
+	  lsect3 = bitmapSize > 0;
+          int lperio = 1;
+	  int lveggy = (ISEC1_CodeTable == 128) && (ISEC1_CenterID == 98) && 
+                      ((ISEC1_Parameter == 27) || (ISEC1_Parameter == 28) || 
+                       (ISEC1_Parameter == 29) || (ISEC1_Parameter == 30) ||
+                       (ISEC1_Parameter == 39) || (ISEC1_Parameter == 40) ||
+                       (ISEC1_Parameter == 41) || (ISEC1_Parameter == 42) ||
+                       (ISEC1_Parameter == 43));
+	
+	  (void) TEMPLATE(qu2reg3,T)(fsec4, ISEC2_RowLonPtr, nlat, nlon, FSEC3_MissVal, iret, lsect3, lperio, lveggy);
+	      
+	  if ( bitmapSize > 0 )
+	    {
+	      int j = 0;	      
+	      for ( int i = 0; i < ISEC4_NumValues; i++ )
+		if ( IS_NOT_EQUAL(fsec4[i], FSEC3_MissVal) ) j++;
+		  
+	      ISEC4_NumNonMissValues = j;
+	    }
+	}
     }
 
-  encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
-    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
+  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
+  int esLen = 4;
+  gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
-#if defined (VECTORCODE)
-  if ( (size_t) gribLen > len )
-    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
+  if ( ISEC0_GRIB_Len )
+    if ( ISEC0_GRIB_Len < gribLen )
+      Warning("Inconsistent length of GRIB message (grib_message_size=%d < grib_record_size=%d)!", ISEC0_GRIB_Len, gribLen);
 
-  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
+  ISEC0_GRIB_Len = gribLen;
 
-  Free(lGrib);
-#endif
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
-  ISEC0_GRIB_Len     = (int)gribLen;
-  ISEC0_GRIB_Version = 1;
+  // ----------------------------------------------------------------
+  // Section 9 . Abort/return to calling routine.
+  // ----------------------------------------------------------------
+  if ( ldebug )
+    {
+      gprintf(__func__, "Section 9.");
+      gprintf(__func__, "Output values set -");
 
-  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
+      gribPrintSec0(isec0);
+      gribPrintSec1(isec0, isec1);
+      // Print section 2 if present.
+      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
 
-  *kret = status;
+      if ( ! l_iorj )
+	{
+	  // Print section 3 if present.
+	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+
+	  TEMPLATE(gribPrintSec4,T)(isec0, isec4, fsec4);
+	  // Special print for 2D spectra wave field real values in section 4
+	  if ( (isec1[ 0] ==  140) && 
+	       (isec1[ 1] ==   98) && 
+	       (isec1[23] ==    1) && 
+	       ((isec1[39] == 1045) || (isec1[39] == 1081))  && 
+	       ((isec1[ 5] ==  250) || (isec1[ 5] ==  251)) )
+	    gribPrintSec4Wave(isec4);
+	}
+    }
 }
 
 #endif /* T */
@@ -19466,3437 +17626,4090 @@ void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *
  * End:
  */
 
-void encode_dummy(void)
-{
-  (void) encode_array_unrolled_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
-  (void) encode_array_unrolled_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
-}
-static const char grb_libvers[] = "1.7.5" " of ""Jun  3 2016"" ""14:44:00";
-const char *
-cgribexLibraryVersion(void)
-{
-  return (grb_libvers);
-}
-
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic pop
-#endif
-
-#ifdef HAVE_CONFIG_H
-#endif
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#ifdef WORDS_BIGENDIAN
-#include <limits.h>
-#endif
-
-
-static const uint32_t crctab[] = {
-  0x00000000,
-  0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
-  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
-  0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
-  0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
-  0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
-  0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
-  0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
-  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
-  0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
-  0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
-  0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
-  0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
-  0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
-  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
-  0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
-  0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
-  0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
-  0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
-  0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
-  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
-  0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
-  0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
-  0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
-  0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
-  0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
-  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
-  0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
-  0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
-  0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
-  0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
-  0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
-  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
-  0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
-  0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
-  0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
-  0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
-  0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
-  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
-  0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
-  0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
-  0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
-  0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
-  0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
-  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
-  0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
-  0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
-  0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
-  0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
-  0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
-  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
-  0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
-};
-
-
-uint32_t
-memcrc(const unsigned char *b, size_t n)
+/* GRIB block 0 - indicator block */
+static
+void encodeIS(GRIBPACK *lGrib, long *gribLen)
 {
-/*  Input arguments:
- *  const char*   b == byte sequence to checksum
- *  size_t        n == length of sequence
- */
-
-
-  uint32_t s = 0;
+  long z;
+  // z = *gribLen;
 
-  memcrc_r(&s, b, n);
+  lGrib[0] = 'G';
+  lGrib[1] = 'R';
+  lGrib[2] = 'I';
+  lGrib[3] = 'B';
 
-  /* Extend with the length of the string. */
-  while (n != 0) {
-    register uint32_t c = n & 0377;
-    n >>= 8;
-    s = (s << 8) ^ crctab[(s >> 24) ^ c];
-  }
+  // lGrib[4]-lGrib[6] contains full length of grib record. 
+  // included before finished CODEGB
 
+  z = 7;   
+  Put1Byte(1); /* grib version */
+  z = 8;
 
-  return ~s;
+  *gribLen = z;
 }
 
-void
-memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len)
+/* GRIB block 5 - end block */
+static
+void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
 {
-/*  Input arguments:
- *  const char*   b == byte sequence to checksum
- *  size_t        n == length of sequence
- */
-
-
-  register uint32_t c, s = *state;
-  register size_t n = block_len;
-  register const unsigned char *b = block;
-
-  for (; n > 0; --n) {
-    c = (uint32_t)(*b++);
-    s = (s << 8) ^ crctab[(s >> 24) ^ c];
-  }
-
-  *state = s;
-}
+  long z = *gribLen;
 
-#ifdef WORDS_BIGENDIAN
-#define SWAP_CSUM(BITWIDTH,BYTEWIDTH,NACC)                              \
-  do {                                                                  \
-    register const uint##BITWIDTH##_t *b = (uint##BITWIDTH##_t *)elems; \
-    for (size_t i = 0; i < num_elems; ++i) {                            \
-      for(size_t aofs = NACC; aofs > 0; --aofs) {                       \
-        uint##BITWIDTH##_t accum = b[i + aofs - 1];                     \
-        for (size_t j = 0; j < BYTEWIDTH; ++j) {                        \
-          uint32_t c = (uint32_t)(accum & UCHAR_MAX);                   \
-          s = (s << 8) ^ crctab[(s >> 24) ^ c];                         \
-          accum >>= 8;                                                  \
-        }                                                               \
-      }                                                                 \
-    }                                                                   \
-  } while (0)
-#endif
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
 
+  if ( z > JP24SET )
+    {
+      long bdslen = z - 4;
+      // fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET);
+      // exit(1);
+      /*
+	If a very large product, the section 4 length field holds
+	the number of bytes in the product after section 4 upto
+	the end of the padding bytes.
+	This is a fixup to get round the restriction on product lengths
+	due to the count being only 24 bits. It is only possible because
+	the (default) rounding for GRIB products is 120 bytes.
+      */
+      while ( z%120 ) lGrib[z++] = 0;
 
-/**
- *  Does endian-swapping prior to checksumming in case platform is big-endian
- *
- *  @param elems points to first first element with alignment elem_size
- *  @param num_elems number of elements to process
- *  @param elem_size size of each element in bytes
- */
-void
-memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
-               size_t elem_size)
-{
-#ifdef WORDS_BIGENDIAN
-  register uint32_t s = *state;
+      if ( z > JP23SET*120 )
+	{
+	  fprintf(stderr, "Abort: GRIB1 record too large (size = %ld; max = %d)!\n", z, JP23SET*120);
+	  exit(1);
+	}
 
-  switch (elem_size)
-  {
-  case 1:
-    memcrc_r(state, elems, num_elems * elem_size);
-    return;
-  case 2:
-    SWAP_CSUM(16,2,1);
-    break;
-  case 4:
-    SWAP_CSUM(32,4,1);
-    break;
-  case 8:
-    SWAP_CSUM(64,8,1);
-    break;
-  case 16:
-    SWAP_CSUM(64,8,2);
-    break;
-  }
-  *state = s;
-#else
-  memcrc_r(state, elems, num_elems * elem_size);
-#endif
-}
+      long itemp = z / (-120);
+      itemp = JP23SET - itemp + 1;
 
+      lGrib[4] = (GRIBPACK)(itemp >> 16);
+      lGrib[5] = (GRIBPACK)(itemp >>  8);
+      lGrib[6] = (GRIBPACK)itemp;
 
-uint32_t
-memcrc_finish(uint32_t *state, off_t total_size)
-{
-  register uint32_t c, s = *state;
-  register uint64_t n = (uint64_t)total_size;
+      bdslen = z - bdslen;
+      lGrib[bdsstart  ] = (GRIBPACK)(bdslen >> 16);
+      lGrib[bdsstart+1] = (GRIBPACK)(bdslen >>  8);
+      lGrib[bdsstart+2] = (GRIBPACK)bdslen;
+    }
+  else
+    {
+      lGrib[4] = (GRIBPACK)(z >> 16);
+      lGrib[5] = (GRIBPACK)(z >>  8);
+      lGrib[6] = (GRIBPACK)z;
 
-  /* Extend with the length of the string. */
-  while (n != 0) {
-    c = n & 0377;
-    n >>= 8;
-    s = (s << 8) ^ crctab[(s >> 24) ^ c];
-  }
+      while ( z%8 ) lGrib[z++] = 0;
+    }
 
-  return ~s;
+  *gribLen = z;
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if  defined(HAVE_CONFIG_H)
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <errno.h>
+/* GRIB block 1 - product definition block. */
 
-#if !defined(HAVE_CONFIG_H) && !defined(HAVE_MALLOC_H) && defined(SX)
-#  define  HAVE_MALLOC_H
-#endif
+#define DWD_extension_253_len 38
+#define DWD_extension_254_len 26
+#define ECMWF_extension_1_len 24
+#define MPIM_extension_1_len  18
 
-#if  defined(HAVE_MALLOC_H)
-#  include <malloc.h>
-#endif
+static
+long getLocalExtLen(int *isec1)
+{
+  long extlen = 0;
 
+  if ( ISEC1_LocalFLag )
+    {
+      if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
+	{
+	  if      ( isec1[36] == 254 ) extlen = DWD_extension_254_len;
+	  else if ( isec1[36] == 253 ) extlen = DWD_extension_253_len;
+	}
+      else if ( ISEC1_CenterID == 98 )
+        {
+	  if ( isec1[36] == 1 )   extlen = ECMWF_extension_1_len;
+        }
+      else if ( ISEC1_CenterID == 252 )
+        {
+	  if ( isec1[36] == 1 ) extlen = MPIM_extension_1_len;
+        }
+    }
 
-enum             {MALLOC_FUNC=0, CALLOC_FUNC, REALLOC_FUNC, FREE_FUNC};
-static const char *memfunc[] = {"Malloc", "Calloc", "Realloc", "Free"};
+  return extlen;
+}
 
-#undef   MEM_UNDEFID
-#define  MEM_UNDEFID  -1
+static
+long getPdsLen(int *isec1)
+{
+  long pdslen = 28;
 
-#define  MEM_MAXNAME  32   /* Min = 8, for  "unknown" ! */
+  pdslen += getLocalExtLen(isec1);
 
-static int dmemory_ExitOnError = 1;
+  return pdslen;
+}
 
-typedef struct
+static
+void encodePDS_DWD_local_Extension_254(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  void     *ptr;
-  size_t    size;
-  size_t    nobj;
-  int       item;
-  int       mtype;
-  int       line;
-  char      filename[MEM_MAXNAME];
-  char      functionname[MEM_MAXNAME];
-}
-MemTable_t;
+  long z = *zs;
 
-static MemTable_t *memTable;
-static size_t  memTableSize  = 0;
-static long    memAccess     = 0;
+  long localextlen = getLocalExtLen(isec1);
+  for ( long i = 0; i < localextlen-2; i++ ) Put1Byte(isec1[24+i]);
 
-static size_t  MemObjs       = 0;
-static size_t  MaxMemObjs    = 0;
-static size_t  MemUsed       = 0;
-static size_t  MaxMemUsed    = 0;
+  int isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
+  Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
 
-static int     MEM_Debug     = 0;   /* If set to 1, debugging */
-static int     MEM_Info      = 0;   /* If set to 1, print mem table at exit */
+  *zs = z;
+}
 
 static
-const char *get_filename(const char *file)
+void encodePDS_DWD_local_Extension_253(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  const char *fnptr = strrchr(file, '/');
-  if ( fnptr ) fnptr++;
-  else         fnptr = (char *) file;
+  long z = *zs;
 
-  return fnptr;
-}
+  long localextlen = DWD_extension_254_len;
+  for ( long i = 0; i < localextlen-2; i++ ) Put1Byte(isec1[24+i]);
 
+  int isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
+  Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
+  Put1Byte(isec1[50]);        /* 55 User id, specified by table       */
+  Put2Byte(isec1[51]);        /* 56 Experiment identifier             */
+  Put2Byte(isec1[52]);        /* 58 Ensemble identification by table  */
+  Put2Byte(isec1[53]);        /* 60 Number of ensemble members        */
+  Put2Byte(isec1[54]);        /* 62 Actual number of ensemble member  */
+  Put1Byte(isec1[55]);        /* 64 Model major version number        */ 
+  Put1Byte(isec1[56]);        /* 65 Model minor version number        */ 
+  Put1Byte(0);                /* 66 Blank for even buffer length      */
 
-void memDebug(int debug)
-{
-  MEM_Debug = debug;
+  *zs = z;
 }
 
-/* If we're not using GNU C, elide __attribute__ */
-#if ! defined __GNUC__ && ! defined __attribute__
-#  define  __attribute__(x)  /*NOTHING*/
-#endif
-
-static
-void memInternalProblem(const char *caller, const char *fmt, ...)
-  __attribute__((noreturn));
-static
-void memError(const char *caller, const char *file, int line, size_t size)
-  __attribute__((noreturn));
-
 static
-void memInternalProblem(const char *functionname, const char *fmt, ...)
+void encodePDS_ECMWF_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  va_list args;
+  long z = *zs;
 
-  va_start(args, fmt);
+  long localextlen = getLocalExtLen(isec1);
+  for ( long i = 0; i < localextlen-12; i++ ) Put1Byte(isec1[24+i]);
+                              /* 12 bytes explicitly encoded below:         */
+  Put1Byte(isec1[36]);        /* ECMWF local GRIB use definition identifier */
+                              /*    1=MARS labelling or ensemble fcst. data */
+  Put1Byte(isec1[37]);        /* Class                                      */
+  Put1Byte(isec1[38]);        /* Type                                       */
+  Put2Byte(isec1[39]);        /* Stream                                     */
 
-  printf("\n");
-   fprintf(stderr, "Internal problem (%s) : ", functionname);
-  vfprintf(stderr, fmt, args);
-   fprintf(stderr, "\n");
+  /* Version number or experiment identifier    */
+  Put1Byte(((unsigned char*) &isec1[40])[0]);
+  Put1Byte(((unsigned char*) &isec1[40])[1]);
+  Put1Byte(((unsigned char*) &isec1[40])[2]);
+  Put1Byte(((unsigned char*) &isec1[40])[3]);
 
-  va_end(args);
+  Put1Byte(isec1[41]);        /* Ensemble forecast number                   */
+  Put1Byte(isec1[42]);        /* Total number of forecasts in ensemble      */
+  Put1Byte(0);                /* (Spare)                                    */
 
-  exit(EXIT_FAILURE);
+  *zs = z;
 }
 
 static
-void memError(const char *functionname, const char *file, int line, size_t size)
+void encodePDS_MPIM_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  fputs("\n", stdout);
-  fprintf(stderr, "Error (%s) : Allocation of %zu bytes failed. [ line %d file %s ]\n",
-	  functionname, size, line, get_filename(file));
+  long z = *zs;
 
-  if ( errno ) perror("System error message ");
+  long localextlen = getLocalExtLen(isec1);
+  for ( long i = 0; i < localextlen-6; i++ ) Put1Byte(isec1[24+i]);
+                              /* 6 bytes explicitly encoded below:          */
+  Put1Byte(isec1[36]);        /* MPIM local GRIB use definition identifier  */
+                              /*    (extension identifier)                  */
+  Put1Byte(isec1[37]);        /* type of ensemble forecast                  */
+  Put2Byte(isec1[38]);        /* individual ensemble member                 */
+  Put2Byte(isec1[39]);        /* number of forecasts in ensemble            */
 
-  exit(EXIT_FAILURE);
+  *zs = z;
 }
 
+/* GRIB BLOCK 1 - PRODUCT DESCRIPTION SECTION */
 static
-void memListPrintEntry(int mtype, int item, size_t size, void *ptr,
-		       const char *functionname, const char *file, int line)
+void encodePDS(GRIBPACK *lpds, long pdsLen, int *isec1)
 {
-  fprintf(stderr, "[%-7s ", memfunc[mtype]);
+  GRIBPACK *lGrib = lpds;
+  long z = 0;
+  int ival;
 
-  fprintf(stderr, "memory item %3d ", item);
-  fprintf(stderr, "(%6zu byte) ", size);
-  fprintf(stderr, "at %p", ptr);
-  if ( file != NULL )
+  int century = ISEC1_Century;
+  int year    = ISEC1_Year;
+
+  if ( century < 0 )
     {
-      fprintf(stderr, " line %4d", line);
-      fprintf(stderr, " file %s", get_filename(file));
+      century = -century;
+      year    = -year;
     }
-  if ( functionname != NULL )
-    fprintf(stderr, " (%s)", functionname);
-  fprintf(stderr, "]\n");
-}
-
-static
-void memListPrintTable(void)
-{
-  if ( MemObjs ) fprintf(stderr, "\nMemory table:\n");
 
-  for ( size_t memID = 0; memID < memTableSize; memID++ )
+  Put3Byte(pdsLen);               /*  0 Length of Block 1        */
+  Put1Byte(ISEC1_CodeTable);      /*  3 Local table number       */
+  Put1Byte(ISEC1_CenterID);       /*  4 Identification of centre */
+  Put1Byte(ISEC1_ModelID);        /*  5 Identification of model  */
+  Put1Byte(ISEC1_GridDefinition); /*  6 Grid definition          */
+  Put1Byte(ISEC1_Sec2Or3Flag);    /*  7 Block 2 included         */
+  Put1Byte(ISEC1_Parameter);      /*  8 Parameter Code           */
+  Put1Byte(ISEC1_LevelType);      /*  9 Type of level            */
+  if ( (ISEC1_LevelType !=  20) &&
+       (ISEC1_LevelType != GRIB1_LTYPE_99)           &&
+       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC)     &&
+       (ISEC1_LevelType != GRIB1_LTYPE_ISOBARIC_PA)  &&
+       (ISEC1_LevelType != GRIB1_LTYPE_ALTITUDE)     &&
+       (ISEC1_LevelType != GRIB1_LTYPE_HEIGHT)       &&
+       (ISEC1_LevelType != GRIB1_LTYPE_SIGMA)        &&
+       (ISEC1_LevelType != GRIB1_LTYPE_HYBRID)       &&
+       (ISEC1_LevelType != GRIB1_LTYPE_LANDDEPTH)    &&
+       (ISEC1_LevelType != GRIB1_LTYPE_ISENTROPIC)   &&
+       (ISEC1_LevelType != 115) &&
+       (ISEC1_LevelType != 117) &&
+       (ISEC1_LevelType != 125) &&
+       (ISEC1_LevelType != 127) &&
+       (ISEC1_LevelType != 160) &&
+       (ISEC1_LevelType != 210) )
     {
-      if ( memTable[memID].item != MEM_UNDEFID )
-        memListPrintEntry(memTable[memID].mtype, memTable[memID].item,
-                          memTable[memID].size*memTable[memID].nobj,
-                          memTable[memID].ptr, memTable[memID].functionname,
-                          memTable[memID].filename, memTable[memID].line);
+      Put1Byte(ISEC1_Level1);
+      Put1Byte(ISEC1_Level2);
+    }
+  else
+    {
+      Put2Byte(ISEC1_Level1);     /* 10 Level                    */    
     }
 
-  if ( MemObjs )
+  Put1Int(year);                  /* 12 Year of Century          */
+  Put1Byte(ISEC1_Month);          /* 13 Month                    */
+  Put1Byte(ISEC1_Day);            /* 14 Day                      */
+  Put1Byte(ISEC1_Hour);           /* 15 Hour                     */
+  Put1Byte(ISEC1_Minute);         /* 16 Minute                   */
+
+  Put1Byte(ISEC1_TimeUnit);       /* 17 Time unit                */
+  if ( ISEC1_TimeRange == 10 )
     {
-      fprintf(stderr, "  Memory access             : %6u\n", (unsigned) memAccess);
-      fprintf(stderr, "  Maximum objects           : %6zu\n", memTableSize);
-      fprintf(stderr, "  Objects used              : %6u\n", (unsigned) MaxMemObjs);
-      fprintf(stderr, "  Objects in use            : %6u\n", (unsigned) MemObjs);
-      fprintf(stderr, "  Memory allocated          : ");
-      if (MemUsed > 1024*1024*1024)
-	fprintf(stderr, " %5d GB\n",   (int) (MemUsed/(1024*1024*1024)));
-      else if (MemUsed > 1024*1024)
-	fprintf(stderr, " %5d MB\n",   (int) (MemUsed/(1024*1024)));
-      else if (MemUsed > 1024)
-	fprintf(stderr, " %5d KB\n",   (int) (MemUsed/(1024)));
-      else
-	fprintf(stderr, " %5d Byte\n", (int)  MemUsed);
+      Put1Byte(ISEC1_TimePeriod1);
+      Put1Byte(ISEC1_TimePeriod2);
+    }
+  else if ( ISEC1_TimeRange == 113 || ISEC1_TimeRange ==   0 )
+    {
+      Put1Byte(ISEC1_TimePeriod1);
+      Put1Byte(0);
+    }
+  else if ( ISEC1_TimeRange ==   5 || ISEC1_TimeRange ==   4 || 
+	    ISEC1_TimeRange ==   3 || ISEC1_TimeRange ==   2 )
+    {
+      Put1Byte(0);
+      Put1Byte(ISEC1_TimePeriod2);
+    }
+  else
+    {
+      Put1Byte(0);
+      Put1Byte(0); 
     }
+  Put1Byte(ISEC1_TimeRange);      /* 20 Timerange flag           */
+  Put2Byte(ISEC1_AvgNum);         /* 21 Average                  */
 
-  if ( MaxMemUsed )
+  Put1Byte(ISEC1_AvgMiss);        /* 23 Missing from averages    */
+  Put1Byte(century);              /* 24 Century                  */
+  Put1Byte(ISEC1_SubCenterID);    /* 25 Subcenter                */
+  Put2Int(ISEC1_DecScaleFactor);  /* 26 Decimal scale factor     */
+
+  if ( ISEC1_LocalFLag )
     {
-      fprintf(stderr, "  Maximum memory allocated  : ");
-      if (MaxMemUsed > 1024*1024*1024)
-	fprintf(stderr, " %5d GB\n",   (int) (MaxMemUsed/(1024*1024*1024)));
-      else if (MaxMemUsed > 1024*1024)
-	fprintf(stderr, " %5d MB\n",   (int) (MaxMemUsed/(1024*1024)));
-      else if (MaxMemUsed > 1024)
-	fprintf(stderr, " %5d KB\n",   (int) (MaxMemUsed/(1024)));
+      if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
+	{
+	  if      ( isec1[36] == 254 ) encodePDS_DWD_local_Extension_254(lGrib, &z, isec1);
+	  else if ( isec1[36] == 253 ) encodePDS_DWD_local_Extension_253(lGrib, &z, isec1);
+	}
+      else if ( ISEC1_CenterID == 98 )
+	{
+	  if ( isec1[36] == 1 ) encodePDS_ECMWF_local_Extension_1(lGrib, &z, isec1);
+	}
+      else if ( ISEC1_CenterID == 252 )
+	{
+	  if ( isec1[36] == 1 ) encodePDS_MPIM_local_Extension_1(lGrib, &z, isec1);
+	}
       else
-	fprintf(stderr, " %5d Byte\n", (int)  MaxMemUsed);
+	{
+	  long i, localextlen;
+	  localextlen = getLocalExtLen(isec1);
+	  for ( i = 0; i < localextlen; i++ )
+	    {
+	      Put1Byte(isec1[24+i]);
+	    }
+	}
     }
 }
 
-static
-void memGetDebugLevel(void)
-{
-  const char *envstr;
 
-  envstr = getenv("MEMORY_INFO");
-  if ( envstr && isdigit((int) envstr[0]) ) MEM_Info = atoi(envstr);
 
-  envstr = getenv("MEMORY_DEBUG");
-  if ( envstr && isdigit((int) envstr[0]) ) MEM_Debug = atoi(envstr);
 
-  if ( MEM_Debug && !MEM_Info ) MEM_Info = 1;
+#ifdef T
+#undef T
+#endif
+#define T double
+#ifdef T
 
-  if ( MEM_Info ) atexit(memListPrintTable);
-}
+
+#define round_float roundf
+#define round_double round
 
 static
-void memInit(void)
+void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
+				     const T *data, T zref, T factor, size_t *gz)
 {
-  static int initDebugLevel = 0;
+  size_t i, z = *gz;
+  unsigned int ival;
+  int cbits, jbits;
+  unsigned int c;
+  static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
+    
+  /* code from gribw routine flist2bitstream */
 
-  if ( ! initDebugLevel )
+  cbits = 8;
+  c = 0;
+  for ( i = packStart; i < datasize; i++ )
     {
-      memGetDebugLevel();
-      initDebugLevel = 1;
+      /* note float -> unsigned int .. truncate */
+      // ival = (unsigned int)(TEMPLATE(round,T)((data[i] - zref) * factor));
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
+      /*
+	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
+	if ( ival < 0 ) ival = 0;
+      */
+      jbits = numBits;
+      while ( cbits <= jbits ) 
+	{
+	  if ( cbits == 8 )
+	    {
+	      jbits -= 8;
+	      lGrib[z++] = (ival >> jbits) & 0xFF;
+	    }
+	  else
+	    {
+	      jbits -= cbits;
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
+	      cbits = 8;
+	      c = 0;
+	    }
+	}
+      /* now jbits < cbits */
+      if ( jbits )
+	{
+	  c = (c << jbits) + (ival & mask[jbits]);
+	  cbits -= jbits;
+	}
     }
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
+
+  *gz = z;
 }
 
+
 static
-int memListDeleteEntry(void *ptr, size_t *size)
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
 {
-  int item = MEM_UNDEFID;
-  size_t memID;
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
 
-  for ( memID = 0; memID < memTableSize; memID++ )
+  if ( IS_BIGENDIAN() )
     {
-      if ( memTable[memID].item == MEM_UNDEFID ) continue;
-      if ( memTable[memID].ptr == ptr ) break;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          // sgrib[i] = (uint16_t)(TEMPLATE(round,T)((data[i] - zref) * factor));
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
     }
-
-  if ( memID != memTableSize )
+  else
     {
-      MemObjs--;
-      MemUsed -= memTable[memID].size * memTable[memID].nobj;
-      *size = memTable[memID].size * memTable[memID].nobj;
-      item = memTable[memID].item;
-      memTable[memID].item = MEM_UNDEFID;
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          // ui16 = (uint16_t)(TEMPLATE(round,T)((data[i] - zref) * factor));
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
     }
 
-  return item;
+  *gz += 2*datasize;
 }
-
+/*
 static
-void memTableInitEntry(size_t memID)
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
 {
-  if ( memID >= memTableSize )
-    memInternalProblem(__func__, "memID %d undefined!", memID);
+  size_t i, z = *gz;
+  uint16_t ui16;
+  T tmp;
 
-  memTable[memID].ptr    = NULL;
-  memTable[memID].item   = MEM_UNDEFID;
-  memTable[memID].size   = 0;
-  memTable[memID].nobj   = 0;
-  memTable[memID].mtype  = MEM_UNDEFID;
-  memTable[memID].line   = MEM_UNDEFID;
-}
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+  for ( i = 0; i < datasize; i++ )
+    {
+      // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
+      ui16 = (uint16_t) tmp;
+      lGrib[z  ] = ui16 >>  8;
+      lGrib[z+1] = ui16;
+      z += 2;
+    }
 
+  *gz = z;
+}
+*/
 static
-int memListNewEntry(int mtype, void *ptr, size_t size, size_t nobj,
-		    const char *functionname, const char *file, int line)
+void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
+			      GRIBPACK *restrict lGrib,
+			      const T *restrict data, 
+			      T zref, T factor, size_t *gz)
 {
-  static int item = 0;
-  size_t memSize = 0;
-  size_t memID = 0;
+#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
+  uint64_t start_minmax, end_minmax;
+#endif
+  uint32_t ui32;
+  size_t i, z = *gz;
+  T tmp;
 
-  /*
-    Look for a free slot in memTable.
-    (Create the table the first time through).
-  */
-  if ( memTableSize == 0 )
-    {
-      memTableSize = 8;
-      memSize  = memTableSize * sizeof(MemTable_t);
-      memTable = (MemTable_t *) malloc(memSize);
-      if( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
+  data += packStart;
+  datasize -= packStart;
 
-      for ( size_t i = 0; i < memTableSize; i++ )
-	memTableInitEntry(i);
-    }
-  else
+  if      ( numBits ==  8 )
     {
-      while ( memID < memTableSize )
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(2, "pack 8 bit base");
+#endif
+
+#if defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
 	{
-	  if ( memTable[memID].item == MEM_UNDEFID ) break;
-	  memID++;
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
+          z++;
 	}
+
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(2);
+#endif
     }
-  /*
-    If the table overflows, double its size.
-  */
-  if ( memID == memTableSize )
+  else if ( numBits == 16 )
     {
-      memTableSize = 2*memTableSize;
-      memSize  = memTableSize*sizeof(MemTable_t);
-      memTable = (MemTable_t*) realloc(memTable, memSize);
-      if ( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(3, "pack 16 bit base");
+#elif defined _GET_X86_COUNTER 
+      start_minmax = _rdtsc();
+#elif defined _GET_MACH_COUNTER 
+      start_minmax = mach_absolute_time();
+#endif
+      if ( sizeof(T) == sizeof(double) )
+      	{
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
+        }
+      else
+        {
+          TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
+        }
 
-      for ( size_t i = memID; i < memTableSize; i++ )
-	memTableInitEntry(i);
+#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
+#if defined _GET_X86_COUNTER 
+      end_minmax = _rdtsc();
+#elif defined _GET_MACH_COUNTER 
+      end_minmax = mach_absolute_time();
+#endif
+#if defined _ENABLE_AVX
+      printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#elif defined _ENABLE_SSE4_1
+      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#else
+      printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#endif  
+#endif
+      
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(3);
+#endif
     }
+  else if ( numBits == 24 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(4, "pack 24 bit base");
+#endif
 
-  memTable[memID].item  = item;
-  memTable[memID].ptr   = ptr;
-  memTable[memID].size  = size;
-  memTable[memID].nobj  = nobj;
-  memTable[memID].mtype = mtype;
-  memTable[memID].line  = line;
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
+	{
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+          ui32 = (uint32_t) tmp;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
+          z += 3;
+	}
 
-  if ( file )
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(4);
+#endif
+    }
+  else if ( numBits == 32 )
     {
-      const char *filename = get_filename(file);
-      size_t len = strlen(filename);
-      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(5, "pack 32 bit base");
+#endif
 
-      (void) memcpy(memTable[memID].filename, filename, len);
-      memTable[memID].filename[len] = '\0';
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
+	{
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+          ui32 = (uint32_t) tmp;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
+          z += 4;
+	}
+
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(5);
+#endif
     }
-  else
+  else if ( numBits > 0 && numBits <= 32 )
     {
-      (void) strcpy(memTable[memID].filename, "unknown");
+      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
     }
-
-  if ( functionname )
+  else if ( numBits == 0 )
     {
-      size_t len = strlen(functionname);
-      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
-
-      (void) memcpy(memTable[memID].functionname, functionname, len);
-      memTable[memID].functionname[len] = '\0';
     }
   else
     {
-      (void) strcpy(memTable[memID].functionname, "unknown");
+      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  MaxMemObjs++;
-  MemObjs++;
-  MemUsed += size*nobj;
-  if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
-
-  return item++;
+  *gz = z;
 }
 
 static
-int memListChangeEntry(void *ptrold, void *ptr, size_t size,
-		       const char *functionname, const char *file, int line)
+void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize, 
+				       GRIBPACK *restrict lGrib,
+				       const T *restrict data, 
+				       T zref, T factor, size_t *gz)
 {
-  int item = MEM_UNDEFID;
-  size_t memID = 0;
+  U_BYTEORDER;
+  size_t i, j, z = *gz;
+#ifdef _ARCH_PWR6
+  enum { CGRIBEX__UNROLL_DEPTH_2 = 8 };
+#else
+  enum { CGRIBEX__UNROLL_DEPTH_2 = 128 };
+#endif
+  size_t residual;
+  size_t ofs;
+  T dval[CGRIBEX__UNROLL_DEPTH_2];
 
-  while( memID < memTableSize )
-    {
-      if ( memTable[memID].item != MEM_UNDEFID )
-	if ( memTable[memID].ptr == ptrold ) break;
-      memID++;
-    }
+  data += packStart;
+  datasize -= packStart;
+  residual =  datasize % CGRIBEX__UNROLL_DEPTH_2;
+  ofs = datasize - residual;
 
-  if ( memID == memTableSize )
+  // reducing FP operations to single FMA is slowing down on pwr6 ...
+
+  if      ( numBits ==  8 )
     {
-      if ( ptrold != NULL )
-	memInternalProblem(__func__, "Item at %p not found.", ptrold);
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(2, "pack 8 bit unrolled");
+#endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+	{
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+#ifdef _ARCH_PWR6
+	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
+	    }
+	  z += CGRIBEX__UNROLL_DEPTH_2;
+	}
+      for (j = 0; j < residual; j++) 
+	{
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      for (j = 0; j < residual; j++) 
+	{
+#ifdef _ARCH_PWR6
+	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
+	}
+      z += residual;
+
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(2);
+#endif
     }
-  else
+  else if ( numBits == 16 )
     {
-      item = memTable[memID].item;
-
-      size_t sizeold = memTable[memID].size*memTable[memID].nobj;
-
-      memTable[memID].ptr   = ptr;
-      memTable[memID].size  = size;
-      memTable[memID].nobj  = 1;
-      memTable[memID].mtype = REALLOC_FUNC;
-      memTable[memID].line  = line;
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(3, "pack 16 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
 
-      if ( file )
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
 	{
-          const char *filename = get_filename(file);
-	  size_t len = strlen(filename);
-	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
-
-	  (void) memcpy(memTable[memID].filename, filename, len);
-	  memTable[memID].filename[len] = '\0';
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  if ( IS_BIGENDIAN() )
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+#ifdef _ARCH_PWR6
+		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
+		}
+	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
+	    }
+	  else
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
+		}
+	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
+	    }
 	}
-      else
+      for (j = 0; j < residual; j++) 
 	{
-	  (void) strcpy(memTable[memID].filename, "unknown");
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
-
-      if ( functionname )
+      if ( IS_BIGENDIAN() )
 	{
-	  size_t len = strlen(functionname);
-	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
-
-	  (void) memcpy(memTable[memID].functionname, functionname, len);
-	  memTable[memID].functionname[len] = '\0';
+	  for (j = 0; j < residual; j++) 
+	    {
+#ifdef _ARCH_PWR6
+	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
+	    }
+	  z += 2*residual;
 	}
       else
 	{
-	  (void) strcpy(memTable[memID].functionname, "unknown");
+	  for (j = 0; j < residual; j++) 
+	    {
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
+	      z += 2;
+	    }
 	}
-
-      MemUsed -= sizeold;
-      MemUsed += size;
-      if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(3);
+#endif
     }
-
-  return item;
-}
-
-
-void *memCalloc(size_t nobjs, size_t size, const char *file, const char *functionname, int line)
-{
-  void *ptr = NULL;
-
-  memInit();
-
-  if ( nobjs*size > 0 )
+  else if ( numBits == 24 )
     {
-      ptr = calloc(nobjs, size);
-
-      if ( MEM_Info )
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(4, "pack 24 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
 	{
-	  memAccess++;
-
-          int item = MEM_UNDEFID;
-	  if ( ptr ) item = memListNewEntry(CALLOC_FUNC, ptr, size, nobjs, functionname, file, line);
-
-	  if ( MEM_Debug ) memListPrintEntry(CALLOC_FUNC, item, size*nobjs, ptr, functionname, file, line);
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+#ifdef _ARCH_PWR6
+	      ival = (unsigned long) dval[j];
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
+	      z += 3;
+	    }
 	}
-
-      if ( ptr == NULL && dmemory_ExitOnError )
-	memError(functionname, file, line, size*nobjs);
-    }
-  else
-    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
-
-  return ptr;
-}
-
-
-void *memMalloc(size_t size, const char *file, const char *functionname, int line)
-{
-  void *ptr = NULL;
-
-  memInit();
-
-  if ( size > 0 )
-    {
-      ptr = malloc(size);
-
-      if ( MEM_Info )
+      for (j = 0; j < residual; j++) 
 	{
-	  memAccess++;
-
-          int item = MEM_UNDEFID;
-	  if ( ptr ) item = memListNewEntry(MALLOC_FUNC, ptr, size, 1, functionname, file, line);
-
-	  if ( MEM_Debug ) memListPrintEntry(MALLOC_FUNC, item, size, ptr, functionname, file, line);
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
 	}
-
-      if ( ptr == NULL && dmemory_ExitOnError )
-	memError(functionname, file, line, size);
+      for (j = 0; j < residual; j++) 
+	{
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
+	  z += 3;
+	}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(4);
+#endif
     }
-  else
-    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
-
-  return ptr;
-}
-
-
-void *memRealloc(void *ptrold, size_t size, const char *file, const char *functionname, int line)
-{
-  void *ptr = NULL;
-
-  memInit();
-
-  if ( size > 0 )
+  else if ( numBits == 32 )
     {
-      ptr = realloc(ptrold, size);
-
-      if ( MEM_Info )
-	{
-	  memAccess++;
-
-          int item = MEM_UNDEFID;
-	  if ( ptr )
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(5, "pack 32 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
+      unsigned int *igrib = (unsigned int *) (lGrib + z);
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+ {
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
 	    {
-	      item = memListChangeEntry(ptrold, ptr, size, functionname, file, line);
-
-	      if ( item == MEM_UNDEFID ) item = memListNewEntry(REALLOC_FUNC, ptr, size, 1, functionname, file, line);
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  if ( IS_BIGENDIAN() )
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+#ifdef _ARCH_PWR6
+		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
+		  igrib++;
+		  z += 4;
+		}
+	    }
+	  else
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
+		  z += 4;
+		}
 	    }
-
-	  if ( MEM_Debug ) memListPrintEntry(REALLOC_FUNC, item, size, ptr, functionname, file, line);
 	}
-
-      if ( ptr == NULL && dmemory_ExitOnError )
-	memError(functionname, file, line, size);
-    }
-  else
-    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, get_filename(file));
-
-  return ptr;
-}
-
-
-void memFree(void *ptr, const char *file, const char *functionname, int line)
-{
-  memInit();
-
-  if ( MEM_Info )
-    {
-      int item;
-      size_t size;
-
-      if ( (item = memListDeleteEntry(ptr, &size)) >= 0 )
+      for (j = 0; j < residual; j++) 
 	{
-	  if ( MEM_Debug ) memListPrintEntry(FREE_FUNC, item, size, ptr, functionname, file, line);
+          // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      if ( IS_BIGENDIAN() )
+	{
+	  for (j = 0; j < residual; j++) 
+	    {
+#ifdef _ARCH_PWR6
+	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
+	      igrib++;
+	      z += 4;
+	    }
 	}
       else
 	{
-	  if ( ptr && MEM_Debug  )
-	    fprintf(stderr, "%s info: memory entry at %p not found. [line %4d file %s (%s)]\n",
-		    __func__, ptr, line, get_filename(file), functionname);
+          for (j = 0; j < residual; j++) 
+	    {
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
+	      z += 4;
+	    }
 	}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(5);
+#endif
     }
-
-  free(ptr);
-}
-
-
-size_t memTotal(void)
-{
-  size_t memtotal = 0;
-#if  defined  (HAVE_MALLINFO)
-  struct mallinfo meminfo = mallinfo();
-  if ( MEM_Debug )
+  else if ( numBits > 0 && numBits <= 32 )
     {
-      fprintf(stderr, "arena      %8zu (non-mmapped space allocated from system)\n", (size_t)meminfo.arena);
-      fprintf(stderr, "ordblks    %8zu (number of free chunks)\n", (size_t)meminfo.ordblks);
-      fprintf(stderr, "smblks     %8zu (number of fastbin blocks)\n", (size_t) meminfo.smblks);
-      fprintf(stderr, "hblks      %8zu (number of mmapped regions)\n", (size_t) meminfo.hblks);
-      fprintf(stderr, "hblkhd     %8zu (space in mmapped regions)\n", (size_t) meminfo.hblkhd);
-      fprintf(stderr, "usmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.usmblks);
-      fprintf(stderr, "fsmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.fsmblks);
-      fprintf(stderr, "uordblks   %8zu (total allocated space)\n", (size_t) meminfo.uordblks);
-      fprintf(stderr, "fordblks   %8zu (total free space)\n", (size_t) meminfo.fordblks);
-      fprintf(stderr, "Memory in use:   %8zu bytes\n", (size_t) meminfo.usmblks + (size_t)meminfo.uordblks);
-      fprintf(stderr, "Total heap size: %8zu bytes\n", (size_t) meminfo.arena);
-
-      /* malloc_stats(); */
+      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
     }
-  memtotal = (size_t)meminfo.arena;
-#endif
-
-  return memtotal;
-}
-
-
-void memExitOnError(void)
-{
-  dmemory_ExitOnError = 1;
-}
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-
-#if !defined (NAMESPACE_H)
-#endif
-
-int _ExitOnError   = 1;	/* If set to 1, exit on error       */
-int _Verbose = 1;	/* If set to 1, errors are reported */
-int _Debug   = 0;       /* If set to 1, debugging           */
-
-/* If we're not using GNU C, elide __attribute__ */
-#if ! defined __GNUC__ && ! defined __attribute__
-#  define  __attribute__(x)  /*NOTHING*/
-#endif
-
-void SysError_(const char *caller, const char *fmt, ...)
-  __attribute__((noreturn));
-
-void SysError_(const char *caller, const char *fmt, ...)
-{
-  va_list args;
-  int saved_errno = errno;
-
-  va_start(args, fmt);
-
-  printf("\n");
-   fprintf(stderr, "Error (%s) : ", caller);
-  vfprintf(stderr, fmt, args);
-   fprintf(stderr, "\n");
-
-  va_end(args);
-
-  if ( saved_errno )
+  else if ( numBits == 0 )
     {
-      errno = saved_errno;
-      perror("System error message");
+    }
+  else
+    {
+      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  exit(EXIT_FAILURE);
-}
-
-
-void Error_(const char *caller, const char *fmt, ...)
-{
-  va_list args;
-
-  va_start(args, fmt);
-
-  printf("\n");
-   fprintf(stderr, "Error (%s) : ", caller);
-  vfprintf(stderr, fmt, args);
-   fprintf(stderr, "\n");
-
-  va_end(args);
-
-  if ( _ExitOnError ) exit(EXIT_FAILURE);
+  *gz = z;
 }
 
-typedef void (*cdiAbortCFunc)(const char * caller, const char * filename,
-                              const char *functionname, int line,
-                              const char * errorString, va_list ap)
-#ifdef __GNUC__
-  __attribute__((noreturn))
-#endif
-;
+#endif /* T */
 
-void cdiAbortC(const char * caller, const char * filename,
-               const char *functionname, int line,
-               const char * errorString, ... )
-{
-  va_list ap;
-  va_start(ap, errorString);
-  cdiAbortCFunc cdiAbortC_p
-    = (cdiAbortCFunc)namespaceSwitchGet(NSSWITCH_ABORT).func;
-  cdiAbortC_p(caller, filename, functionname, line, errorString, ap);
-  va_end(ap);
-}
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-void
-cdiAbortC_serial(const char *caller, const char *filename,
-                 const char *functionname, int line,
-                 const char *errorString, va_list ap)
-{
-  fprintf(stderr, "ERROR, %s, %s, line %d%s%s\nerrorString: \"",
-          functionname, filename, line, caller?", called from ":"",
-          caller?caller:"");
-  vfprintf(stderr, errorString, ap);
-  fputs("\"\n", stderr);
-  exit(EXIT_FAILURE);
-}
+#ifdef T
+#undef T
+#endif
+#define T float
+#ifdef T
 
-typedef void (*cdiWarningFunc)(const char * caller, const char * fmt,
-                               va_list ap);
 
-void Warning_(const char *caller, const char *fmt, ...)
-{
-  va_list args;
+#define round_float roundf
+#define round_double round
 
-  va_start(args, fmt);
+static
+void TEMPLATE(encode_array_common,T)(int numBits, size_t packStart, size_t datasize, GRIBPACK *lGrib,
+				     const T *data, T zref, T factor, size_t *gz)
+{
+  size_t i, z = *gz;
+  unsigned int ival;
+  int cbits, jbits;
+  unsigned int c;
+  static unsigned int mask[] = {0,1,3,7,15,31,63,127,255};
+    
+  /* code from gribw routine flist2bitstream */
 
-  if ( _Verbose )
+  cbits = 8;
+  c = 0;
+  for ( i = packStart; i < datasize; i++ )
     {
-      cdiWarningFunc cdiWarning_p
-        = (cdiWarningFunc)namespaceSwitchGet(NSSWITCH_WARNING).func;
-      cdiWarning_p(caller, fmt, args);
+      /* note float -> unsigned int .. truncate */
+      // ival = (unsigned int)(TEMPLATE(round,T)((data[i] - zref) * factor));
+      ival = (unsigned int) ((data[i] - zref) * factor + (T)0.5);
+      /*
+	if ( ival > max_nbpv_pow2 ) ival = max_nbpv_pow2;
+	if ( ival < 0 ) ival = 0;
+      */
+      jbits = numBits;
+      while ( cbits <= jbits ) 
+	{
+	  if ( cbits == 8 )
+	    {
+	      jbits -= 8;
+	      lGrib[z++] = (ival >> jbits) & 0xFF;
+	    }
+	  else
+	    {
+	      jbits -= cbits;
+	      lGrib[z++] = (GRIBPACK)((c << cbits) + ((ival >> jbits) & mask[cbits]));
+	      cbits = 8;
+	      c = 0;
+	    }
+	}
+      /* now jbits < cbits */
+      if ( jbits )
+	{
+	  c = (c << jbits) + (ival & mask[jbits]);
+	  cbits -= jbits;
+	}
     }
+  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
 
-  va_end(args);
-}
-
-void cdiWarning(const char *caller, const char *fmt, va_list ap)
-{
-  fprintf(stderr, "Warning (%s) : ", caller);
-  vfprintf(stderr, fmt, ap);
-  fputc('\n', stderr);
+  *gz = z;
 }
 
 
-void Message_(const char *caller, const char *fmt, ...)
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
 {
-  va_list args;
-
-  va_start(args, fmt);
+  U_BYTEORDER;
+  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
 
-   fprintf(stdout, "%-18s : ", caller);
-  vfprintf(stdout, fmt, args);
-   fprintf(stdout, "\n");
+  if ( IS_BIGENDIAN() )
+    {
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          // sgrib[i] = (uint16_t)(TEMPLATE(round,T)((data[i] - zref) * factor));
+          sgrib[i] = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+        }
+    }
+  else
+    {
+      uint16_t ui16;
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          // ui16 = (uint16_t)(TEMPLATE(round,T)((data[i] - zref) * factor));
+          ui16 = (uint16_t) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
+    }
 
-  va_end(args);
+  *gz += 2*datasize;
 }
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef EXSE_H
-#define EXSE_H
-
-enum {
-  EXSE_SINGLE_PRECISION = 4,
-  EXSE_DOUBLE_PRECISION = 8,
-};
+static
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
+{
+  size_t i, z = *gz;
+  uint16_t ui16;
+  T tmp;
 
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
 #endif
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
+  for ( i = 0; i < datasize; i++ )
+    {
+      // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+      tmp = ((data[i] - zref) * factor + (T)0.5);
+      ui16 = (uint16_t) tmp;
+      lGrib[z  ] = ui16 >>  8;
+      lGrib[z+1] = ui16;
+      z += 2;
+    }
 
+  *gz = z;
+}
+*/
+static
+void TEMPLATE(encode_array,T)(int numBits, size_t packStart, size_t datasize, 
+			      GRIBPACK *restrict lGrib,
+			      const T *restrict data, 
+			      T zref, T factor, size_t *gz)
+{
+#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER 
+  uint64_t start_minmax, end_minmax;
+#endif
+  uint32_t ui32;
+  size_t i, z = *gz;
+  T tmp;
 
+  data += packStart;
+  datasize -= packStart;
 
-enum {
-  EXT_HEADER_LEN = 4,
-};
+  if      ( numBits ==  8 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(2, "pack 8 bit base");
+#endif
 
+#if defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
+	{
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+	  lGrib[z  ] = (GRIBPACK)tmp;
+          z++;
+	}
 
-static int initExtLib       = 0;
-static int extDefaultPrec   = 0;
-static int extDefaultNumber = EXT_REAL;
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(2);
+#endif
+    }
+  else if ( numBits == 16 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(3, "pack 16 bit base");
+#elif defined _GET_X86_COUNTER 
+      start_minmax = _rdtsc();
+#elif defined _GET_MACH_COUNTER 
+      start_minmax = mach_absolute_time();
+#endif
+      if ( sizeof(T) == sizeof(double) )
+      	{
+          grib_encode_array_2byte_double(datasize, lGrib, (const double *) data, zref, factor, &z);
+        }
+      else
+        {
+          TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
+        }
 
+#if defined _GET_X86_COUNTER || defined _GET_MACH_COUNTER
+#if defined _GET_X86_COUNTER 
+      end_minmax = _rdtsc();
+#elif defined _GET_MACH_COUNTER 
+      end_minmax = mach_absolute_time();
+#endif
+#if defined _ENABLE_AVX
+      printf("AVX encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#elif defined _ENABLE_SSE4_1
+      printf("SSE 4.1 encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#else
+      printf("loop encoding cycles:: %" PRIu64 "\n", end_minmax-start_minmax);
+#endif  
+#endif
+      
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(3);
+#endif
+    }
+  else if ( numBits == 24 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(4, "pack 24 bit base");
+#endif
 
-/*
- * A version string.
- */
-#undef  LIBVERSION
-#define LIBVERSION      1.4.0
-#define XSTRING(x)	#x
-#define STRING(x)	XSTRING(x)
-static const char ext_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__ ;
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
+	{
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+          ui32 = (uint32_t) tmp;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+2] =  (GRIBPACK)ui32;
+          z += 3;
+	}
 
-const char *extLibraryVersion(void)
-{
-  return ext_libvers;
-}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(4);
+#endif
+    }
+  else if ( numBits == 32 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(5, "pack 32 bit base");
+#endif
 
+#if   defined (CRAY)
+#pragma _CRI ivdep
+#elif defined (SX)
+#pragma vdir nodep
+#elif defined (__uxp__)
+#pragma loop novrec
+#elif defined (__ICC)
+#pragma ivdep
+#endif
+      for ( i = 0; i < datasize; i++ )
+	{
+	  // tmp = TEMPLATE(round,T)((data[i] - zref) * factor);
+	  tmp = ((data[i] - zref) * factor + (T)0.5);
+          ui32 = (uint32_t) tmp;
+          lGrib[z  ] =  (GRIBPACK)(ui32 >> 24);
+          lGrib[z+1] =  (GRIBPACK)(ui32 >> 16);
+          lGrib[z+2] =  (GRIBPACK)(ui32 >>  8);
+          lGrib[z+3] =  (GRIBPACK)ui32;
+          z += 4;
+	}
 
-static int EXT_Debug = 0;    /* If set to 1, debugging */
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(5);
+#endif
+    }
+  else if ( numBits > 0 && numBits <= 32 )
+    {
+      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+    }
+  else if ( numBits == 0 )
+    {
+    }
+  else
+    {
+      Error("Unimplemented packing factor %d!", numBits);
+    }
 
+  *gz = z;
+}
 
-void extDebug(int debug)
+static
+void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t datasize, 
+				       GRIBPACK *restrict lGrib,
+				       const T *restrict data, 
+				       T zref, T factor, size_t *gz)
 {
-  EXT_Debug = debug;
+  U_BYTEORDER;
+  size_t i, j, z = *gz;
+#ifdef _ARCH_PWR6
+  enum { CGRIBEX__UNROLL_DEPTH_2 = 8 };
+#else
+  enum { CGRIBEX__UNROLL_DEPTH_2 = 128 };
+#endif
+  size_t residual;
+  size_t ofs;
+  T dval[CGRIBEX__UNROLL_DEPTH_2];
 
-  if ( EXT_Debug )
-    Message("debug level %d", debug);
-}
+  data += packStart;
+  datasize -= packStart;
+  residual =  datasize % CGRIBEX__UNROLL_DEPTH_2;
+  ofs = datasize - residual;
 
+  // reducing FP operations to single FMA is slowing down on pwr6 ...
 
-static
-void extLibInit()
-{
-  const char *envName = "EXT_PRECISION";
+  if      ( numBits ==  8 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(2, "pack 8 bit unrolled");
+#endif
+      unsigned char *cgrib = (unsigned char *) (lGrib + z);
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+	{
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+#ifdef _ARCH_PWR6
+	      *cgrib++ =  (unsigned long) dval[j];
+#else
+	      *cgrib++ =  (unsigned char) dval[j];
+#endif
+	    }
+	  z += CGRIBEX__UNROLL_DEPTH_2;
+	}
+      for (j = 0; j < residual; j++) 
+	{
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      for (j = 0; j < residual; j++) 
+	{
+#ifdef _ARCH_PWR6
+	  *cgrib++ = (unsigned long) dval[j];
+#else
+	  *cgrib++ = (unsigned char) dval[j];
+#endif
+	}
+      z += residual;
 
-  char *envString = getenv(envName);
-  if ( envString )
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(2);
+#endif
+    }
+  else if ( numBits == 16 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(3, "pack 16 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint16_t ival;
+#endif
+      uint16_t *sgrib = (uint16_t *) (lGrib+z);
+
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+	{
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  if ( IS_BIGENDIAN() )
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+#ifdef _ARCH_PWR6
+		  *sgrib++ = (unsigned long) dval[j];
+#else
+		  *sgrib++ = (uint16_t) dval[j];
+#endif
+		}
+	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
+	    }
+	  else
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+		  ival = (uint16_t) dval[j];
+                  *sgrib++ = gribSwapByteOrder_uint16(ival);
+		}
+	      z += 2*CGRIBEX__UNROLL_DEPTH_2;
+	    }
+	}
+      for (j = 0; j < residual; j++) 
+	{
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      if ( IS_BIGENDIAN() )
+	{
+	  for (j = 0; j < residual; j++) 
+	    {
+#ifdef _ARCH_PWR6
+	      *sgrib++ = (unsigned long) dval[j];
+#else
+              *sgrib++ = (uint16_t) dval[j];
+#endif
+	    }
+	  z += 2*residual;
+	}
+      else
+	{
+	  for (j = 0; j < residual; j++) 
+	    {
+              ival = (uint16_t) dval[j];
+	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
+	      lGrib[z+1] = (GRIBPACK)ival;
+	      z += 2;
+	    }
+	}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(3);
+#endif
+    }
+  else if ( numBits == 24 )
+    {
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(4, "pack 24 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+	{
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+#ifdef _ARCH_PWR6
+	      ival = (unsigned long) dval[j];
+#else
+	      ival = (uint32_t) dval[j];
+#endif
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+2] =  (GRIBPACK)ival;
+	      z += 3;
+	    }
+	}
+      for (j = 0; j < residual; j++) 
+	{
+	  // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      for (j = 0; j < residual; j++) 
+	{
+	  ival = (uint32_t) dval[j];
+	  lGrib[z  ] =  (GRIBPACK)(ival >> 16);
+	  lGrib[z+1] =  (GRIBPACK)(ival >>  8);
+	  lGrib[z+2] =  (GRIBPACK)ival;
+	  z += 3;
+	}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(4);
+#endif
+    }
+  else if ( numBits == 32 )
     {
-      int pos = 0;
-
-      if ( strlen(envString) == 2  )
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(5, "pack 32 bit unrolled");
+#endif
+#ifdef _ARCH_PWR6
+      unsigned long ival;
+#else
+      uint32_t ival;
+#endif
+      unsigned int *igrib = (unsigned int *) (lGrib + z);
+      for ( i = 0; i < datasize - residual; i += CGRIBEX__UNROLL_DEPTH_2 )
+ {
+	  for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+	    {
+	      // dval[j] = TEMPLATE(round,T)((data[i+j] - zref) * factor);
+	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  if ( IS_BIGENDIAN() )
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+#ifdef _ARCH_PWR6
+		  *igrib = (unsigned long) dval[j];
+#else
+		  *igrib = (uint32_t) dval[j];
+#endif
+		  igrib++;
+		  z += 4;
+		}
+	    }
+	  else
+	    {
+	      for (j = 0; j < CGRIBEX__UNROLL_DEPTH_2; j++)
+		{
+                  ival = (uint32_t) dval[j];
+		  lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+		  lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+		  lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+		  lGrib[z+3] =  (GRIBPACK)ival;
+		  z += 4;
+		}
+	    }
+	}
+      for (j = 0; j < residual; j++) 
 	{
-	  switch ( tolower((int) envString[pos]) )
+          // dval[j] = TEMPLATE(round,T)((data[ofs+j] - zref) * factor);
+	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	}
+      if ( IS_BIGENDIAN() )
+	{
+	  for (j = 0; j < residual; j++) 
 	    {
-	    case 'r':
-	      {
-		extDefaultNumber = EXT_REAL;
-		switch ( (int) envString[pos+1] )
-		  {
-		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
-		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
-		  default:
-		    Message("Invalid digit in %s: %s", envName, envString);
-		  }
-		break;
-	      }
-	    case 'c':
-	      {
-		extDefaultNumber = EXT_COMP;
-		switch ( (int) envString[pos+1] )
-		  {
-		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
-		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
-		  default:
-		    Message("Invalid digit in %s: %s", envName, envString);
-		  }
-		break;
-	      }
-	    default:
-              {
-                Message("Invalid character in %s: %s", envName, envString);
-                break;
-              }
-            }
+#ifdef _ARCH_PWR6
+	      *igrib = (unsigned long) dval[j];
+#else
+	      *igrib = (uint32_t) dval[j];
+#endif
+	      igrib++;
+	      z += 4;
+	    }
+	}
+      else
+	{
+          for (j = 0; j < residual; j++) 
+	    {
+	      ival = (uint32_t) dval[j];
+	      lGrib[z  ] =  (GRIBPACK)(ival >> 24);
+	      lGrib[z+1] =  (GRIBPACK)(ival >> 16);
+	      lGrib[z+2] =  (GRIBPACK)(ival >>  8);
+	      lGrib[z+3] =  (GRIBPACK)ival;
+	      z += 4;
+	    }
 	}
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(5);
+#endif
+    }
+  else if ( numBits > 0 && numBits <= 32 )
+    {
+      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+    }
+  else if ( numBits == 0 )
+    {
+    }
+  else
+    {
+      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  initExtLib = 1;
-}
-
-static
-void extInit(extrec_t *extp)
-{
-  extp->checked    = 0;
-  extp->byteswap   = 0;
-  extp->prec       = 0;
-  extp->number     = extDefaultNumber;
-  extp->datasize   = 0;
-  extp->buffersize = 0;
-  extp->buffer     = NULL;
+  *gz = z;
 }
 
+#endif /* T */
 
-void *extNew(void)
-{
-  if ( ! initExtLib ) extLibInit();
-
-  extrec_t *extp = (extrec_t *) Malloc(sizeof(extrec_t));
-
-  extInit(extp);
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-  return (void*)extp;
-}
 
+#ifdef T
+#undef T
+#endif
+#define T double
+#ifdef T
 
-void extDelete(void *ext)
+/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
+static
+void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 {
-  extrec_t *extp = (extrec_t *) ext;
+  long z = *gribLen;
+  int exponent, mantissa;
+  int ival;
+  int pvoffset = 0xFF;
+  int gdslen = 32;
 
-  if ( extp )
-    {
-      if ( extp->buffer ) Free(extp->buffer);
-      Free(extp);
-    }
-}
+  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
 
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
 
-int extCheckFiletype(int fileID, int *swap)
-{
-  size_t fact = 0;
-  size_t data =  0;
-  size_t dimxy = 0;
-  int found = 0;
-  unsigned char buffer[40], *pbuf;
+  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
 
-  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
+  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
 
-  size_t blocklen  = (size_t) get_UINT32(buffer);
-  size_t sblocklen = (size_t) get_SUINT32(buffer);
+  gdslen += ISEC2_NumVCP * 4;
 
-  if ( EXT_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+  Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
+  Put1Byte(ISEC2_NumVCP);       /*  3    NV */
+  Put1Byte(pvoffset);           /*  4    PV */
+  Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
 
-  if ( blocklen == 16 )
+  if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
     {
-     *swap = 0;
-      fact = blocklen/4;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
-      pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
+      Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
+      Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
+      Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
+      Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
+      Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
+      PutnZero(18);             /* 14-31 reserved                 */
     }
-  else if ( blocklen == 32 )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
     {
-     *swap = 0;
-      fact = blocklen/4;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
-      pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT64(pbuf);
-      pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
+      Put2Byte(ISEC2_GME_NI2);
+      Put2Byte(ISEC2_GME_NI3);
+      Put3Byte(ISEC2_GME_ND);
+      Put3Byte(ISEC2_GME_NI);
+      Put1Byte(ISEC2_GME_AFlag);
+      Put3Int(ISEC2_GME_LatPP);
+      Put3Int(ISEC2_GME_LonPP);
+      Put3Int(ISEC2_GME_LonMPL);
+      Put1Byte(ISEC2_GME_BFlag);
+      PutnZero(5);
     }
-  else if ( sblocklen == 16 )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
     {
-     *swap = 1;
-      fact = sblocklen/4;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
-      pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
+      Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
+
+      Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
+      Put3Int(ISEC2_FirstLat);
+      Put3Int(ISEC2_FirstLon);
+      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
+      Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
+      Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
+      Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
+      Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */  
+      Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
+      Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */  
+      Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
+      PutnZero(2);                     /* 34-41 */
     }
-  else if ( sblocklen == 32 )
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
     {
-     *swap = 1;
-      fact = sblocklen/4;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
-      pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT64(pbuf);
-      pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
-    }
+      int numlon = ISEC2_Reduced ? 0xFFFF : ISEC2_NumLon;
+      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
 
-  fileRewind(fileID);
+      Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
+      Put3Int(ISEC2_FirstLat);
+      Put3Int(ISEC2_FirstLon);
+      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
+      Put3Int(ISEC2_LastLat);
+      Put3Int(ISEC2_LastLon);
+      unsigned lonIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LonIncr;
+      unsigned latIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LatIncr;
+      Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
+      if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
+	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
+      else
+	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
 
-  if      ( data && dimxy*fact   == data ) found = 1;
-  else if ( data && dimxy*fact*2 == data ) found = 1;
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      PutnZero(4);                     /* 28-31 reserved                 */
 
-  if ( EXT_Debug )
+      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+	{
+	  Put3Int(ISEC2_LatSP);
+	  Put3Int(ISEC2_LonSP);
+	  Put1Real((double)(FSEC2_RotAngle));
+	}
+    }
+  else
     {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimxy = %lu data = %lu", dimxy, data);
+      Error("Unsupported grid type %d", ISEC2_GridType);
     }
 
-  return found;
-}
-
-
-int extInqHeader(void *ext, int *header)
-{
-  extrec_t *extp = (extrec_t *) ext;
-
-  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
-    header[i] = extp->header[i];
+#if defined (SX)
+#pragma vdir novector     /* vectorization gives wrong results on NEC */
+#endif
+  for ( long i = 0; i < ISEC2_NumVCP; ++i )
+    {
+      Put1Real((double)(fsec2[10+i]));
+    }
 
-  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+  if ( ISEC2_Reduced )
+    for ( long i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
 
-  return 0;
+  *gribLen = z;
 }
 
-
-int extDefHeader(void *ext, const int *header)
+/* GRIB BLOCK 3 - BIT MAP SECTION */
+static
+void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
 {
-  extrec_t *extp = (extrec_t *) ext;
-
-  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
-    extp->header[i] = header[i];
+  long z = *gribLen;
+  static bool lmissvalinfo = true;
+  //  unsigned int c, imask;
 
-  extp->datasize = (size_t)header[3];
-  if ( extp->number == EXT_COMP ) extp->datasize *= 2;
+  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
+    {
+      lmissvalinfo = false;
+      Message("Missing value = NaN is unsupported!");
+    }
 
-  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+  long bitmapSize = ISEC4_NumValues;
+  long imaskSize = ((bitmapSize+7)>>3)<<3;
+  GRIBPACK *bitmap = &lGrib[z+6];
+  long fsec4size = 0;
 
-  return 0;
-}
+#if defined (VECTORCODE)
+  unsigned int *imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
+  memset(imask, 0, imaskSize*sizeof(int));
 
-static
-int extInqData(extrec_t *extp, int prec, void *data)
-{
-  size_t i;
-  int ierr = 0;
-  int byteswap = extp->byteswap;
-  size_t datasize = extp->datasize;
-  void *buffer   = extp->buffer;
-  int rprec    = extp->prec;
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+  for ( long i = 0; i < bitmapSize; i++ )
+    {
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  imask[i] = 1;
+	}
+    }
 
-  switch ( rprec )
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+  for ( long i = 0; i < imaskSize/8; i++ )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( sizeof(FLT32) == 4 )
-	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
+      bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
+	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
+	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
+	          (imask[i*8+6] << 1) | (imask[i*8+7]);
+    }
 
-	    if ( rprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT32));
-	    else
-	      for ( i = 0; i < datasize; ++i )
-		((double *) data)[i] = (double) ((float *) buffer)[i];
-	  }
-	else
-	  {
-	    Error("not implemented for %d byte float", sizeof(FLT32));
-	  }
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-	if ( sizeof(FLT64) == 8 )
-	  {
-	    if ( byteswap ) swap8byte(buffer, datasize);
+  Free(imask);
+#else
+  for ( long i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
 
-	    if ( rprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT64));
-	    else
-	      for ( i = 0; i < datasize; ++i )
-		((float *) data)[i] = (float) ((double *) buffer)[i];
-	  }
-	else
-	  {
-	    Error("not implemented for %d byte float", sizeof(FLT64));
-	  }
-	break;
-    default:
-      {
-	Error("unexpected data precision %d", rprec);
-	break;
-      }
+  for ( long i = 0; i < bitmapSize; i++ )
+    {
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
+	}
     }
+#endif
 
-  return ierr;
-}
-
+  long bmsLen = imaskSize/8 + 6;
+  long bmsUnusedBits = imaskSize - bitmapSize;
 
-int extInqDataSP(void *ext, float *data)
-{
-  return extInqData((extrec_t *)ext, EXSE_SINGLE_PRECISION, (void *) data);
-}
+  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
+  Put1Byte(bmsUnusedBits);
+  Put2Byte(0);
 
+  *gribLen += bmsLen;
 
-int extInqDataDP(void *ext, double *data)
-{
-  return extInqData((extrec_t *)ext, EXSE_DOUBLE_PRECISION, (void *) data);
+  *datasize = fsec4size;
 }
 
-
-static int extDefData(void *ext, int prec, const void *data)
+/* GRIB BLOCK 4 - BINARY DATA SECTION */
+static
+int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
+			  long *datstart, long *datsize, int code)
 {
-  extrec_t *extp = (extrec_t *) ext;
-  size_t i;
-  int rprec;
-  void *buffer;
-
-  if ( extDefaultPrec ) rprec = extDefaultPrec;
-  else                  rprec = extp->prec;
-
-  if ( ! rprec ) rprec = prec;
-
-  extp->prec = rprec;
-
-  int *header = extp->header;
-
-  size_t datasize = (size_t)header[3];
-  if ( extp->number == EXT_COMP ) datasize *= 2;
-  size_t blocklen = datasize * (size_t)rprec;
-
-  extp->datasize = datasize;
-
-  size_t buffersize = extp->buffersize;
+  /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
+  /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  if ( buffersize != blocklen )
-    {
-      buffersize = blocklen;
-      buffer = extp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      extp->buffer = buffer;
-      extp->buffersize = buffersize;
-    }
-  else
-    buffer = extp->buffer;
+  size_t z = (size_t)*gribLen;
+  long i;
+  int numBits;
+  int ival;
+  long PackStart = 0;
+  int Flag = 0;
+  int binscale = 0;
+  int bds_head = 11;
+  int bds_ext = 0;
+  /* ibits = BitsPerInt; */
+  int exponent, mantissa;
+  bool lspherc = false;
+  int isubset = 0, itemp = 0, itrunc = 0;
+  T factor = 1, fmin, fmax;
+  const double jpepsln = 1.0e-12; /* -----> tolerance used to check equality     */
+                                  /*        of floating point numbers - needed   */
+		                  /*        on some platforms (eg vpp700, linux) */
+  extern int CGRIBEX_Const;       /* 1: Don't pack constant fields on regular grids */
 
-  switch ( rprec )
+  if ( isec2 )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( rprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT32));
-	else
-	  for ( i = 0; i < datasize; i++ )
-	    ((float *) buffer)[i] = (float) ((double *) data)[i];
+      /* If section 2 is present, it says if data is spherical harmonic */
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	if ( rprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT64));
-	else
-	  for ( i = 0; i < datasize; i++ )
-	    ((double *) buffer)[i] = (double) ((float *) data)[i];
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", rprec);
-        break;
-      }
+      isec4[2] = lspherc ? 128 : 0;
     }
+  else
+    {
+      /* Section 4 says if it's spherical harmonic data.. */
 
-  return 0;
-}
-
-
-int extDefDataSP(void *ext, const float *data)
-{
-  return extDefData(ext, EXSE_SINGLE_PRECISION, (void *) data);
-}
-
+      lspherc = ( isec4[2] == 128 );
+    }
 
-int extDefDataDP(void *ext, const double *data)
-{
-  return extDefData(ext, EXSE_DOUBLE_PRECISION, (void *) data);
-}
+  /* Complex packing supported for spherical harmonics. */
 
+  bool lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
+                  ( lspherc && isec2 && ( isec2[5] == 2 ) );
 
-int extRead(int fileID, void *ext)
-{
-  extrec_t *extp = (extrec_t *) ext;
-  size_t i;
-  void *buffer;
-  int status;
+  /* Check input specification is consistent */
 
-  if ( ! extp->checked )
+  if ( lcomplex && isec2 )
     {
-      status = extCheckFiletype(fileID, &extp->byteswap);
-      if ( status == 0 ) Error("Not a EXTRA file!");
-      extp->checked = 1;
+      if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
+	{
+	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
+	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
+	  return (807);
+	}
+      else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
+	{
+	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
+	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
+	  return (807);
+        }
+      else if ( lcomplex )
+	{
+	  /*
+	    Truncation of full spectrum, which is supposed triangular,
+	    has to be diagnosed. Define also sub-set truncation.
+	  */
+	  isubset = isec4[17];
+	  /* When encoding, use the total number of data. */
+	  itemp   = isec4[0];
+	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
+	}
     }
 
-  int byteswap = extp->byteswap;
-
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
-
-  if ( fileEOF(fileID) ) return -1;
+  if ( decscale )
+    {
+      T scale = (T) pow(10.0, (double) decscale);
+      for ( long i = 0; i < datasize; ++i ) data[i] *= scale;
+    }
 
-  if ( EXT_Debug )
-    Message("blocklen = %lu", blocklen);
+  if ( lspherc )
+    {
+      if ( lcomplex )
+	{
+	  int jup  = isubset;
+	  int ioff = (jup+1)*(jup+2);
+	  bds_ext = 4 + 3 + 4*ioff;
+	  PackStart = ioff;
+	  Flag = 192;
+	}
+      else
+	{
+	  bds_ext = 4;
+	  PackStart = 1;
+	  Flag = 128;
+	}
+    }
 
-  size_t hprec = blocklen / EXT_HEADER_LEN;
+  *datstart = bds_head + bds_ext;
 
-  extp->prec = (int)hprec;
+  int nbpv = numBits = ISEC4_NumBits;
 
-  switch ( hprec )
+  if ( lspherc && lcomplex )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-        INT32 tempheader[4];
-	binReadInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader);
-
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          extp->header[i] = (int)tempheader[i];
+      int pcStart, pcScale;
+      pcStart = isubset;
+      pcScale = isec4[16];
+      TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
+    }
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-        INT64 tempheader[4];
-	binReadInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader);
+  fmin = fmax = data[PackStart];
 
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          extp->header[i] = (int)tempheader[i];
+  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
 
-	break;
-      }
-    default:
-      {
-	Error("Unexpected header precision %d", hprec);
-        break;
-      }
-    }
+  double zref = (double)fmin;
 
-  size_t blocklen2 = binReadF77Block(fileID, byteswap);
 
-  if ( blocklen2 != blocklen )
+  if ( CGRIBEX_Const && !lspherc )
     {
-      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
+      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
     }
 
-  extp->datasize = (size_t)extp->header[3];
 
-  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  blocklen = binReadF77Block(fileID, byteswap);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
-  size_t buffersize = (size_t)extp->buffersize;
+  Flag += unused_bits;
 
-  if ( buffersize < blocklen )
-    {
-      buffersize = blocklen;
-      buffer = extp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      extp->buffer = buffer;
-      extp->buffersize = buffersize;
-    }
-  else
-    buffer = extp->buffer;
 
-  size_t dprec = blocklen / extp->datasize;
+  /*
+    Adjust number of bits per value if full integer length to
+    avoid hitting most significant bit (sign bit).
+  */
+  /* if( nbpv == ibits ) nbpv = nbpv - 1; */
+  /*
+    Calculate the binary scaling factor to spread the range of
+    values over the number of bits per value.
+    Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floats
+    as a guideline).           
+  */
+  double range = fabs(fmax - fmin);
 
-  if ( dprec == hprec )
+  if ( fabs(fmin) < FLT_MIN ) fmin = 0;
+  /*
+    Have to allow tolerance in comparisons on some platforms
+    (eg vpp700 and linux), such as 0.9999999999999999 = 1.0,
+    to avoid clipping ranges which are a power of 2.
+  */
+  if ( range <= jpepsln )
     {
-      extp->number = EXT_REAL;
+      binscale = 0;
     }
-  else if ( dprec == 2*hprec )
+  else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
     {
-      dprec /= 2;
-      extp->datasize *= 2;
-      extp->number = EXT_COMP;
+      binscale = 0;
+    }
+  else if ( fabs(range-1.0) <= jpepsln )
+    {
+      binscale = 1 - nbpv;
+    }
+  else if ( range > 1.0 )
+    {
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      int jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
+      else
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
+    }
+  else
+    {
+      double rangec = range - jpepsln, p05 = 0.5;
+      int jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
+	{
+          p05 *= 0.5;
+          jloop++;
+	}
+      if ( jloop < 127 )
+	{
+	  binscale = 1 - jloop - nbpv;
+	}
+      else
+	{
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
+	}
     }
 
-  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
+
+  if ( binscale != 0 )
     {
-      Warning("Unexpected data precision %d", dprec);
-      return -1;
+      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
+
+      factor = (T)intpow2(-binscale);
     }
 
-  fileRead(fileID, buffer, blocklen);
+  ref2ibm(&zref, BitsPerInt);
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+  Put3Byte(blockLength);      /*  0-2 Length of Block 4        */
+  Put1Byte(Flag);             /*  3   Flag & Unused bits       */
+  if ( binscale < 0 ) binscale = 32768 - binscale;
+  Put2Byte(binscale);         /*  4-5 Scale factor             */
+  Put1Real(zref);             /*  6-9 Reference value          */
+  Put1Byte(nbpv);             /*   10 Packing size             */
 
-  if ( blocklen2 != blocklen )
+  if ( lspherc )
     {
-      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
+      if ( lcomplex )
+	{
+	  int jup = isubset;
+	  int ioff = (int)z + bds_ext;
+	  if ( ioff > 0xFFFF ) ioff = 0;
+	  Put2Byte(ioff);
+	  Put2Int(isec4[16]);
+	  Put1Byte(jup);
+	  Put1Byte(jup);
+	  Put1Byte(jup);
+	  for ( i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
+	}
+      else
+	{
+	  Put1Real((double)(data[0]));
+	}
     }
 
+  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
+
+#if  defined  (_ARCH_PWR6)
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+#else
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+#endif
+
+  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
+
+  *gribLen = (long)z;
+
   return 0;
 }
 
 
-int extWrite(int fileID, void *ext)
+void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
+			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
+			     int kleng, int *kword, int efunc, int *kret)
 {
-  extrec_t *extp = (extrec_t *) ext;
-  size_t i;
-  union { INT32 i32[EXT_HEADER_LEN]; INT64 i64[EXT_HEADER_LEN]; } tempheader;
-  int byteswap = extp->byteswap;
-  int rprec  = extp->prec;
-  int number = extp->number;
-  int *header = extp->header;
+  long gribLen = 0; // Counter of GRIB length for output
+  long fsec4size = 0;
+  long datstart, datsize;
 
-  /* write header record */
-  size_t blocklen = EXT_HEADER_LEN * (size_t)rprec;
+  UNUSED(isec3);
+  UNUSED(efunc);
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  grsdef();
 
-  switch ( rprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          tempheader.i32[i] = (INT32) header[i];
+  unsigned char *CGrib = (unsigned char *) kgrib;
 
-	binWriteInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader.i32);
+  bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          tempheader.i64[i] = (INT64) header[i];
+  // set max header len
+  size_t len = 16384;
 
-	binWriteInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader.i64);
+  // add data len
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected header precision %d", rprec);
-        break;
-      }
-    }
+  len += numBytes*(size_t)klenp;
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  // add bitmap len
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
-  size_t datasize = (size_t)header[3];
-  if ( number == EXT_COMP ) datasize *= 2;
-  blocklen = datasize * (size_t)rprec;
+#if defined (VECTORCODE)
+  GRIBPACK *lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
+  if ( lGrib == NULL ) SysError("No Memory!");
+#else
+  GRIBPACK *lGrib = CGrib;
+#endif
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  long isLen = 8;
+  encodeIS(lGrib, &gribLen);
+  GRIBPACK *lpds = &lGrib[isLen];
+  long pdsLen = getPdsLen(isec1);
 
-  extp->datasize = datasize;
+  encodePDS(lpds, pdsLen,  isec1);
+  gribLen += pdsLen;
+  /*
+  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
+    {
+      static bool lwarn_cplx = true;
 
-  void *buffer = extp->buffer;
+      if ( lwarn_cplx )
+	Message("Complex packing of spectral data unsupported, using simple packing!");
 
-  switch ( rprec )
+      isec2[5] = 1;
+      isec4[3] = 0;
+
+      lwarn_cplx = false;
+    }
+  */
+  if ( gdsIncluded ) TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
+  /*
+    ----------------------------------------------------------------
+    BMS Bit-Map Section Section (Section 3)
+    ----------------------------------------------------------------
+  */ 
+  if ( bmsIncluded )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", rprec);
-        break;
-      }
+      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
+    }
+  else
+    {
+      fsec4size = ISEC4_NumValues;
     }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  long bdsstart = gribLen;
+  int status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
+                                     isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
+  if ( status )
+    {
+      *kret = status;
+      return;
+    }
 
-  return 0;
-}
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  encodeES(lGrib, &gribLen, bdsstart);
 
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>  // gettimeofday()
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
+    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
+#if defined (VECTORCODE)
+  if ( (size_t) gribLen > len )
+    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
 
+  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
 
-#if ! defined (O_BINARY)
-#define O_BINARY 0
+  Free(lGrib);
 #endif
 
-#ifndef strdupx
-#ifndef strdup
-char *strdup(const char *s);
-#endif
-#define strdupx  strdup
-/*
-#define strdupx(s)                                \
-({                                                \
-   const char *__old = (s);                       \
-   size_t __len = strlen(__old) + 1;              \
-   char *__new = (char *) Malloc(__len);          \
-   (char *) memcpy(__new, __old, __len);          \
-})
-*/
-#endif
+  ISEC0_GRIB_Len     = (int)gribLen;
+  ISEC0_GRIB_Version = 1;
 
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
-#if defined (HAVE_MMAP)
-#  include <sys/mman.h> /* mmap() is defined in this header */
-#endif
+  *kret = status;
+}
 
+#endif /* T */
 
-#if ! defined   (FALSE)
-#  define  FALSE  0
-#endif
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-#if ! defined   (TRUE)
-#  define  TRUE   1
+#ifdef T
+#undef T
 #endif
+#define T float
+#ifdef T
 
-/* #define  MAX_FILES  FOPEN_MAX */
-#define  MAX_FILES  4096
+/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
+static
+void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
+{
+  long z = *gribLen;
+  int exponent, mantissa;
+  int ival;
+  int pvoffset = 0xFF;
+  int gdslen = 32;
 
-static int _file_max = MAX_FILES;
+  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
 
-static void file_initialize(void);
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
 
-static int _file_init = FALSE;
+  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
 
-#if  defined  (HAVE_LIBPTHREAD)
-#include <pthread.h>
+  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
 
-static pthread_once_t  _file_init_thread = PTHREAD_ONCE_INIT;
-static pthread_mutex_t _file_mutex;
+  gdslen += ISEC2_NumVCP * 4;
 
-#  define FILE_LOCK()         pthread_mutex_lock(&_file_mutex)
-#  define FILE_UNLOCK()       pthread_mutex_unlock(&_file_mutex)
-#  define FILE_INIT()        \
-   if ( _file_init == FALSE ) pthread_once(&_file_init_thread, file_initialize)
+  Put3Byte(gdslen);             /*  0- 2 Length of Block 2 Byte 0 */
+  Put1Byte(ISEC2_NumVCP);       /*  3    NV */
+  Put1Byte(pvoffset);           /*  4    PV */
+  Put1Byte(ISEC2_GridType);     /*  5    LatLon=0 Gauss=4 Spectral=50 */
+
+  if ( ISEC2_GridType == GRIB1_GTYPE_SPECTRAL )
+    {
+      Put2Byte(ISEC2_PentaJ);   /*  6- 7 Pentagonal resolution J  */
+      Put2Byte(ISEC2_PentaK);   /*  8- 9 Pentagonal resolution K  */
+      Put2Byte(ISEC2_PentaM);   /* 10-11 Pentagonal resolution M  */
+      Put1Byte(ISEC2_RepType);  /* 12    Representation type      */
+      Put1Byte(ISEC2_RepMode);  /* 13    Representation mode      */
+      PutnZero(18);             /* 14-31 reserved                 */
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_GME )
+    {
+      Put2Byte(ISEC2_GME_NI2);
+      Put2Byte(ISEC2_GME_NI3);
+      Put3Byte(ISEC2_GME_ND);
+      Put3Byte(ISEC2_GME_NI);
+      Put1Byte(ISEC2_GME_AFlag);
+      Put3Int(ISEC2_GME_LatPP);
+      Put3Int(ISEC2_GME_LonPP);
+      Put3Int(ISEC2_GME_LonMPL);
+      Put1Byte(ISEC2_GME_BFlag);
+      PutnZero(5);
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
+    {
+      Put2Byte(ISEC2_NumLon);          /*  6- 7 Longitudes               */
+
+      Put2Byte(ISEC2_NumLat);          /*  8- 9 Latitudes                */
+      Put3Int(ISEC2_FirstLat);
+      Put3Int(ISEC2_FirstLon);
+      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
+      Put3Int(ISEC2_Lambert_Lov);      /* 17-19 */
+      Put3Int(ISEC2_Lambert_dx);       /* 20-22 */
+      Put3Int(ISEC2_Lambert_dy);       /* 23-25 */
+      Put1Byte(ISEC2_Lambert_ProjFlag);/* 26    Projection flag          */
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      Put3Int(ISEC2_Lambert_LatS1);    /* 28-30 */  
+      Put3Int(ISEC2_Lambert_LatS2);    /* 31-33 */
+      Put3Int(ISEC2_Lambert_LatSP);    /* 34-36 */  
+      Put3Int(ISEC2_Lambert_LonSP);    /* 37-39 */
+      PutnZero(2);                     /* 34-41 */
+    }
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
+	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
+	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+    {
+      int numlon = ISEC2_Reduced ? 0xFFFF : ISEC2_NumLon;
+      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
+
+      Put2Byte(ISEC2_NumLat);          /*  8- 9 Number of Latitudes      */
+      Put3Int(ISEC2_FirstLat);
+      Put3Int(ISEC2_FirstLon);
+      Put1Byte(ISEC2_ResFlag);         /* 16    Resolution flag          */
+      Put3Int(ISEC2_LastLat);
+      Put3Int(ISEC2_LastLon);
+      unsigned lonIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LonIncr;
+      unsigned latIncr = (ISEC2_ResFlag == 0) ? 0xFFFF : (unsigned)ISEC2_LatIncr;
+      Put2Byte(lonIncr);               /* 23-24 i - direction increment  */
+      if ( ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN )
+	Put2Byte(ISEC2_NumPar);        /* 25-26 Latitudes Pole->Equator  */
+      else
+	Put2Byte(latIncr);             /* 25-26 j - direction increment  */
 
-#else
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      PutnZero(4);                     /* 28-31 reserved                 */
 
-#  define FILE_LOCK()
-#  define FILE_UNLOCK()
-#  define FILE_INIT()        \
-   if ( _file_init == FALSE ) file_initialize()
+      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+	{
+	  Put3Int(ISEC2_LatSP);
+	  Put3Int(ISEC2_LonSP);
+	  Put1Real((double)(FSEC2_RotAngle));
+	}
+    }
+  else
+    {
+      Error("Unsupported grid type %d", ISEC2_GridType);
+    }
 
+#if defined (SX)
+#pragma vdir novector     /* vectorization gives wrong results on NEC */
 #endif
+  for ( long i = 0; i < ISEC2_NumVCP; ++i )
+    {
+      Put1Real((double)(fsec2[10+i]));
+    }
 
+  if ( ISEC2_Reduced )
+    for ( long i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
 
-typedef struct
-{
-  int        self;
-  int        flag;           /* access and error flag         */
-  int        eof;            /* end of file flag              */
-  int        fd;             /* file descriptor used for read */
-  FILE      *fp;             /* FILE pointer used for write   */
-  char      *name;           /* file name                     */
-  off_t      size;           /* file size                     */
-  off_t      position;       /* file position                 */
-  long       access;         /* file access                   */
-  off_t      byteTrans;      /*                               */
-  size_t     blockSize;      /* file block size               */
-  int        mode;           /* file access mode              */
-  short      type;           /* file type ( 1:open 2:fopen )  */
-  short      bufferType;     /* buffer type ( 1:std 2:mmap )  */
-  size_t     bufferSize;     /* file buffer size              */
-  size_t     mappedSize;     /* mmap buffer size              */
-  char      *buffer;         /* file buffer                   */
-  long       bufferNumFill;  /* number of buffer fill         */
-  char      *bufferPtr;      /* file buffer pointer           */
-  off_t      bufferPos;
-  off_t      bufferStart;
-  off_t      bufferEnd;
-  size_t     bufferCnt;
-  double     time_in_sec;
+  *gribLen = z;
 }
-bfile_t;
 
+/* GRIB BLOCK 3 - BIT MAP SECTION */
+static
+void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
+{
+  long z = *gribLen;
+  static bool lmissvalinfo = true;
+  //  unsigned int c, imask;
 
-enum F_I_L_E_Flags
-  {
-    FILE_READ  =  01,
-    FILE_WRITE =  02,
-    FILE_UNBUF =  04,
-    FILE_EOF   = 010,
-    FILE_ERROR = 020
-  };
-
+  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
+    {
+      lmissvalinfo = false;
+      Message("Missing value = NaN is unsupported!");
+    }
 
-static int FileInfo  = FALSE;
+  long bitmapSize = ISEC4_NumValues;
+  long imaskSize = ((bitmapSize+7)>>3)<<3;
+  GRIBPACK *bitmap = &lGrib[z+6];
+  long fsec4size = 0;
 
+#if defined (VECTORCODE)
+  unsigned int *imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
+  memset(imask, 0, imaskSize*sizeof(int));
 
-#if ! defined (MIN_BUF_SIZE)
-#  define  MIN_BUF_SIZE  131072L
+#if defined (CRAY)
+#pragma _CRI ivdep
 #endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+  for ( long i = 0; i < bitmapSize; i++ )
+    {
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  imask[i] = 1;
+	}
+    }
 
+#if defined (CRAY)
+#pragma _CRI ivdep
+#endif
+#if defined (SX)
+#pragma vdir nodep
+#endif
+#ifdef __uxpch__
+#pragma loop novrec
+#endif
+  for ( long i = 0; i < imaskSize/8; i++ )
+    {
+      bitmap[i] = (imask[i*8+0] << 7) | (imask[i*8+1] << 6) |
+	          (imask[i*8+2] << 5) | (imask[i*8+3] << 4) |
+	          (imask[i*8+4] << 3) | (imask[i*8+5] << 2) |
+	          (imask[i*8+6] << 1) | (imask[i*8+7]);
+    }
 
-static size_t FileBufferSizeMin = MIN_BUF_SIZE;
-static long   FileBufferSizeEnv = -1;
-static short  FileBufferTypeEnv =  0;
-
-static short  FileTypeRead  = FILE_TYPE_OPEN;
-static short  FileTypeWrite = FILE_TYPE_FOPEN;
-static int    FileFlagWrite = 0;
-
-static int    FILE_Debug = 0;   /* If set to 1, debugging */
-
-
-static void file_table_print(void);
-
-/*
- * A version string.
- */
-#undef   LIBVERSION
-#define  LIBVERSION      1.8.2
-#define  XSTRING(x)	 #x
-#define  STRING(x) 	 XSTRING(x)
-static const char file_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__;
+  Free(imask);
+#else
+  for ( long i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
 
-/*
-  21/05/2004  1.3.2 set min I/O Buffersize to 128k
-  31/05/2005  1.4.0 replace fileTable by _fileList
-  26/08/2005  1.4.1 fileClose with return value
-                    checks for all fileptr
-  01/09/2005  1.5.0 thread safe version
-  06/11/2005  1.5.1 add filePtrEOF, filePtr, filePtrGetc
-  03/02/2006  1.5.2 ansi C: define getpagesize and strdupx
-  27/12/2007  1.6.0 add FILE_TYPE_FOPEN
-  24/03/2008  1.6.1 add O_BINARY if available
-                    remove default HAVE_MMAP
-                    use HAVE_STRUCT_STAT_ST_BLKSIZE
-  22/08/2010  1.7.0 refactor
-  11/11/2010  1.7.1 update for changed interface of error.h
-  02/02/2012  1.8.0 cleanup
-  16/11/2012  1.8.1 added support for unbuffered write
-  27/06/2013  1.8.2 added env. var. FILE_TYPE_WRITE (1:open; 2:fopen)
- */
+  for ( long i = 0; i < bitmapSize; i++ )
+    {
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
+	}
+    }
+#endif
 
+  long bmsLen = imaskSize/8 + 6;
+  long bmsUnusedBits = imaskSize - bitmapSize;
 
-typedef struct _filePtrToIdx {
-  int idx;
-  bfile_t *ptr;
-  struct _filePtrToIdx *next;
-} filePtrToIdx;
+  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
+  Put1Byte(bmsUnusedBits);
+  Put2Byte(0);
 
+  *gribLen += bmsLen;
 
-static filePtrToIdx *_fileList  = NULL;
-static filePtrToIdx *_fileAvail = NULL;
+  *datasize = fsec4size;
+}
 
+/* GRIB BLOCK 4 - BINARY DATA SECTION */
 static
-void file_list_new(void)
+int TEMPLATE(encodeBDS,T)(GRIBPACK *lGrib, long *gribLen, int decscale, int *isec2, int *isec4, long datasize, T *data,
+			  long *datstart, long *datsize, int code)
 {
-  assert(_fileList == NULL);
+  /* Uwe Schulzweida, 11/04/2003 : Check that number of bits per value is not exceeded */
+  /* Uwe Schulzweida,  6/05/2003 : Copy result to fpval to prevent integer overflow */
 
-  _fileList = (filePtrToIdx *) Malloc((size_t)_file_max * sizeof (filePtrToIdx));
-}
+  size_t z = (size_t)*gribLen;
+  long i;
+  int numBits;
+  int ival;
+  long PackStart = 0;
+  int Flag = 0;
+  int binscale = 0;
+  int bds_head = 11;
+  int bds_ext = 0;
+  /* ibits = BitsPerInt; */
+  int exponent, mantissa;
+  bool lspherc = false;
+  int isubset = 0, itemp = 0, itrunc = 0;
+  T factor = 1, fmin, fmax;
+  const double jpepsln = 1.0e-12; /* -----> tolerance used to check equality     */
+                                  /*        of floating point numbers - needed   */
+		                  /*        on some platforms (eg vpp700, linux) */
+  extern int CGRIBEX_Const;       /* 1: Don't pack constant fields on regular grids */
 
-static
-void file_list_delete(void)
-{
-  if ( _fileList )
+  if ( isec2 )
     {
-      Free(_fileList);
-      _fileList = NULL;
-    }
-}
+      /* If section 2 is present, it says if data is spherical harmonic */
 
-static
-void file_init_pointer(void)
-{
-  int  i;
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
 
-  for ( i = 0; i < _file_max; i++ )
-    {
-      _fileList[i].next = _fileList + i + 1;
-      _fileList[i].idx  = i;
-      _fileList[i].ptr  = 0;
+      isec4[2] = lspherc ? 128 : 0;
     }
+  else
+    {
+      /* Section 4 says if it's spherical harmonic data.. */
 
-  _fileList[_file_max-1].next = 0;
+      lspherc = ( isec4[2] == 128 );
+    }
 
-  _fileAvail = _fileList;
-}
+  /* Complex packing supported for spherical harmonics. */
 
-static
-bfile_t *file_to_pointer(int idx)
-{
-  bfile_t *fileptr = NULL;
+  bool lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
+                  ( lspherc && isec2 && ( isec2[5] == 2 ) );
 
-  FILE_INIT();
+  /* Check input specification is consistent */
 
-  if ( idx >= 0 && idx < _file_max )
+  if ( lcomplex && isec2 )
     {
-      FILE_LOCK();
-
-      fileptr = _fileList[idx].ptr;
-
-      FILE_UNLOCK();
+      if ( ( isec4[3] != 64 ) && ( isec2[5] == 2 ) )
+	{
+	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
+	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
+	  return (807);
+	}
+      else if ( ( isec4[3] == 64 ) && ( isec2[5] != 2 ) )
+	{
+	  gprintf(__func__, "  COMPLEX mismatch. isec4[3] = %d\n", isec4[3]);
+	  gprintf(__func__, "  COMPLEX mismatch. isec2[5] = %d\n", isec2[5]);
+	  return (807);
+        }
+      else if ( lcomplex )
+	{
+	  /*
+	    Truncation of full spectrum, which is supposed triangular,
+	    has to be diagnosed. Define also sub-set truncation.
+	  */
+	  isubset = isec4[17];
+	  /* When encoding, use the total number of data. */
+	  itemp   = isec4[0];
+	  itrunc  = (int) (sqrt(itemp*4 + 1.) - 3) / 2;
+	}
     }
-  else
-    Error("file index %d undefined!", idx);
-
-  return (fileptr);
-}
-
-/* Create an index from a pointer */
-static
-int file_from_pointer(bfile_t *ptr)
-{
-  int      idx = -1;
-  filePtrToIdx *newptr;
 
-  if ( ptr )
+  if ( decscale )
     {
-      FILE_LOCK();
+      T scale = (T) pow(10.0, (double) decscale);
+      for ( long i = 0; i < datasize; ++i ) data[i] *= scale;
+    }
 
-      if ( _fileAvail )
+  if ( lspherc )
+    {
+      if ( lcomplex )
 	{
-	  newptr       = _fileAvail;
-	  _fileAvail   = _fileAvail->next;
-	  newptr->next = 0;
-	  idx	       = newptr->idx;
-	  newptr->ptr  = ptr;
-
-	  if ( FILE_Debug )
-	    Message("Pointer %p has idx %d from file list", ptr, idx);
+	  int jup  = isubset;
+	  int ioff = (jup+1)*(jup+2);
+	  bds_ext = 4 + 3 + 4*ioff;
+	  PackStart = ioff;
+	  Flag = 192;
 	}
       else
-	Warning("Too many open files (limit is %d)!", _file_max);
-
-      FILE_UNLOCK();
+	{
+	  bds_ext = 4;
+	  PackStart = 1;
+	  Flag = 128;
+	}
     }
-  else
-    Error("Internal problem (pointer %p undefined)", ptr);
 
-  return (idx);
-}
+  *datstart = bds_head + bds_ext;
 
-static
-void file_init_entry(bfile_t *fileptr)
-{
-  fileptr->self          = file_from_pointer(fileptr);
+  int nbpv = numBits = ISEC4_NumBits;
 
-  fileptr->flag          = 0;
-  fileptr->fd            = -1;
-  fileptr->fp            = NULL;
-  fileptr->mode          = 0;
-  fileptr->size          = 0;
-  fileptr->name          = NULL;
-  fileptr->access        = 0;
-  fileptr->position      = 0;
-  fileptr->byteTrans     = 0;
-  fileptr->type          = 0;
-  fileptr->bufferType    = 0;
-  fileptr->bufferSize    = 0;
-  fileptr->mappedSize    = 0;
-  fileptr->buffer        = NULL;
-  fileptr->bufferNumFill = 0;
-  fileptr->bufferStart   = 0;
-  fileptr->bufferEnd     = -1;
-  fileptr->bufferPos     = 0;
-  fileptr->bufferCnt     = 0;
-  fileptr->bufferPtr     = NULL;
-  fileptr->time_in_sec   = 0.0;
-}
+  if ( lspherc && lcomplex )
+    {
+      int pcStart, pcScale;
+      pcStart = isubset;
+      pcScale = isec4[16];
+      TEMPLATE(scale_complex,T)(data, pcStart, pcScale, itrunc, 0);
+      TEMPLATE(gather_complex,T)(data, (size_t)pcStart, (size_t)itrunc, (size_t)datasize);
+    }
 
-static
-bfile_t *file_new_entry(void)
-{
-  bfile_t *fileptr;
+  fmin = fmax = data[PackStart];
 
-  fileptr = (bfile_t *) Malloc(sizeof(bfile_t));
+  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
 
-  if ( fileptr ) file_init_entry(fileptr);
+  double zref = (double)fmin;
 
-  return (fileptr);
-}
 
-static
-void file_delete_entry(bfile_t *fileptr)
-{
-  int idx;
+  if ( CGRIBEX_Const && !lspherc )
+    {
+      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
+    }
 
-  idx = fileptr->self;
 
-  FILE_LOCK();
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
-  Free(fileptr);
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
-  _fileList[idx].next = _fileAvail;
-  _fileList[idx].ptr  = 0;
-  _fileAvail   	      = &_fileList[idx];
+  Flag += unused_bits;
 
-  FILE_UNLOCK();
 
-  if ( FILE_Debug )
-    Message("Removed idx %d from file list", idx);
-}
+  /*
+    Adjust number of bits per value if full integer length to
+    avoid hitting most significant bit (sign bit).
+  */
+  /* if( nbpv == ibits ) nbpv = nbpv - 1; */
+  /*
+    Calculate the binary scaling factor to spread the range of
+    values over the number of bits per value.
+    Limit scaling to 2**-126 to 2**127 (using IEEE 32-bit floats
+    as a guideline).           
+  */
+  double range = fabs(fmax - fmin);
+
+  if ( fabs(fmin) < FLT_MIN ) fmin = 0;
+  /*
+    Have to allow tolerance in comparisons on some platforms
+    (eg vpp700 and linux), such as 0.9999999999999999 = 1.0,
+    to avoid clipping ranges which are a power of 2.
+  */
+  if ( range <= jpepsln )
+    {
+      binscale = 0;
+    }
+  else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
+    {
+      binscale = 0;
+    }
+  else if ( fabs(range-1.0) <= jpepsln )
+    {
+      binscale = 1 - nbpv;
+    }
+  else if ( range > 1.0 )
+    {
+      double rangec = range + jpepsln,
+        p2 = 2.0;
+      int jloop = 1;
+      while ( jloop < 128 && p2 <= rangec )
+        {
+          p2 *= 2.0;
+          ++jloop;
+        }
+      if (jloop < 128)
+        binscale = jloop - nbpv;
+      else
+        {
+          gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+          gprintf(__func__, "> range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+          return (707);
+        }
+    }
+  else
+    {
+      double rangec = range - jpepsln, p05 = 0.5;
+      int jloop = 1;
+      while ( jloop < 127 && p05 >= rangec )
+	{
+          p05 *= 0.5;
+          jloop++;
+	}
+      if ( jloop < 127 )
+	{
+	  binscale = 1 - jloop - nbpv;
+	}
+      else
+	{
+	  gprintf(__func__, "Problem calculating binary scale value for encode code %d!", code);
+	  gprintf(__func__, "< range %g rangec %g fmin %g fmax %g", range, rangec, fmin, fmax);
+	  return (707);
+	}
+    }
 
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
-const char *fileLibraryVersion(void)
-{
-  return (file_libvers);
-}
+  if ( binscale != 0 )
+    {
+      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
 
+      factor = (T)intpow2(-binscale);
+    }
 
-static
-int pagesize(void)
-{
-#if defined(_SC_PAGESIZE)
-  return ((int) sysconf(_SC_PAGESIZE));
-#else
-#ifndef POSIXIO_DEFAULT_PAGESIZE
-#define POSIXIO_DEFAULT_PAGESIZE 4096
-#endif
-  return ((int) POSIXIO_DEFAULT_PAGESIZE);
-#endif
-}
+  ref2ibm(&zref, BitsPerInt);
 
-static
-double file_time()
-{
-  double tseconds = 0.0;
-  struct timeval mytime;
-  gettimeofday(&mytime, NULL);
-  tseconds = (double) mytime.tv_sec + (double) mytime.tv_usec*1.0e-6;
-  return (tseconds);
-}
+  Put3Byte(blockLength);      /*  0-2 Length of Block 4        */
+  Put1Byte(Flag);             /*  3   Flag & Unused bits       */
+  if ( binscale < 0 ) binscale = 32768 - binscale;
+  Put2Byte(binscale);         /*  4-5 Scale factor             */
+  Put1Real(zref);             /*  6-9 Reference value          */
+  Put1Byte(nbpv);             /*   10 Packing size             */
 
-void fileDebug(int debug)
-{
-  FILE_Debug = debug;
+  if ( lspherc )
+    {
+      if ( lcomplex )
+	{
+	  int jup = isubset;
+	  int ioff = (int)z + bds_ext;
+	  if ( ioff > 0xFFFF ) ioff = 0;
+	  Put2Byte(ioff);
+	  Put2Int(isec4[16]);
+	  Put1Byte(jup);
+	  Put1Byte(jup);
+	  Put1Byte(jup);
+	  for ( i = 0; i < ((jup+1)*(jup+2)); i++ ) Put1Real((double)(data[i]));
+	}
+      else
+	{
+	  Put1Real((double)(data[0]));
+	}
+    }
 
-  if ( FILE_Debug )
-    Message("Debug level %d", debug);
-}
+  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
+#if  defined  (_ARCH_PWR6)
+  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+#else
+  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+#endif
 
-void *filePtr(int fileID)
-{
-  bfile_t *fileptr;
+  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
 
-  fileptr = file_to_pointer(fileID);
+  *gribLen = (long)z;
 
-  return (fileptr);
+  return 0;
 }
 
-static
-void file_pointer_info(const char *caller, int fileID)
-{
-  if ( FILE_Debug )
-    {
-      fprintf(stdout, "%-18s : ", caller);
-      fprintf(stdout, "The fileID %d underlying pointer is not valid!", fileID);
-      fprintf(stdout, "\n");
-    }
-}
 
+void TEMPLATE(grib_encode,T)(int *isec0, int *isec1, int *isec2, T *fsec2, int *isec3,
+			     T *fsec3, int *isec4, T *fsec4, int klenp, int *kgrib,
+			     int kleng, int *kword, int efunc, int *kret)
+{
+  long gribLen = 0; // Counter of GRIB length for output
+  long fsec4size = 0;
+  long datstart, datsize;
+
+  UNUSED(isec3);
+  UNUSED(efunc);
 
-int fileSetBufferType(int fileID, int type)
-{
-  int ret = 0;
-  bfile_t *fileptr;
+  grsdef();
 
-  fileptr = file_to_pointer(fileID);
+  unsigned char *CGrib = (unsigned char *) kgrib;
 
-  if ( fileptr )
-    {
-      switch (type)
-	{
-	case FILE_BUFTYPE_STD:
-	case FILE_BUFTYPE_MMAP:
-	  fileptr->bufferType = (short)type;
-	  break;
-	default:
-	  Error("File type %d not implemented!", type);
-	}
-    }
+  bool gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  bool bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
-#if ! defined (HAVE_MMAP)
-  if ( type == FILE_BUFTYPE_MMAP ) ret = 1;
-#endif
+  // set max header len
+  size_t len = 16384;
 
-  return (ret);
-}
+  // add data len
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-int fileFlush(int fileID)
-{
-  bfile_t *fileptr;
-  int retval = 0;
+  len += numBytes*(size_t)klenp;
 
-  fileptr = file_to_pointer(fileID);
+  // add bitmap len
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
-  if ( fileptr ) retval = fflush(fileptr->fp);
+#if defined (VECTORCODE)
+  GRIBPACK *lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
+  if ( lGrib == NULL ) SysError("No Memory!");
+#else
+  GRIBPACK *lGrib = CGrib;
+#endif
 
-  return (retval);
-}
+  long isLen = 8;
+  encodeIS(lGrib, &gribLen);
+  GRIBPACK *lpds = &lGrib[isLen];
+  long pdsLen = getPdsLen(isec1);
 
+  encodePDS(lpds, pdsLen,  isec1);
+  gribLen += pdsLen;
+  /*
+  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
+    {
+      static bool lwarn_cplx = true;
 
-void fileClearerr(int fileID)
-{
-  bfile_t *fileptr;
+      if ( lwarn_cplx )
+	Message("Complex packing of spectral data unsupported, using simple packing!");
 
-  fileptr = file_to_pointer(fileID);
+      isec2[5] = 1;
+      isec4[3] = 0;
 
-  if ( fileptr )
+      lwarn_cplx = false;
+    }
+  */
+  if ( gdsIncluded ) TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
+  /*
+    ----------------------------------------------------------------
+    BMS Bit-Map Section Section (Section 3)
+    ----------------------------------------------------------------
+  */ 
+  if ( bmsIncluded )
     {
-      if ( fileptr->mode != 'r' )
-	clearerr(fileptr->fp);
+      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
+    }
+  else
+    {
+      fsec4size = ISEC4_NumValues;
     }
-}
 
+  long bdsstart = gribLen;
+  int status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
+                                     isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
+  if ( status )
+    {
+      *kret = status;
+      return;
+    }
 
-int filePtrEOF(void *vfileptr)
-{
-  bfile_t *fileptr = (bfile_t *) vfileptr;
-  int retval = 0;
+  encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
+    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
-  return (retval);
-}
+#if defined (VECTORCODE)
+  if ( (size_t) gribLen > len )
+    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
 
+  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
 
-int fileEOF(int fileID)
-{
-  bfile_t *fileptr;
-  int retval = 0;
+  Free(lGrib);
+#endif
 
-  fileptr = file_to_pointer(fileID);
+  ISEC0_GRIB_Len     = (int)gribLen;
+  ISEC0_GRIB_Version = 1;
 
-  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
-  return (retval);
+  *kret = status;
 }
 
-void fileRewind(int fileID)
-{
-  fileSetPos(fileID, (off_t) 0, SEEK_SET);
-  fileClearerr(fileID);
-}
+#endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-off_t fileGetPos(int fileID)
+void encode_dummy(void)
 {
-  off_t filepos = 0;
-  bfile_t *fileptr;
+  (void) encode_array_unrolled_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
+  (void) encode_array_unrolled_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
+}
+static const char grb_libvers[] = "1.9.0" " of ""Sep 29 2017"" ""10:16:02";
+const char *
+cgribexLibraryVersion(void)
+{
+  return (grb_libvers);
+}
 
-  fileptr = file_to_pointer(fileID);
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic pop
+#endif
 
-  if ( fileptr )
-    {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	filepos = fileptr->position;
-      else
-	filepos = ftell(fileptr->fp);
-    }
+#ifdef HAVE_CONFIG_H
+#endif
 
-  if ( FILE_Debug ) Message("Position %ld", filepos);
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef WORDS_BIGENDIAN
+#include <limits.h>
+#endif
 
-  return (filepos);
-}
+
+static const uint32_t crctab[] = {
+  0x00000000,
+  0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+  0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+  0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+  0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+  0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+  0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+  0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+  0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+  0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+  0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+  0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+  0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+  0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+  0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+  0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+  0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+  0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+  0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+  0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+  0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+  0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+  0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+  0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+  0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+  0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+  0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+  0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+  0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+  0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+  0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+  0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+  0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+  0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+  0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+  0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+  0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+  0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+  0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+  0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+  0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+  0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+  0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+  0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+  0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+  0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+  0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+  0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
 
 
-int fileSetPos(int fileID, off_t offset, int whence)
+uint32_t
+memcrc(const unsigned char *b, size_t n)
 {
-  int status = 0;
-  bfile_t *fileptr;
+/*  Input arguments:
+ *  const char*   b == byte sequence to checksum
+ *  size_t        n == length of sequence
+ */
 
-  fileptr = file_to_pointer(fileID);
 
-  if ( FILE_Debug ) Message("Offset %8ld  Whence %3d", (long) offset, whence);
+  uint32_t s = 0;
 
-  if ( fileptr == 0 )
-    {
-      file_pointer_info(__func__, fileID);
-      return (1);
-    }
+  memcrc_r(&s, b, n);
 
-  switch (whence)
-    {
-    case SEEK_SET:
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	{
-	  off_t position = offset;
-	  fileptr->position = position;
-	  if ( position < fileptr->bufferStart || position > fileptr->bufferEnd )
-	    {
-	      if ( fileptr->bufferType == FILE_BUFTYPE_STD )
-		fileptr->bufferPos = position;
-	      else
-		fileptr->bufferPos = position - position % pagesize();
+  /* Extend with the length of the string. */
+  while (n != 0) {
+    register uint32_t c = n & 0377;
+    n >>= 8;
+    s = (s << 8) ^ crctab[(s >> 24) ^ c];
+  }
 
-	      fileptr->bufferCnt = 0;
-	      fileptr->bufferPtr = NULL;
-	    }
-	  else
-	    {
-	      if ( fileptr->bufferPos != fileptr->bufferEnd + 1 )
-		{
-		  if ( FILE_Debug )
-		    Message("Reset buffer pos from %ld to %ld",
-			    fileptr->bufferPos, fileptr->bufferEnd + 1);
 
-		  fileptr->bufferPos = fileptr->bufferEnd + 1;
-		}
-	      fileptr->bufferCnt = (size_t)(fileptr->bufferEnd - position) + 1;
-	      fileptr->bufferPtr = fileptr->buffer + position - fileptr->bufferStart;
-	    }
-	}
-      else
-	{
-	  status = fseek(fileptr->fp, offset, whence);
-	}
-      break;
-    case SEEK_CUR:
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	{
-	  fileptr->position += offset;
-	  off_t position = fileptr->position;
-	  if ( position < fileptr->bufferStart || position > fileptr->bufferEnd )
-	    {
-	      if ( fileptr->bufferType == FILE_BUFTYPE_STD )
-		fileptr->bufferPos = position;
-	      else
-		fileptr->bufferPos = position - position % pagesize();
+  return ~s;
+}
 
-	      fileptr->bufferCnt = 0;
-	      fileptr->bufferPtr = NULL;
-	    }
-	  else
-	    {
-	      if ( fileptr->bufferPos != fileptr->bufferEnd + 1 )
-		{
-		  if ( FILE_Debug )
-		    Message("Reset buffer pos from %ld to %ld",
-			    fileptr->bufferPos, fileptr->bufferEnd + 1);
+void
+memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len)
+{
+/*  Input arguments:
+ *  const char*   b == byte sequence to checksum
+ *  size_t        n == length of sequence
+ */
 
-		  fileptr->bufferPos = fileptr->bufferEnd + 1;
-		}
-	      fileptr->bufferCnt -= (size_t)offset;
-	      fileptr->bufferPtr += offset;
-	    }
-	}
-      else
-	{
-	  status = fseek(fileptr->fp, offset, whence);
-	}
-      break;
-    default:
-      Error("Whence = %d not implemented", whence);
-    }
 
-  if ( fileptr->position < fileptr->size )
-    if ( (fileptr->flag & FILE_EOF) != 0 )
-      fileptr->flag -= FILE_EOF;
+  register uint32_t c, s = *state;
+  register size_t n = block_len;
+  register const unsigned char *b = block;
 
-  return (status);
+  for (; n > 0; --n) {
+    c = (uint32_t)(*b++);
+    s = (s << 8) ^ crctab[(s >> 24) ^ c];
+  }
+
+  *state = s;
 }
 
-static
-void file_table_print(void)
-{
-  int fileID;
-  int lprintHeader = 1;
-  bfile_t *fileptr;
+#ifdef WORDS_BIGENDIAN
+#define SWAP_CSUM(BITWIDTH,BYTEWIDTH,NACC)                              \
+  do {                                                                  \
+    register const uint##BITWIDTH##_t *b = (uint##BITWIDTH##_t *)elems; \
+    for (size_t i = 0; i < num_elems; ++i) {                            \
+      for(size_t aofs = NACC; aofs > 0; --aofs) {                       \
+        uint##BITWIDTH##_t accum = b[i + aofs - 1];                     \
+        for (size_t j = 0; j < BYTEWIDTH; ++j) {                        \
+          uint32_t c = (uint32_t)(accum & UCHAR_MAX);                   \
+          s = (s << 8) ^ crctab[(s >> 24) ^ c];                         \
+          accum >>= 8;                                                  \
+        }                                                               \
+      }                                                                 \
+    }                                                                   \
+  } while (0)
+#endif
 
-  for ( fileID = 0; fileID < _file_max; fileID++ )
-    {
-      fileptr = file_to_pointer(fileID);
 
-      if ( fileptr )
-	{
-	  if ( lprintHeader )
-	    {
-	      fprintf(stderr, "\nFile table:\n");
-	      fprintf(stderr, "+-----+---------+");
-	      fprintf(stderr, "----------------------------------------------------+\n");
-	      fprintf(stderr, "|  ID |  Mode   |");
-	      fprintf(stderr, "  Name                                              |\n");
-	      fprintf(stderr, "+-----+---------+");
-	      fprintf(stderr, "----------------------------------------------------+\n");
-	      lprintHeader = 0;
-	    }
+/**
+ *  Does endian-swapping prior to checksumming in case platform is big-endian
+ *
+ *  @param elems points to first first element with alignment elem_size
+ *  @param num_elems number of elements to process
+ *  @param elem_size size of each element in bytes
+ */
+void
+memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
+               size_t elem_size)
+{
+#ifdef WORDS_BIGENDIAN
+  register uint32_t s = *state;
 
-	  fprintf(stderr, "| %3d | ", fileID);
+  switch (elem_size)
+  {
+  case 1:
+    memcrc_r(state, elems, num_elems * elem_size);
+    return;
+  case 2:
+    SWAP_CSUM(16,2,1);
+    break;
+  case 4:
+    SWAP_CSUM(32,4,1);
+    break;
+  case 8:
+    SWAP_CSUM(64,8,1);
+    break;
+  case 16:
+    SWAP_CSUM(64,8,2);
+    break;
+  }
+  *state = s;
+#else
+  memcrc_r(state, elems, num_elems * elem_size);
+#endif
+}
 
-	  switch ( fileptr->mode )
-	    {
-	    case 'r':
-	      fprintf(stderr, "read   ");
-	      break;
-	    case 'w':
-	      fprintf(stderr, "write  ");
-	      break;
-	    case 'a':
-	      fprintf(stderr, "append ");
-	      break;
-	    default:
-	      fprintf(stderr, "unknown");
-	    }
 
-          fprintf(stderr, " | %-51s|\n", fileptr->name);
-	}
-    }
+uint32_t
+memcrc_finish(uint32_t *state, off_t total_size)
+{
+  register uint32_t c, s = *state;
+  register uint64_t n = (uint64_t)total_size;
 
-  if ( lprintHeader == 0 )
-    {
-      fprintf(stderr, "+-----+---------+");
-      fprintf(stderr, "----------------------------------------------------+\n");
-    }
+  /* Extend with the length of the string. */
+  while (n != 0) {
+    c = n & 0377;
+    n >>= 8;
+    s = (s << 8) ^ crctab[(s >> 24) ^ c];
+  }
+
+  return ~s;
 }
 
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if  defined(HAVE_CONFIG_H)
+#endif
 
-char *fileInqName(int fileID)
-{
-  bfile_t *fileptr;
-  char *name = NULL;
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
 
-  fileptr = file_to_pointer(fileID);
+#if !defined(HAVE_CONFIG_H) && !defined(HAVE_MALLOC_H) && defined(SX)
+#  define  HAVE_MALLOC_H
+#endif
 
-  if ( fileptr ) name = fileptr->name;
+#if  defined(HAVE_MALLOC_H)
+#  include <malloc.h>
+#endif
 
-  return (name);
-}
 
+enum             {MALLOC_FUNC=0, CALLOC_FUNC, REALLOC_FUNC, FREE_FUNC};
+static const char *memfunc[] = {"Malloc", "Calloc", "Realloc", "Free"};
 
-int fileInqMode(int fileID)
-{
-  bfile_t *fileptr;
-  int mode = 0;
+#undef   MEM_UNDEFID
+#define  MEM_UNDEFID  -1
 
-  fileptr = file_to_pointer(fileID);
+#define  MEM_MAXNAME  32   /* Min = 8, for  "unknown" ! */
 
-  if ( fileptr ) mode = fileptr->mode;
+static int dmemory_ExitOnError = 1;
 
-  return (mode);
+typedef struct
+{
+  void     *ptr;
+  size_t    size;
+  size_t    nobj;
+  int       item;
+  int       mtype;
+  int       line;
+  char      filename[MEM_MAXNAME];
+  char      functionname[MEM_MAXNAME];
 }
+MemTable_t;
+
+static MemTable_t *memTable;
+static size_t  memTableSize  = 0;
+static long    memAccess     = 0;
+
+static size_t  MemObjs       = 0;
+static size_t  MaxMemObjs    = 0;
+static size_t  MemUsed       = 0;
+static size_t  MaxMemUsed    = 0;
+
+static int     MEM_Debug     = 0;   /* If set to 1, debugging */
+static int     MEM_Info      = 0;   /* If set to 1, print mem table at exit */
 
 static
-long file_getenv(const char *envName)
+const char *get_filename(const char *file)
 {
-  char *envString;
-  long envValue = -1;
-  long fact = 1;
+  const char *fnptr = strrchr(file, '/');
+  if ( fnptr ) fnptr++;
+  else         fnptr = (char *) file;
+
+  return fnptr;
+}
 
-  envString = getenv(envName);
 
-  if ( envString )
-    {
-      int loop;
+void memDebug(int debug)
+{
+  MEM_Debug = debug;
+}
 
-      for ( loop = 0; loop < (int) strlen(envString); loop++ )
-	{
-	  if ( ! isdigit((int) envString[loop]) )
-	    {
-	      switch ( tolower((int) envString[loop]) )
-		{
-		case 'k':  fact =       1024;  break;
-		case 'm':  fact =    1048576;  break;
-		case 'g':  fact = 1073741824;  break;
-		default:
-		  fact = 0;
-		  Message("Invalid number string in %s: %s", envName, envString);
-		  Warning("%s must comprise only digits [0-9].",envName);
-		}
-	      break;
-	    }
-	}
+/* If we're not using GNU C, elide __attribute__ */
+#if ! defined __GNUC__ && ! defined __attribute__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
+
+static
+void memInternalProblem(const char *caller, const char *fmt, ...)
+  __attribute__((noreturn));
+static
+void memError(const char *caller, const char *file, int line, size_t size)
+  __attribute__((noreturn));
 
-      if ( fact ) envValue = fact*atol(envString);
+static
+void memInternalProblem(const char *functionname, const char *fmt, ...)
+{
+  va_list args;
 
-      if ( FILE_Debug ) Message("Set %s to %ld", envName, envValue);
-    }
+  va_start(args, fmt);
+
+  printf("\n");
+   fprintf(stderr, "Internal problem (%s) : ", functionname);
+  vfprintf(stderr, fmt, args);
+   fprintf(stderr, "\n");
 
-  return (envValue);
+  va_end(args);
+
+  exit(EXIT_FAILURE);
 }
 
 static
-void file_initialize(void)
+void memError(const char *functionname, const char *file, int line, size_t size)
 {
-  long value;
-  char *envString;
-
-#if  defined  (HAVE_LIBPTHREAD)
-  /* initialize global API mutex lock */
-  pthread_mutex_init(&_file_mutex, NULL);
-#endif
-
-  value = file_getenv("FILE_DEBUG");
-  if ( value >= 0 ) FILE_Debug = (int) value;
+  fputs("\n", stdout);
+  fprintf(stderr, "Error (%s) : Allocation of %zu bytes failed. [ line %d file %s ]\n",
+	  functionname, size, line, get_filename(file));
 
-  value = file_getenv("FILE_MAX");
-  if ( value >= 0 ) _file_max = (int) value;
+  if ( errno ) perror("System error message ");
 
-  if ( FILE_Debug )
-    Message("FILE_MAX = %d", _file_max);
+  exit(EXIT_FAILURE);
+}
 
-  FileInfo  = (int) file_getenv("FILE_INFO");
+static
+void memListPrintEntry(int mtype, int item, size_t size, void *ptr,
+		       const char *functionname, const char *file, int line)
+{
+  fprintf(stderr, "[%-7s ", memfunc[mtype]);
 
-  value  = file_getenv("FILE_BUFSIZE");
-  if ( value >= 0 ) FileBufferSizeEnv = value;
-  else
+  fprintf(stderr, "memory item %3d ", item);
+  fprintf(stderr, "(%6zu byte) ", size);
+  fprintf(stderr, "at %p", ptr);
+  if ( file != NULL )
     {
-      value  = file_getenv("GRIB_API_IO_BUFFER_SIZE");
-      if ( value >= 0 ) FileBufferSizeEnv = value;
+      fprintf(stderr, " line %4d", line);
+      fprintf(stderr, " file %s", get_filename(file));
     }
+  if ( functionname != NULL )
+    fprintf(stderr, " (%s)", functionname);
+  fprintf(stderr, "]\n");
+}
 
-  value = file_getenv("FILE_TYPE_READ");
-  if ( value > 0 )
-    {
-      switch (value)
-	{
-	case FILE_TYPE_OPEN:
-	case FILE_TYPE_FOPEN:
-	  FileTypeRead = (short)value;
-	  break;
-	default:
-	  Warning("File type %d not implemented!", value);
-	}
-    }
+static
+void memListPrintTable(void)
+{
+  if ( MemObjs ) fprintf(stderr, "\nMemory table:\n");
 
-  value = file_getenv("FILE_TYPE_WRITE");
-  if ( value > 0 )
+  for ( size_t memID = 0; memID < memTableSize; memID++ )
     {
-      switch (value)
-	{
-	case FILE_TYPE_OPEN:
-	case FILE_TYPE_FOPEN:
-	  FileTypeWrite = (short)value;
-	  break;
-	default:
-	  Warning("File type %d not implemented!", value);
-	}
+      if ( memTable[memID].item != MEM_UNDEFID )
+        memListPrintEntry(memTable[memID].mtype, memTable[memID].item,
+                          memTable[memID].size*memTable[memID].nobj,
+                          memTable[memID].ptr, memTable[memID].functionname,
+                          memTable[memID].filename, memTable[memID].line);
     }
 
-#if defined (O_NONBLOCK)
-  FileFlagWrite = O_NONBLOCK;
-#endif
-  envString = getenv("FILE_FLAG_WRITE");
-  if ( envString )
+  if ( MemObjs )
     {
-#if defined (O_NONBLOCK)
-      if ( strcmp(envString, "NONBLOCK") == 0 ) FileFlagWrite = O_NONBLOCK;
-#endif
+      fprintf(stderr, "  Memory access             : %6u\n", (unsigned) memAccess);
+      fprintf(stderr, "  Maximum objects           : %6zu\n", memTableSize);
+      fprintf(stderr, "  Objects used              : %6u\n", (unsigned) MaxMemObjs);
+      fprintf(stderr, "  Objects in use            : %6u\n", (unsigned) MemObjs);
+      fprintf(stderr, "  Memory allocated          : ");
+      if (MemUsed > 1024*1024*1024)
+	fprintf(stderr, " %5d GB\n",   (int) (MemUsed/(1024*1024*1024)));
+      else if (MemUsed > 1024*1024)
+	fprintf(stderr, " %5d MB\n",   (int) (MemUsed/(1024*1024)));
+      else if (MemUsed > 1024)
+	fprintf(stderr, " %5d KB\n",   (int) (MemUsed/(1024)));
+      else
+	fprintf(stderr, " %5d Byte\n", (int)  MemUsed);
     }
 
-  value = file_getenv("FILE_BUFTYPE");
-#if ! defined (HAVE_MMAP)
-  if ( value == FILE_BUFTYPE_MMAP )
-    {
-      Warning("MMAP not available!");
-      value = 0;
-    }
-#endif
-  if ( value > 0 )
+  if ( MaxMemUsed )
     {
-      switch (value)
-	{
-	case FILE_BUFTYPE_STD:
-	case FILE_BUFTYPE_MMAP:
-	  FileBufferTypeEnv = (short)value;
-	  break;
-	default:
-	  Warning("File buffer type %d not implemented!", value);
-	}
+      fprintf(stderr, "  Maximum memory allocated  : ");
+      if (MaxMemUsed > 1024*1024*1024)
+	fprintf(stderr, " %5d GB\n",   (int) (MaxMemUsed/(1024*1024*1024)));
+      else if (MaxMemUsed > 1024*1024)
+	fprintf(stderr, " %5d MB\n",   (int) (MaxMemUsed/(1024*1024)));
+      else if (MaxMemUsed > 1024)
+	fprintf(stderr, " %5d KB\n",   (int) (MaxMemUsed/(1024)));
+      else
+	fprintf(stderr, " %5d Byte\n", (int)  MaxMemUsed);
     }
+}
 
-  file_list_new();
-  atexit(file_list_delete);
-
-  FILE_LOCK();
+static
+void memGetDebugLevel(void)
+{
+  const char *envstr;
 
-  file_init_pointer();
+  envstr = getenv("MEMORY_INFO");
+  if ( envstr && isdigit((int) envstr[0]) ) MEM_Info = atoi(envstr);
 
-  FILE_UNLOCK();
+  envstr = getenv("MEMORY_DEBUG");
+  if ( envstr && isdigit((int) envstr[0]) ) MEM_Debug = atoi(envstr);
 
-  if ( FILE_Debug ) atexit(file_table_print);
+  if ( MEM_Debug && !MEM_Info ) MEM_Info = 1;
 
-  _file_init = TRUE;
+  if ( MEM_Info ) atexit(memListPrintTable);
 }
 
 static
-void file_set_buffer(bfile_t *fileptr)
+void memInit(void)
 {
-  size_t buffersize = 0;
+  static int initDebugLevel = 0;
 
-  if ( fileptr->mode == 'r' )
+  if ( ! initDebugLevel )
     {
-      if ( FileBufferTypeEnv )
-	fileptr->bufferType = FileBufferTypeEnv;
-      else if ( fileptr->bufferType == 0 )
-	fileptr->bufferType = FILE_BUFTYPE_STD;
-
-      if ( FileBufferSizeEnv >= 0 )
-	buffersize = (size_t) FileBufferSizeEnv;
-      else if ( fileptr->bufferSize > 0 )
-	buffersize = fileptr->bufferSize;
-      else
-	{
-	  buffersize = fileptr->blockSize * 4;
-	  if ( buffersize < FileBufferSizeMin ) buffersize = FileBufferSizeMin;
-	}
-
-      if ( (size_t) fileptr->size < buffersize )
-	buffersize = (size_t) fileptr->size;
-
-      if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
-	{
-	  size_t blocksize = (size_t) pagesize();
-	  size_t minblocksize = 4 * blocksize;
-	  buffersize = buffersize - buffersize % minblocksize;
+      memGetDebugLevel();
+      initDebugLevel = 1;
+    }
+}
 
-	  if ( buffersize < (size_t) fileptr->size && buffersize < minblocksize )
-	    buffersize = minblocksize;
-	}
+static
+int memListDeleteEntry(void *ptr, size_t *size)
+{
+  int item = MEM_UNDEFID;
+  size_t memID;
 
-      if ( buffersize == 0 ) buffersize = 1;
-    }
-  else
+  for ( memID = 0; memID < memTableSize; memID++ )
     {
-      fileptr->bufferType = FILE_BUFTYPE_STD;
-
-      if ( FileBufferSizeEnv >= 0 )
-	buffersize = (size_t) FileBufferSizeEnv;
-      else if ( fileptr->bufferSize > 0 )
-	buffersize = fileptr->bufferSize;
-      else
-	{
-	  buffersize = fileptr->blockSize * 4;
-	  if ( buffersize < FileBufferSizeMin ) buffersize = FileBufferSizeMin;
-	}
+      if ( memTable[memID].item == MEM_UNDEFID ) continue;
+      if ( memTable[memID].ptr == ptr ) break;
     }
 
-  if ( fileptr->bufferType == FILE_BUFTYPE_STD || fileptr->type == FILE_TYPE_FOPEN )
+  if ( memID != memTableSize )
     {
-      if ( buffersize > 0 )
-        {
-          fileptr->buffer = (char *) Malloc(buffersize);
-          if ( fileptr->buffer == NULL )
-            SysError("Allocation of file buffer failed!");
-        }
+      MemObjs--;
+      MemUsed -= memTable[memID].size * memTable[memID].nobj;
+      *size = memTable[memID].size * memTable[memID].nobj;
+      item = memTable[memID].item;
+      memTable[memID].item = MEM_UNDEFID;
     }
 
-  if ( fileptr->type == FILE_TYPE_FOPEN )
-    if ( setvbuf(fileptr->fp, fileptr->buffer, fileptr->buffer ? _IOFBF : _IONBF, buffersize) )
-      SysError("setvbuf failed!");
-
-  fileptr->bufferSize = buffersize;
+  return item;
 }
 
 static
-int file_fill_buffer(bfile_t *fileptr)
+void memTableInitEntry(size_t memID)
 {
-  ssize_t nread;
-  int fd;
-  long offset = 0;
-  off_t retseek;
-
-  if ( FILE_Debug )
-    Message("file ptr = %p  Cnt = %ld", fileptr, fileptr->bufferCnt);
-
-  if ( (fileptr->flag & FILE_EOF) != 0 ) return (EOF);
-
-  if ( fileptr->buffer == NULL ) file_set_buffer(fileptr);
+  if ( memID >= memTableSize )
+    memInternalProblem(__func__, "memID %d undefined!", memID);
 
-  if ( fileptr->bufferSize == 0 ) return (EOF);
+  memTable[memID].ptr    = NULL;
+  memTable[memID].item   = MEM_UNDEFID;
+  memTable[memID].size   = 0;
+  memTable[memID].nobj   = 0;
+  memTable[memID].mtype  = MEM_UNDEFID;
+  memTable[memID].line   = MEM_UNDEFID;
+}
 
-  fd = fileptr->fd;
+static
+int memListNewEntry(int mtype, void *ptr, size_t size, size_t nobj,
+		    const char *functionname, const char *file, int line)
+{
+  static int item = 0;
+  size_t memSize = 0;
+  size_t memID = 0;
 
-#if defined (HAVE_MMAP)
-  if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
+  /*
+    Look for a free slot in memTable.
+    (Create the table the first time through).
+  */
+  if ( memTableSize == 0 )
     {
-      if ( fileptr->bufferPos >= fileptr->size )
-	{
-	  nread = 0;
-	}
-      else
-	{
-          xassert(fileptr->bufferSize <= SSIZE_MAX);
-	  nread = (ssize_t)fileptr->bufferSize;
-	  if ( (nread + fileptr->bufferPos) > fileptr->size )
-	    nread = fileptr->size - fileptr->bufferPos;
-
-	  if ( fileptr->buffer )
-	    {
-              int ret;
-	      ret = munmap(fileptr->buffer, fileptr->mappedSize);
-	      if ( ret == -1 ) SysError("munmap error for read %s", fileptr->name);
-	      fileptr->buffer = NULL;
-	    }
-
-	  fileptr->mappedSize = (size_t)nread;
-
-	  fileptr->buffer = (char*) mmap(NULL, (size_t) nread, PROT_READ, MAP_PRIVATE, fd, fileptr->bufferPos);
-
-	  if ( fileptr->buffer == MAP_FAILED ) SysError("mmap error for read %s", fileptr->name);
+      memTableSize = 8;
+      memSize  = memTableSize * sizeof(MemTable_t);
+      memTable = (MemTable_t *) malloc(memSize);
+      if( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
 
-	  offset = fileptr->position - fileptr->bufferPos;
-	}
+      for ( size_t i = 0; i < memTableSize; i++ )
+	memTableInitEntry(i);
     }
   else
-#endif
     {
-      retseek = lseek(fileptr->fd, fileptr->bufferPos, SEEK_SET);
-      if ( retseek == (off_t)-1 )
-	SysError("lseek error at pos %ld file %s", (long) fileptr->bufferPos, fileptr->name);
-
-      nread = read(fd, fileptr->buffer, fileptr->bufferSize);
+      while ( memID < memTableSize )
+	{
+	  if ( memTable[memID].item == MEM_UNDEFID ) break;
+	  memID++;
+	}
     }
-
-  if ( nread <= 0 )
+  /*
+    If the table overflows, double its size.
+  */
+  if ( memID == memTableSize )
     {
-      if ( nread == 0 )
-	fileptr->flag |= FILE_EOF;
-      else
-	fileptr->flag |= FILE_ERROR;
+      memTableSize = 2*memTableSize;
+      memSize  = memTableSize*sizeof(MemTable_t);
+      memTable = (MemTable_t*) realloc(memTable, memSize);
+      if ( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
 
-      fileptr->bufferCnt = 0;
-      return (EOF);
+      for ( size_t i = memID; i < memTableSize; i++ )
+	memTableInitEntry(i);
     }
 
-  fileptr->bufferPtr = fileptr->buffer;
-  fileptr->bufferCnt = (size_t)nread;
+  memTable[memID].item  = item;
+  memTable[memID].ptr   = ptr;
+  memTable[memID].size  = size;
+  memTable[memID].nobj  = nobj;
+  memTable[memID].mtype = mtype;
+  memTable[memID].line  = line;
 
-  fileptr->bufferStart = fileptr->bufferPos;
-  fileptr->bufferPos  += nread;
-  fileptr->bufferEnd   = fileptr->bufferPos - 1;
+  if ( file )
+    {
+      const char *filename = get_filename(file);
+      size_t len = strlen(filename);
+      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-  if ( FILE_Debug )
+      (void) memcpy(memTable[memID].filename, filename, len);
+      memTable[memID].filename[len] = '\0';
+    }
+  else
     {
-      Message("fileID = %d  Val     = %d",  fileptr->self, (int) fileptr->buffer[0]);
-      Message("fileID = %d  Start   = %ld", fileptr->self, fileptr->bufferStart);
-      Message("fileID = %d  End     = %ld", fileptr->self, fileptr->bufferEnd);
-      Message("fileID = %d  nread   = %ld", fileptr->self, nread);
-      Message("fileID = %d  offset  = %ld", fileptr->self, offset);
-      Message("fileID = %d  Pos     = %ld", fileptr->self, fileptr->bufferPos);
-      Message("fileID = %d  postion = %ld", fileptr->self, fileptr->position);
+      (void) strcpy(memTable[memID].filename, "unknown");
     }
 
-  if ( offset > 0 )
+  if ( functionname )
     {
-      if ( offset > nread )
-	Error("Internal problem with buffer handling. nread = %d offset = %d", nread, offset);
+      size_t len = strlen(functionname);
+      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-      fileptr->bufferPtr += offset;
-      fileptr->bufferCnt -= (size_t)offset;
+      (void) memcpy(memTable[memID].functionname, functionname, len);
+      memTable[memID].functionname[len] = '\0';
+    }
+  else
+    {
+      (void) strcpy(memTable[memID].functionname, "unknown");
     }
 
-  fileptr->bufferNumFill++;
+  MaxMemObjs++;
+  MemObjs++;
+  MemUsed += size*nobj;
+  if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
 
-  return ((unsigned char) *fileptr->bufferPtr);
+  return item++;
 }
 
 static
-void file_copy_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
+int memListChangeEntry(void *ptrold, void *ptr, size_t size,
+		       const char *functionname, const char *file, int line)
 {
-  if ( FILE_Debug )
-    Message("size = %ld  Cnt = %ld", size, fileptr->bufferCnt);
-
-  if ( fileptr->bufferCnt < size )
-    Error("Buffer too small. bufferCnt = %d", fileptr->bufferCnt);
+  int item = MEM_UNDEFID;
+  size_t memID = 0;
 
-  if ( size == 1 )
+  while( memID < memTableSize )
     {
-      ((char *)ptr)[0] = fileptr->bufferPtr[0];
+      if ( memTable[memID].item != MEM_UNDEFID )
+	if ( memTable[memID].ptr == ptrold ) break;
+      memID++;
+    }
 
-      fileptr->bufferPtr++;
-      fileptr->bufferCnt--;
+  if ( memID == memTableSize )
+    {
+      if ( ptrold != NULL )
+	memInternalProblem(__func__, "Item at %p not found.", ptrold);
     }
   else
     {
-      memcpy(ptr, fileptr->bufferPtr, size);
+      item = memTable[memID].item;
 
-      fileptr->bufferPtr += size;
-      fileptr->bufferCnt -= size;
-    }
-}
+      size_t sizeold = memTable[memID].size*memTable[memID].nobj;
 
-static
-size_t file_read_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
-{
-  size_t nread, rsize;
-  size_t offset = 0;
+      memTable[memID].ptr   = ptr;
+      memTable[memID].size  = size;
+      memTable[memID].nobj  = 1;
+      memTable[memID].mtype = REALLOC_FUNC;
+      memTable[memID].line  = line;
 
-  if ( FILE_Debug )
-    Message("size = %ld  Cnt = %ld", size, (long) fileptr->bufferCnt);
+      if ( file )
+	{
+          const char *filename = get_filename(file);
+	  size_t len = strlen(filename);
+	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-  if ( ((long)fileptr->bufferCnt) < 0L )
-    Error("Internal problem. bufferCnt = %ld", (long) fileptr->bufferCnt);
+	  (void) memcpy(memTable[memID].filename, filename, len);
+	  memTable[memID].filename[len] = '\0';
+	}
+      else
+	{
+	  (void) strcpy(memTable[memID].filename, "unknown");
+	}
 
-  rsize = size;
+      if ( functionname )
+	{
+	  size_t len = strlen(functionname);
+	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-  while ( fileptr->bufferCnt < rsize )
-    {
-      nread = fileptr->bufferCnt;
-      /*
-      fprintf(stderr, "rsize = %d nread = %d\n", (int) rsize, (int) nread);
-      */
-      if ( nread > (size_t) 0 )
-	file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
-      offset += nread;
-      if ( nread < rsize )
-	rsize -= nread;
+	  (void) memcpy(memTable[memID].functionname, functionname, len);
+	  memTable[memID].functionname[len] = '\0';
+	}
       else
-	rsize = 0;
+	{
+	  (void) strcpy(memTable[memID].functionname, "unknown");
+	}
 
-      if ( file_fill_buffer(fileptr) == EOF ) break;
+      MemUsed -= sizeold;
+      MemUsed += size;
+      if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
     }
 
-  nread = size - offset;
-
-  if ( fileptr->bufferCnt < nread ) nread = fileptr->bufferCnt;
-
-  if ( nread > (unsigned) 0 )
-    file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
-
-  return (nread+offset);
-}
-
-
-void fileSetBufferSize(int fileID, long buffersize)
-{
-  bfile_t *fileptr = file_to_pointer(fileID);
-  xassert(buffersize >= 0);
-  if ( fileptr ) fileptr->bufferSize = (size_t)buffersize;
-}
-
-/*
- *   Open a file. Returns file ID, or -1 on error
- */
-int fileOpen(const char *filename, const char *mode)
-{
-  int (*myFileOpen)(const char *filename, const char *mode)
-    = (int (*)(const char *, const char *))
-    namespaceSwitchGet(NSSWITCH_FILE_OPEN).func;
-  return myFileOpen(filename, mode);
+  return item;
 }
 
-int fileOpen_serial(const char *filename, const char *mode)
-{
-  FILE *fp = NULL;    /* file pointer    (used for write) */
-  int fd = -1;        /* file descriptor (used for read)  */
-  int fileID = FILE_UNDEFID;
-  int fmode = 0;
-  struct stat filestat;
-  bfile_t *fileptr = NULL;
-
-  FILE_INIT();
-
-  fmode = tolower((int) mode[0]);
 
-  switch ( fmode )
-    {
-    case 'r':
-      if ( FileTypeRead == FILE_TYPE_FOPEN )
-	fp = fopen(filename, "rb");
-      else
-	fd =  open(filename, O_RDONLY | O_BINARY);
-      break;
-    case 'x':  fp = fopen(filename, "rb");      break;
-    case 'w':
-      if ( FileTypeWrite == FILE_TYPE_FOPEN )
-        fp = fopen(filename, "wb");
-      else
-	fd =  open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY | FileFlagWrite, 0666);
-      break;
-    case 'a':  fp = fopen(filename, "ab");      break;
-    default:   Error("Mode %c unexpected!", fmode);
-    }
+void *memCalloc(size_t nobjs, size_t size, const char *file, const char *functionname, int line)
+{
+  void *ptr = NULL;
 
-  if ( FILE_Debug )
-    if ( fp == NULL && fd == -1 )
-      Message("Open failed on %s mode %c errno %d", filename, fmode, errno);
+  memInit();
 
-  if ( fp )
+  if ( nobjs*size > 0 )
     {
-      if ( stat(filename, &filestat) != 0 ) return (fileID);
+      ptr = calloc(nobjs, size);
 
-      fileptr = file_new_entry();
-      if ( fileptr )
+      if ( MEM_Info )
 	{
-	  fileID = fileptr->self;
-	  fileptr->fp = fp;
-	}
-    }
-  else if ( fd >= 0 )
-    {
-      if ( fstat(fd, &filestat) != 0 ) return (fileID);
+	  memAccess++;
 
-      fileptr = file_new_entry();
-      if ( fileptr )
-	{
-	  fileID = fileptr->self;
-	  fileptr->fd = fd;
+          int item = MEM_UNDEFID;
+	  if ( ptr ) item = memListNewEntry(CALLOC_FUNC, ptr, size, nobjs, functionname, file, line);
+
+	  if ( MEM_Debug ) memListPrintEntry(CALLOC_FUNC, item, size*nobjs, ptr, functionname, file, line);
 	}
+
+      if ( ptr == NULL && dmemory_ExitOnError )
+	memError(functionname, file, line, size*nobjs);
     }
+  else
+    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
 
-  if ( fileID >= 0 )
-    {
-      fileptr->mode = fmode;
-      fileptr->name = strdupx(filename);
+  return ptr;
+}
 
-#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
-      fileptr->blockSize = (size_t) filestat.st_blksize;
-#else
-      fileptr->blockSize = (size_t) 4096;
-#endif
 
-      if ( fmode == 'r' )
-        fileptr->type = FileTypeRead;
-      else if ( fmode == 'w' )
-        fileptr->type = FileTypeWrite;
-      else
-	fileptr->type = FILE_TYPE_FOPEN;
+void *memMalloc(size_t size, const char *file, const char *functionname, int line)
+{
+  void *ptr = NULL;
 
-      if ( fmode == 'r' ) fileptr->size = filestat.st_size;
+  memInit();
 
-      if ( fileptr->type == FILE_TYPE_FOPEN ) file_set_buffer(fileptr);
+  if ( size > 0 )
+    {
+      ptr = malloc(size);
 
-      if ( FILE_Debug )
-	Message("File %s opened with ID %d", filename, fileID);
+      if ( MEM_Info )
+	{
+	  memAccess++;
+
+          int item = MEM_UNDEFID;
+	  if ( ptr ) item = memListNewEntry(MALLOC_FUNC, ptr, size, 1, functionname, file, line);
+
+	  if ( MEM_Debug ) memListPrintEntry(MALLOC_FUNC, item, size, ptr, functionname, file, line);
+	}
+
+      if ( ptr == NULL && dmemory_ExitOnError )
+	memError(functionname, file, line, size);
     }
+  else
+    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, file);
 
-  return (fileID);
+  return ptr;
 }
 
-/*
- *   Close a file.
- */
-int fileClose(int fileID)
-{
-  int (*myFileClose)(int fileID)
-    = (int (*)(int))namespaceSwitchGet(NSSWITCH_FILE_CLOSE).func;
-  return myFileClose(fileID);
-}
 
-int fileClose_serial(int fileID)
+void *memRealloc(void *ptrold, size_t size, const char *file, const char *functionname, int line)
 {
-  char *name;
-  int ret;
-  const char *fbtname[] = {"unknown", "standard", "mmap"};
-  const char *ftname[] = {"unknown", "open", "fopen"};
-  bfile_t *fileptr = file_to_pointer(fileID);
-  double rout = 0;
+  void *ptr = NULL;
 
-  if ( fileptr == NULL )
+  memInit();
+
+  if ( size > 0 )
     {
-      file_pointer_info(__func__, fileID);
-      return (1);
+      ptr = realloc(ptrold, size);
+
+      if ( MEM_Info )
+	{
+	  memAccess++;
+
+          int item = MEM_UNDEFID;
+	  if ( ptr )
+	    {
+	      item = memListChangeEntry(ptrold, ptr, size, functionname, file, line);
+
+	      if ( item == MEM_UNDEFID ) item = memListNewEntry(REALLOC_FUNC, ptr, size, 1, functionname, file, line);
+	    }
+
+	  if ( MEM_Debug ) memListPrintEntry(REALLOC_FUNC, item, size, ptr, functionname, file, line);
+	}
+
+      if ( ptr == NULL && dmemory_ExitOnError )
+	memError(functionname, file, line, size);
     }
+  else
+    fprintf(stderr, "Warning (%s) : Allocation of 0 bytes! [ line %d file %s ]\n", functionname, line, get_filename(file));
 
-  name = fileptr->name;
+  return ptr;
+}
 
-  if ( FILE_Debug )
-    Message("fileID = %d  filename = %s", fileID, name);
 
-  if ( FileInfo > 0 )
-    {
-      fprintf(stderr, "____________________________________________\n");
-      fprintf(stderr, " file ID          : %d\n",  fileID);
-      fprintf(stderr, " file name        : %s\n",  fileptr->name);
-      fprintf(stderr, " file type        : %d (%s)\n", fileptr->type, ftname[fileptr->type]);
+void memFree(void *ptr, const char *file, const char *functionname, int line)
+{
+  memInit();
 
-      if ( fileptr->type == FILE_TYPE_FOPEN )
-	fprintf(stderr, " file pointer     : %p\n",  (void *) fileptr->fp);
-      else
-        {
-          fprintf(stderr, " file descriptor  : %d\n",  fileptr->fd);
-          fprintf(stderr, " file flag        : %d\n", FileFlagWrite);
-        }
-      fprintf(stderr, " file mode        : %c\n",  fileptr->mode);
+  if ( MEM_Info )
+    {
+      int item;
+      size_t size;
 
-      if ( sizeof(off_t) > sizeof(long) )
+      if ( (item = memListDeleteEntry(ptr, &size)) >= 0 )
 	{
-#if defined (_WIN32)
-	  fprintf(stderr, " file size        : %I64d\n", (long long) fileptr->size);
-	  if ( fileptr->type == FILE_TYPE_OPEN )
-	    fprintf(stderr, " file position    : %I64d\n", (long long) fileptr->position);
-	  fprintf(stderr, " bytes transfered : %I64d\n", (long long) fileptr->byteTrans);
-#else
-	  fprintf(stderr, " file size        : %lld\n", (long long) fileptr->size);
-	  if ( fileptr->type == FILE_TYPE_OPEN )
-	    fprintf(stderr, " file position    : %lld\n", (long long) fileptr->position);
-	  fprintf(stderr, " bytes transfered : %lld\n", (long long) fileptr->byteTrans);
-#endif
+	  if ( MEM_Debug ) memListPrintEntry(FREE_FUNC, item, size, ptr, functionname, file, line);
 	}
       else
 	{
-	  fprintf(stderr, " file size        : %ld\n", (long) fileptr->size);
-	  if ( fileptr->type == FILE_TYPE_OPEN )
-	    fprintf(stderr, " file position    : %ld\n", (long) fileptr->position);
-	  fprintf(stderr, " bytes transfered : %ld\n", (long) fileptr->byteTrans);
+	  if ( ptr && MEM_Debug  )
+	    fprintf(stderr, "%s info: memory entry at %p not found. [line %4d file %s (%s)]\n",
+		    __func__, ptr, line, get_filename(file), functionname);
 	}
+    }
 
-      if ( fileptr->time_in_sec > 0 )
-        {
-          rout = (double)fileptr->byteTrans / (1024.*1024.*fileptr->time_in_sec);
-        }
-
-      fprintf(stderr, " wall time [s]    : %.2f\n", fileptr->time_in_sec);
-      fprintf(stderr, " data rate [MB/s] : %.1f\n", rout);
+  free(ptr);
+}
 
-      fprintf(stderr, " file access      : %ld\n", fileptr->access);
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	{
-	  fprintf(stderr, " buffer type      : %d (%s)\n", fileptr->bufferType, fbtname[fileptr->bufferType]);
-	  fprintf(stderr, " num buffer fill  : %ld\n", fileptr->bufferNumFill);
-	}
-      fprintf(stderr, " buffer size      : %lu\n", (unsigned long) fileptr->bufferSize);
-      fprintf(stderr, " block size       : %lu\n", (unsigned long) fileptr->blockSize);
-      fprintf(stderr, " page size        : %d\n",  pagesize());
-      fprintf(stderr, "--------------------------------------------\n");
-    }
 
-  if ( fileptr->type == FILE_TYPE_FOPEN )
+size_t memTotal(void)
+{
+  size_t memtotal = 0;
+#if  defined  (HAVE_MALLINFO)
+  struct mallinfo meminfo = mallinfo();
+  if ( MEM_Debug )
     {
-      ret = fclose(fileptr->fp);
-      if ( ret == EOF )
-	SysError("EOF returned for close of %s!", name);
+      fprintf(stderr, "arena      %8zu (non-mmapped space allocated from system)\n", (size_t)meminfo.arena);
+      fprintf(stderr, "ordblks    %8zu (number of free chunks)\n", (size_t)meminfo.ordblks);
+      fprintf(stderr, "smblks     %8zu (number of fastbin blocks)\n", (size_t) meminfo.smblks);
+      fprintf(stderr, "hblks      %8zu (number of mmapped regions)\n", (size_t) meminfo.hblks);
+      fprintf(stderr, "hblkhd     %8zu (space in mmapped regions)\n", (size_t) meminfo.hblkhd);
+      fprintf(stderr, "usmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.usmblks);
+      fprintf(stderr, "fsmblks    %8zu (maximum total allocated space)\n", (size_t) meminfo.fsmblks);
+      fprintf(stderr, "uordblks   %8zu (total allocated space)\n", (size_t) meminfo.uordblks);
+      fprintf(stderr, "fordblks   %8zu (total free space)\n", (size_t) meminfo.fordblks);
+      fprintf(stderr, "Memory in use:   %8zu bytes\n", (size_t) meminfo.usmblks + (size_t)meminfo.uordblks);
+      fprintf(stderr, "Total heap size: %8zu bytes\n", (size_t) meminfo.arena);
+
+      /* malloc_stats(); */
     }
-  else
-    {
-#if defined (HAVE_MMAP)
-      if ( fileptr->buffer && fileptr->mappedSize )
-	{
-	  ret = munmap(fileptr->buffer, fileptr->mappedSize);
-	  if ( ret == -1 ) SysError("munmap error for close %s", fileptr->name);
-	  fileptr->buffer = NULL;
-	}
+  memtotal = (size_t)meminfo.arena;
 #endif
-      ret = close(fileptr->fd);
-      if ( ret == -1 )
-	SysError("EOF returned for close of %s!", name);
-    }
 
-  if ( fileptr->name )    Free((void*) fileptr->name);
-  if ( fileptr->buffer )  Free((void*) fileptr->buffer);
+  return memtotal;
+}
 
-  file_delete_entry(fileptr);
 
-  return (0);
+void memExitOnError(void)
+{
+  dmemory_ExitOnError = 1;
 }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
 
-int filePtrGetc(void *vfileptr)
+#if !defined (NAMESPACE_H)
+#endif
+
+int _ExitOnError   = 1;	/* If set to 1, exit on error       */
+int _Verbose = 1;	/* If set to 1, errors are reported */
+int _Debug   = 0;       /* If set to 1, debugging           */
+
+/* If we're not using GNU C, elide __attribute__ */
+#if ! defined __GNUC__ && ! defined __attribute__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
+
+void SysError_(const char *caller, const char *fmt, ...)
+  __attribute__((noreturn));
+
+void SysError_(const char *caller, const char *fmt, ...)
 {
-  int ivalue = EOF;
-  int fillret = 0;
-  bfile_t *fileptr = (bfile_t *) vfileptr;
+  va_list args;
+  int saved_errno = errno;
 
-  if ( fileptr )
-    {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	{
-	  if ( fileptr->bufferCnt == 0 ) fillret = file_fill_buffer(fileptr);
+  va_start(args, fmt);
 
-	  if ( fillret >= 0 )
-	    {
-	      ivalue = (unsigned char) *fileptr->bufferPtr++;
-	      fileptr->bufferCnt--;
-	      fileptr->position++;
+  printf("\n");
+   fprintf(stderr, "Error (%s) : ", caller);
+  vfprintf(stderr, fmt, args);
+   fprintf(stderr, "\n");
 
-	      fileptr->byteTrans++;
-	      fileptr->access++;
-	    }
-	}
-      else
-	{
-	  ivalue = fgetc(fileptr->fp);
-	  if ( ivalue >= 0 )
-	    {
-	      fileptr->byteTrans++;
-	      fileptr->access++;
-	    }
-	  else
-	    fileptr->flag |= FILE_EOF;
-	}
+  va_end(args);
+
+  if ( saved_errno )
+    {
+      errno = saved_errno;
+      perror("System error message");
     }
 
-  return (ivalue);
+  exit(EXIT_FAILURE);
 }
 
 
-int fileGetc(int fileID)
+void Error_(const char *caller, const char *fmt, ...)
 {
-  int ivalue;
-  bfile_t *fileptr;
+  va_list args;
+
+  va_start(args, fmt);
+
+  printf("\n");
+   fprintf(stderr, "Error (%s) : ", caller);
+  vfprintf(stderr, fmt, args);
+   fprintf(stderr, "\n");
+
+  va_end(args);
 
-  fileptr = file_to_pointer(fileID);
+  if ( _ExitOnError ) exit(EXIT_FAILURE);
+}
+
+typedef void (*cdiAbortCFunc)(const char * caller, const char * filename,
+                              const char *functionname, int line,
+                              const char * errorString, va_list ap)
+#ifdef __GNUC__
+  __attribute__((noreturn))
+#endif
+;
 
-  ivalue = filePtrGetc((void *)fileptr);
+void cdiAbortC(const char * caller, const char * filename,
+               const char *functionname, int line,
+               const char * errorString, ... )
+{
+  va_list ap;
+  va_start(ap, errorString);
+  cdiAbortCFunc cdiAbortC_p
+    = (cdiAbortCFunc)namespaceSwitchGet(NSSWITCH_ABORT).func;
+  cdiAbortC_p(caller, filename, functionname, line, errorString, ap);
+  va_end(ap);
+}
 
-  return (ivalue);
+void
+cdiAbortC_serial(const char *caller, const char *filename,
+                 const char *functionname, int line,
+                 const char *errorString, va_list ap)
+{
+  fprintf(stderr, "ERROR, %s, %s, line %d%s%s\nerrorString: \"",
+          functionname, filename, line, caller?", called from ":"",
+          caller?caller:"");
+  vfprintf(stderr, errorString, ap);
+  fputs("\"\n", stderr);
+  exit(EXIT_FAILURE);
 }
 
+typedef void (*cdiWarningFunc)(const char * caller, const char * fmt,
+                               va_list ap);
 
-size_t filePtrRead(void *vfileptr, void *restrict ptr, size_t size)
+void Warning_(const char *caller, const char *fmt, ...)
 {
-  size_t nread = 0;
-  bfile_t *fileptr = (bfile_t *) vfileptr;
+  va_list args;
 
-  if ( fileptr )
-    {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	nread = file_read_from_buffer(fileptr, ptr, size);
-      else
-	{
-	  nread = fread(ptr, 1, size, fileptr->fp);
-	  if ( nread != size )
-	    {
-	      if ( nread == 0 )
-		fileptr->flag |= FILE_EOF;
-	      else
-		fileptr->flag |= FILE_ERROR;
-	    }
-	}
+  va_start(args, fmt);
 
-      fileptr->position  += (off_t)nread;
-      fileptr->byteTrans += (off_t)nread;
-      fileptr->access++;
+  if ( _Verbose )
+    {
+      cdiWarningFunc cdiWarning_p
+        = (cdiWarningFunc)namespaceSwitchGet(NSSWITCH_WARNING).func;
+      cdiWarning_p(caller, fmt, args);
     }
 
-  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
+  va_end(args);
+}
 
-  return (nread);
+void cdiWarning(const char *caller, const char *fmt, va_list ap)
+{
+  fprintf(stderr, "Warning (%s) : ", caller);
+  vfprintf(stderr, fmt, ap);
+  fputc('\n', stderr);
 }
 
 
-size_t fileRead(int fileID, void *restrict ptr, size_t size)
+void Message_(const char *caller, const char *fmt, ...)
 {
-  size_t nread = 0;
-  bfile_t *fileptr;
+  va_list args;
 
-  fileptr = file_to_pointer(fileID);
+  va_start(args, fmt);
 
-  if ( fileptr )
-    {
-      double t_begin = 0.0;
+   fprintf(stdout, "%-18s : ", caller);
+  vfprintf(stdout, fmt, args);
+   fprintf(stdout, "\n");
 
-      if ( FileInfo ) t_begin = file_time();
+  va_end(args);
+}
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef EXSE_H
+#define EXSE_H
 
-      if ( fileptr->type == FILE_TYPE_OPEN )
-	nread = file_read_from_buffer(fileptr, ptr, size);
-      else
-	{
-	  nread = fread(ptr, 1, size, fileptr->fp);
-	  if ( nread != size )
-	    {
-	      if ( nread == 0 )
-		fileptr->flag |= FILE_EOF;
-	      else
-		fileptr->flag |= FILE_ERROR;
-	    }
-	}
+enum {
+  EXSE_SINGLE_PRECISION = 4,
+  EXSE_DOUBLE_PRECISION = 8,
+};
 
-      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
+#endif
+#if defined (HAVE_CONFIG_H)
+#endif
 
-      fileptr->position  += (off_t)nread;
-      fileptr->byteTrans += (off_t)nread;
-      fileptr->access++;
-    }
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
-  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
 
-  return (nread);
+
+enum {
+  EXT_HEADER_LEN = 4,
+};
+
+
+static int initExtLib       = 0;
+static int extDefaultPrec   = 0;
+static int extDefaultNumber = EXT_REAL;
+
+
+/*
+ * A version string.
+ */
+#undef  LIBVERSION
+#define LIBVERSION      1.4.0
+#define XSTRING(x)	#x
+#define STRING(x)	XSTRING(x)
+static const char ext_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__ ;
+
+const char *extLibraryVersion(void)
+{
+  return ext_libvers;
 }
 
 
-size_t fileWrite(int fileID, const void *restrict ptr, size_t size)
+static int EXT_Debug = 0;    /* If set to 1, debugging */
+
+
+void extDebug(int debug)
 {
-  size_t nwrite = 0;
-  bfile_t *fileptr;
+  EXT_Debug = debug;
 
-  fileptr = file_to_pointer(fileID);
+  if ( EXT_Debug )
+    Message("debug level %d", debug);
+}
 
-  if ( fileptr )
-    {
-      double t_begin = 0.0;
 
-      /* if ( fileptr->buffer == NULL ) file_set_buffer(fileptr); */
+static
+void extLibInit()
+{
+  const char *envName = "EXT_PRECISION";
 
-      if ( FileInfo ) t_begin = file_time();
+  char *envString = getenv(envName);
+  if ( envString )
+    {
+      int pos = 0;
 
-      if ( fileptr->type == FILE_TYPE_FOPEN )
-        nwrite = fwrite(ptr, 1, size, fileptr->fp);
-      else
-        {
-          ssize_t temp = write(fileptr->fd, ptr, size);
-          if (temp == -1)
-            {
-              perror("error writing to file");
-              nwrite = 0;
+      if ( strlen(envString) == 2  )
+	{
+	  switch ( tolower((int) envString[pos]) )
+	    {
+	    case 'r':
+	      {
+		extDefaultNumber = EXT_REAL;
+		switch ( (int) envString[pos+1] )
+		  {
+		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
+		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
+		  default:
+		    Message("Invalid digit in %s: %s", envName, envString);
+		  }
+		break;
+	      }
+	    case 'c':
+	      {
+		extDefaultNumber = EXT_COMP;
+		switch ( (int) envString[pos+1] )
+		  {
+		  case '4': extDefaultPrec = EXSE_SINGLE_PRECISION; break;
+		  case '8': extDefaultPrec = EXSE_DOUBLE_PRECISION; break;
+		  default:
+		    Message("Invalid digit in %s: %s", envName, envString);
+		  }
+		break;
+	      }
+	    default:
+              {
+                Message("Invalid character in %s: %s", envName, envString);
+                break;
+              }
             }
-          else
-            nwrite = (size_t)temp;
-        }
-
-      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
-
-      fileptr->position  += (off_t)nwrite;
-      fileptr->byteTrans += (off_t)nwrite;
-      fileptr->access++;
+	}
     }
 
-  return (nwrite);
+  initExtLib = 1;
 }
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _GAUSSGRID_H
-#define _GAUSSGRID_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+static
+void extInit(extrec_t *extp)
+{
+  extp->checked    = 0;
+  extp->byteswap   = 0;
+  extp->prec       = 0;
+  extp->number     = extDefaultNumber;
+  extp->datasize   = 0;
+  extp->buffersize = 0;
+  extp->buffer     = NULL;
+}
 
-void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
 
-#if defined (__cplusplus)
-}
-#endif
+void *extNew(void)
+{
+  if ( ! initExtLib ) extLibInit();
 
-#endif  /* _GAUSSGRID_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifdef HAVE_CONFIG_H
-#endif
+  extrec_t *extp = (extrec_t *) Malloc(sizeof(extrec_t));
 
-#include <math.h>
-#include <float.h>
-#include <stdio.h>
-#include <stdlib.h>
+  extInit(extp);
 
+  return (void*)extp;
+}
 
 
-#ifndef  M_PI
-#define  M_PI        3.14159265358979323846  /* pi */
-#endif
+void extDelete(void *ext)
+{
+  extrec_t *extp = (extrec_t *) ext;
 
-#ifndef  M_SQRT2
-#define  M_SQRT2     1.41421356237309504880
-#endif
+  if ( extp )
+    {
+      if ( extp->buffer ) Free(extp->buffer);
+      Free(extp);
+    }
+}
 
 
-static
-void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag, 
-            double *pw, double *pdxn, double *pxmod)
+int extCheckFiletype(int fileID, int *swap)
 {
-  double zdlk;
-  double zdlldn;
-  double zdlx;
-  double zdlmod;
-  double zdlxn;
+  size_t fact = 0;
+  size_t data =  0;
+  size_t dimxy = 0;
+  int found = 0;
+  unsigned char buffer[40], *pbuf;
 
-  size_t ik;
+  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
 
-  /* 1.0 Newton iteration step */
+  size_t blocklen  = (size_t) get_UINT32(buffer);
+  size_t sblocklen = (size_t) get_SUINT32(buffer);
+
+  if ( EXT_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
-  zdlx = pdx;
-  zdlk = 0.0;
-  if (kodd == 0) 
+  if ( blocklen == 16 )
     {
-      zdlk = 0.5*pfn[0];
+     *swap = 0;
+      fact = blocklen/4;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
+      pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
     }
-  zdlxn  = 0.0;
-  zdlldn = 0.0;
-
-  ik = 1;
-
-  if (kflag == 0) 
+  else if ( blocklen == 32 )
     {
-      for(size_t jn = 2-kodd; jn <= kn; jn += 2) 
-	{
-	  /* normalised ordinary Legendre polynomial == \overbar{p_n}^0 */
-	  zdlk   = zdlk + pfn[ik]*cos((double)(jn)*zdlx);
-	  /* normalised derivative == d/d\theta(\overbar{p_n}^0) */
-	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
-	  ik++;
-	}
-      /* Newton method */
-      zdlmod = -(zdlk/zdlldn);
-      zdlxn = zdlx + zdlmod;
-      *pdxn = zdlxn;
-      *pxmod = zdlmod;
+     *swap = 0;
+      fact = blocklen/4;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
+      pbuf = buffer+3*fact;      dimxy = (size_t) get_UINT64(pbuf);
+      pbuf = buffer+blocklen+4;  data  = (size_t) get_UINT32(pbuf);
+    }
+  else if ( sblocklen == 16 )
+    {
+     *swap = 1;
+      fact = sblocklen/4;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
+      pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
+    }
+  else if ( sblocklen == 32 )
+    {
+     *swap = 1;
+      fact = sblocklen/4;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
+      pbuf = buffer+3*fact;       dimxy = (size_t) get_SUINT64(pbuf);
+      pbuf = buffer+sblocklen+4;  data  = (size_t) get_SUINT32(pbuf);
     }
 
-  /* 2.0 Compute weights */
+  fileRewind(fileID);
 
-  if (kflag == 1) 
+  if      ( data && dimxy*fact   == data ) found = 1;
+  else if ( data && dimxy*fact*2 == data ) found = 1;
+
+  if ( EXT_Debug )
     {
-      for(size_t jn = 2-kodd; jn <= kn; jn += 2) 
-	{
-	  /* normalised derivative */
-	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
-	  ik++;
-	}
-      *pw = (double)(2*kn+1)/(zdlldn*zdlldn);
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimxy = %lu data = %lu", dimxy, data);
     }
 
-  return;
+  return found;
 }
 
-static
-void gawl(double *pfn, double *pl, double *pw, size_t kn)
+
+int extInqHeader(void *ext, int *header)
 {
-  double pmod = 0;
-  int iflag;
-  int itemax;
-  double zw = 0;
-  double zdlx;
-  double zdlxn = 0;
+  extrec_t *extp = (extrec_t *) ext;
 
-  /* 1.0 Initizialization */
+  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
+    header[i] = extp->header[i];
 
-  iflag  =  0;
-  itemax = 20;
+  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
 
-  size_t iodd   = (kn % 2);
+  return 0;
+}
 
-  zdlx   =  *pl;
 
-  /* 2.0 Newton iteration */
+int extDefHeader(void *ext, const int *header)
+{
+  extrec_t *extp = (extrec_t *) ext;
 
-  for (int jter = 1; jter <= itemax+1; jter++)
-    {
-      cpledn(kn, iodd, pfn, zdlx, iflag, &zw, &zdlxn, &pmod);
-      zdlx = zdlxn;
-      if (iflag == 1) break;
-      if (fabs(pmod) <= DBL_EPSILON*1000.0) iflag = 1;
-    }
+  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
+    extp->header[i] = header[i];
 
-  *pl = zdlxn;
-  *pw = zw;
+  extp->datasize = (size_t)header[3];
+  if ( extp->number == EXT_COMP ) extp->datasize *= 2;
 
-  return;
+  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+
+  return 0;
 }
 
 static
-void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
+int extInqData(extrec_t *extp, int prec, void *data)
 {
-  /*
-   * 1.0 Initialize Fourier coefficients for ordinary Legendre polynomials
-   *
-   * Belousov, Swarztrauber, and ECHAM use zfn(0,0) = sqrt(2)
-   * IFS normalisation chosen to be 0.5*Integral(Pnm**2) = 1 (zfn(0,0) = 2.0)
-   */
-  double *zfn, *zfnlat;
-
-  double z, zfnn;
-
-  zfn    = (double *) Malloc((kn+1) * (kn+1) * sizeof(double));
-  zfnlat = (double *) Malloc((kn/2+1+1)*sizeof(double));
+  size_t i;
+  int ierr = 0;
+  int byteswap = extp->byteswap;
+  size_t datasize = extp->datasize;
+  void *buffer   = extp->buffer;
+  int rprec    = extp->prec;
 
-  zfn[0] = M_SQRT2;
-  for (size_t jn = 1; jn <= kn; jn++)
+  switch ( rprec )
     {
-      zfnn = zfn[0];
-      for (size_t jgl = 1; jgl <= jn; jgl++)
-	{
-	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl))); 
-	}
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( sizeof(FLT32) == 4 )
+	  {
+	    if ( byteswap ) swap4byte(buffer, datasize);
 
-      zfn[jn*(kn+1)+jn] = zfnn;
+	    if ( rprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT32));
+	    else
+	      for ( i = 0; i < datasize; ++i )
+		((double *) data)[i] = (double) ((float *) buffer)[i];
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT32));
+	  }
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+	if ( sizeof(FLT64) == 8 )
+	  {
+	    if ( byteswap ) swap8byte(buffer, datasize);
 
-      size_t iodd = jn % 2;
-      for (size_t jgl = 2; jgl <= jn-iodd; jgl += 2) 
-	{
-	  zfn[jn*(kn+1)+jn-jgl] = zfn[jn*(kn+1)+jn-jgl+2]
-	    *((double)((jgl-1)*(2*jn-jgl+2)))/((double)(jgl*(2*jn-jgl+1)));
-	}
+	    if ( rprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT64));
+	    else
+	      for ( i = 0; i < datasize; ++i )
+		((float *) data)[i] = (float) ((double *) buffer)[i];
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT64));
+	  }
+	break;
+    default:
+      {
+	Error("unexpected data precision %d", rprec);
+	break;
+      }
     }
 
+  return ierr;
+}
 
-  /* 2.0 Gaussian latitudes and weights */
 
-  size_t iodd = kn % 2;
-  size_t ik = iodd;
-  for (size_t jgl = iodd; jgl <= kn; jgl += 2)
-    {
-      zfnlat[ik] = zfn[kn*(kn+1)+jgl];
-      ik++;
-    } 
+int extInqDataSP(void *ext, float *data)
+{
+  return extInqData((extrec_t *)ext, EXSE_SINGLE_PRECISION, (void *) data);
+}
 
-  /*
-   * 2.1 Find first approximation of the roots of the
-   *     Legendre polynomial of degree kn.
-   */
 
-  size_t ins2 = kn/2+(kn % 2);
+int extInqDataDP(void *ext, double *data)
+{
+  return extInqData((extrec_t *)ext, EXSE_DOUBLE_PRECISION, (void *) data);
+}
 
-  for (size_t jgl = 1; jgl <= ins2; jgl++) 
-    {
-      z = ((double)(4*jgl-1))*M_PI/((double)(4*kn+2)); 
-      pl[jgl-1] = z+1.0/(tan(z)*((double)(8*kn*kn)));
-    }
 
-  /* 2.2 Computes roots and weights for transformed theta */
+static int extDefData(void *ext, int prec, const void *data)
+{
+  extrec_t *extp = (extrec_t *) ext;
+  size_t i;
+  int rprec;
+  void *buffer;
 
-  for (size_t jgl = ins2; jgl >= 1 ; jgl--) 
-    {
-      size_t jglm1 = jgl-1;
-      gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
-    }
+  if ( extDefaultPrec ) rprec = extDefaultPrec;
+  else                  rprec = extp->prec;
 
-  /* convert to physical latitude */
+  if ( ! rprec ) rprec = prec;
 
-  for (size_t jgl = 0; jgl < ins2; jgl++) 
+  extp->prec = rprec;
+
+  int *header = extp->header;
+
+  size_t datasize = (size_t)header[3];
+  if ( extp->number == EXT_COMP ) datasize *= 2;
+  size_t blocklen = datasize * (size_t)rprec;
+
+  extp->datasize = datasize;
+
+  size_t buffersize = extp->buffersize;
+
+  if ( buffersize != blocklen )
     {
-      pl[jgl] = cos(pl[jgl]);
+      buffersize = blocklen;
+      buffer = extp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      extp->buffer = buffer;
+      extp->buffersize = buffersize;
     }
+  else
+    buffer = extp->buffer;
 
-  for (size_t jgl = 1; jgl <= kn/2; jgl++) 
+  switch ( rprec )
     {
-      size_t jglm1 = jgl-1;
-      size_t isym =  kn-jgl;
-      pl[isym] =  -pl[jglm1];
-      pw[isym] =  pw[jglm1];
-    }
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( rprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT32));
+	else
+	  for ( i = 0; i < datasize; i++ )
+	    ((float *) buffer)[i] = (float) ((double *) data)[i];
 
-  Free(zfnlat);
-  Free(zfn);
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	if ( rprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT64));
+	else
+	  for ( i = 0; i < datasize; i++ )
+	    ((double *) buffer)[i] = (double) ((float *) data)[i];
 
-  return;
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", rprec);
+        break;
+      }
+    }
+
+  return 0;
 }
 
-#if 0
-static
-void gauaw_old(double *pa, double *pw, int nlat)
+
+int extDefDataSP(void *ext, const float *data)
 {
-  /*
-   * Compute Gaussian latitudes.  On return pa contains the
-   * sine of the latitudes starting closest to the north pole and going
-   * toward the south
-   *
-   */
+  return extDefData(ext, EXSE_SINGLE_PRECISION, (void *) data);
+}
 
-  const int itemax = 20;
 
-  int isym, iter, ins2, jn, j;
-  double za, zw, zan;
-  double z, zk, zkm1, zkm2, zx, zxn, zldn, zmod;
+int extDefDataDP(void *ext, const double *data)
+{
+  return extDefData(ext, EXSE_DOUBLE_PRECISION, (void *) data);
+}
 
-  /*
-   * Perform the Newton loop
-   * Find 0 of Legendre polynomial with Newton loop
-   */
 
-  ins2 = nlat/2 + nlat%2;
+int extRead(int fileID, void *ext)
+{
+  extrec_t *extp = (extrec_t *) ext;
+  size_t i;
+  void *buffer;
+  int status;
 
-  for ( j = 0; j < ins2; j++ )
+  if ( ! extp->checked )
     {
-      z = (double) (4*(j+1)-1)*M_PI / (double) (4*nlat+2);
-      pa[j] = cos(z + 1.0/(tan(z)*(double)(8*nlat*nlat)));
+      status = extCheckFiletype(fileID, &extp->byteswap);
+      if ( status == 0 ) Error("Not a EXTRA file!");
+      extp->checked = 1;
     }
 
-  for ( j = 0; j < ins2; j++ )
-    {
+  int byteswap = extp->byteswap;
 
-      za = pa[j];
+  /* read header record */
+  size_t blocklen = binReadF77Block(fileID, byteswap);
 
-      iter = 0;
-      do
-	{
-	  iter++;
-	  zk = 0.0;
+  if ( fileEOF(fileID) ) return -1;
 
-	  /* Newton iteration step */
+  if ( EXT_Debug )
+    Message("blocklen = %lu", blocklen);
 
-	  zkm2 = 1.0;
-	  zkm1 = za;
-	  zx = za;
-	  for ( jn = 2; jn <= nlat; jn++ )
-	    {
-	      zk = ((double) (2*jn-1)*zx*zkm1-(double)(jn-1)*zkm2) / (double)(jn);
-	      zkm2 = zkm1;
-	      zkm1 = zk;
-	    }
-	  zkm1 = zkm2;
-	  zldn = ((double) (nlat)*(zkm1-zx*zk)) / (1.-zx*zx);
-	  zmod = -zk/zldn;
-	  zxn = zx+zmod;
-	  zan = zxn;
-
-	  /* computes weight */
-
-	  zkm2 = 1.0;
-	  zkm1 = zxn;
-	  zx = zxn;
-	  for ( jn = 2; jn <= nlat; jn++ )
-	    {
-	      zk = ((double) (2*jn-1)*zx*zkm1-(double)(jn-1)*zkm2) / (double) (jn);
-	      zkm2 = zkm1;
-	      zkm1 = zk;
-	    }
-	  zkm1 = zkm2;
-	  zw = (1.0-zx*zx) / ((double) (nlat*nlat)*zkm1*zkm1);
-	  za = zan;
-	}
-      while ( iter <= itemax && fabs(zmod) >= DBL_EPSILON );
+  size_t hprec = blocklen / EXT_HEADER_LEN;
 
-      pa[j] = zan;
-      pw[j] = 2.0*zw;
-    }
+  extp->prec = (int)hprec;
 
-#if defined (SX)
-#pragma vdir nodep
-#endif
-  for (j = 0; j < nlat/2; j++)
+  switch ( hprec )
     {
-      isym = nlat-(j+1);
-      pa[isym] = -pa[j];
-      pw[isym] =  pw[j];
-    }
-
-  return;
-}
-#endif
-
-void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
-{
-  //gauaw_old(pa, pw, nlat);
-  gauaw(nlat, pa, pw);
-}
+    case EXSE_SINGLE_PRECISION:
+      {
+        INT32 tempheader[4];
+	binReadInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader);
 
-/*
-#define NGL  48
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          extp->header[i] = (int)tempheader[i];
 
-int main (int rgc, char *argv[])
-{
-  int ngl = NGL;
-  double plo[NGL], pwo[NGL];
-  double pl[NGL], pw[NGL];
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+        INT64 tempheader[4];
+	binReadInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader);
 
-  int i;
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          extp->header[i] = (int)tempheader[i];
 
-  gauaw(ngl, pl, pw);
-  gauaw_old(plo, pwo, ngl);
-  for (i = 0; i < ngl; i++)
-    {
-      pl[i]  = asin(pl[i])/M_PI*180.0;
-      plo[i] = asin(plo[i])/M_PI*180.0;
+	break;
+      }
+    default:
+      {
+	Error("Unexpected header precision %d", hprec);
+        break;
+      }
     }
 
-  for (i = 0; i < ngl; i++)
+  size_t blocklen2 = binReadF77Block(fileID, byteswap);
+
+  if ( blocklen2 != blocklen )
     {
-      fprintf(stderr, "%4d%25.18f%25.18f%25.18f%25.18f\n", i+1, pl[i], pw[i], pl[i]-plo[i], pw[i]-pwo[i]);
+      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
     }
 
-  return 0;
-}
-*/
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  extp->datasize = (size_t)extp->header[3];
 
-#if  defined  (HAVE_LIBGRIB_API)
-#  include <grib_api.h>
-#endif
+  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
 
-#include <stdio.h>
+  blocklen = binReadF77Block(fileID, byteswap);
 
+  size_t buffersize = (size_t)extp->buffersize;
 
-static char gribapi_libvers[64] = "";
-#if  defined  (HAVE_LIBGRIB_API)
-static int gribapi_libvers_init;
-#endif
+  if ( buffersize < blocklen )
+    {
+      buffersize = blocklen;
+      buffer = extp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      extp->buffer = buffer;
+      extp->buffersize = buffersize;
+    }
+  else
+    buffer = extp->buffer;
 
+  size_t dprec = blocklen / extp->datasize;
 
-void gribapiLibraryVersion(int* major_version, int* minor_version, int* revision_version)
-{
-#if  defined  (HAVE_LIBGRIB_API)
-  long version = grib_get_api_version();
-  (*major_version)    = (int)(version/10000);
-  (*minor_version)    = (int)((version-(*major_version)*10000)/100);
-  (*revision_version) = (int)(version-(*major_version)*10000-(*minor_version)*100);
-#else
-  (*major_version)    = 0;
-  (*minor_version)    = 0;
-  (*revision_version) = 0;
-#endif
-}
+  if ( dprec == hprec )
+    {
+      extp->number = EXT_REAL;
+    }
+  else if ( dprec == 2*hprec )
+    {
+      dprec /= 2;
+      extp->datasize *= 2;
+      extp->number = EXT_COMP;
+    }
 
-const char *gribapiLibraryVersionString(void)
-{
-#if  defined  (HAVE_LIBGRIB_API)
-  if (!gribapi_libvers_init)
+  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
     {
-      int major_version, minor_version, revision_version;
+      Warning("Unexpected data precision %d", dprec);
+      return -1;
+    }
 
-      gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
+  fileRead(fileID, buffer, blocklen);
 
-      sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
-      gribapi_libvers_init = 1;
+  blocklen2 = binReadF77Block(fileID, byteswap);
+
+  if ( blocklen2 != blocklen )
+    {
+      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
     }
-#endif
 
-  return (gribapi_libvers);
+  return 0;
 }
 
 
-void gribContainersNew(stream_t * streamptr)
+int extWrite(int fileID, void *ext)
 {
-  int editionNumber = 2;
+  extrec_t *extp = (extrec_t *) ext;
+  size_t i;
+  union { INT32 i32[EXT_HEADER_LEN]; INT64 i64[EXT_HEADER_LEN]; } tempheader;
+  int byteswap = extp->byteswap;
+  int rprec  = extp->prec;
+  int number = extp->number;
+  int *header = extp->header;
 
-  if ( streamptr->filetype == FILETYPE_GRB ) editionNumber = 1;
-  (void)editionNumber;
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( streamptr->filetype == FILETYPE_GRB )
-    {
-    }
-  else
-#endif
-    {
-      int nvars = streamptr->nvars;
+  /* write header record */
+  size_t blocklen = EXT_HEADER_LEN * (size_t)rprec;
 
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers;
-      gribContainers = (gribContainer_t **) Malloc(nvars*sizeof(gribContainer_t *));
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      for ( int varID = 0; varID < nvars; ++varID )
-        {
-          int nlevs = streamptr->vars[varID].nlevs;
-          gribContainers[varID] = (gribContainer_t *) Malloc(nlevs*sizeof(gribContainer_t));
+  switch ( rprec )
+    {
+    case EXSE_SINGLE_PRECISION:
+      {
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          tempheader.i32[i] = (INT32) header[i];
 
-          for ( int levelID = 0; levelID < nlevs; ++levelID )
-            {
-              gribContainers[varID][levelID].gribHandle = gribHandleNew(editionNumber);
-              gribContainers[varID][levelID].init = FALSE;
-            }
-	}
+	binWriteInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader.i32);
 
-      streamptr->gribContainers = (void **) gribContainers;
-#else
-      gribContainer_t *gribContainers
-        = (gribContainer_t *) Malloc((size_t)nvars*sizeof(gribContainer_t));
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          tempheader.i64[i] = (INT64) header[i];
 
-      for ( int varID = 0; varID < nvars; ++varID )
-        {
-          gribContainers[varID].gribHandle = gribHandleNew(editionNumber);
-          gribContainers[varID].init = FALSE;
-	}
+	binWriteInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader.i64);
 
-      streamptr->gribContainers = (void *) gribContainers;
-#endif
+	break;
+      }
+    default:
+      {
+	Error("unexpected header precision %d", rprec);
+        break;
+      }
     }
-}
 
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-void gribContainersDelete(stream_t * streamptr)
-{
-  if ( streamptr->gribContainers )
-    {
-      int nvars = streamptr->nvars;
-
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers = (gribContainer_t **) streamptr->gribContainers;
+  size_t datasize = (size_t)header[3];
+  if ( number == EXT_COMP ) datasize *= 2;
+  blocklen = datasize * (size_t)rprec;
 
-      for ( int varID = 0; varID < nvars; ++varID )
-	{
-          int nlevs = streamptr->vars[varID].nlevs;
-          for ( int levelID = 0; levelID < nlevs; ++levelID )
-            {
-              gribHandleDelete(gribContainers[varID][levelID].gribHandle);
-            }
-          Free(gribContainers[varID]);
-	}
-#else
-      gribContainer_t *gribContainers = (gribContainer_t *) streamptr->gribContainers;
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      for ( int varID = 0; varID < nvars; ++varID )
-	{
-          gribHandleDelete(gribContainers[varID].gribHandle);
-	}
-#endif
+  extp->datasize = datasize;
 
-      Free(gribContainers);
+  void *buffer = extp->buffer;
 
-      streamptr->gribContainers = NULL;
+  switch ( rprec )
+    {
+    case EXSE_SINGLE_PRECISION:
+      {
+	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", rprec);
+        break;
+      }
     }
+
+  binWriteF77Block(fileID, byteswap, blocklen);
+
+  return 0;
 }
 /*
  * Local Variables:
@@ -22907,7390 +21720,7862 @@ void gribContainersDelete(stream_t * streamptr)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _GRID_H
-#define _GRID_H
+#if defined (HAVE_CONFIG_H)
+#endif
 
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>  // gettimeofday()
 
-typedef unsigned char mask_t;
 
-typedef struct grid_t grid_t;
 
-struct gridVirtTable
-{
-  void (*destroy)(grid_t *gridptr);
-  grid_t *(*copy)(grid_t *gridptr);
-  void (*copyScalarFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
-  void (*copyArrayFields)(grid_t *gridptrOrig, grid_t *gridptrDup);
-  void (*defXVals)(grid_t *gridptr, const double *xvals);
-  void (*defYVals)(grid_t *gridptr, const double *yvals);
-  void (*defMask)(grid_t *gridptr, const int *mask);
-  void (*defMaskGME)(grid_t *gridptr, const int *mask);
-  void (*defXBounds)(grid_t *gridptr, const double *xbounds);
-  void (*defYBounds)(grid_t *gridptr, const double *ybounds);
-  void (*defArea)(grid_t *gridptr, const double *area);
-  double (*inqXVal)(grid_t *gridptr, int index);
-  double (*inqYVal)(grid_t *gridptr, int index);
-  int (*inqXVals)(grid_t *gridptr, double *xvals);
-  int (*inqYVals)(grid_t *gridptr, double *yvals);
-  const double *(*inqXValsPtr)(grid_t *gridptr);
-  const double *(*inqYValsPtr)(grid_t *gridptr);
-  /* return if for both grids, all xval and all yval are equal */
-  bool (*compareXYFull)(grid_t *gridRef, grid_t *gridTest);
-  /* return if for both grids, x[0], y[0], x[size-1] and y[size-1] are
-   * respectively equal */
-  bool (*compareXYAO)(grid_t *gridRef, grid_t *gridTest);
-  void (*inqArea)(grid_t *gridptr, double *area);
-  const double *(*inqAreaPtr)(grid_t *gridptr);
-  int (*hasArea)(grid_t *gridptr);
-  int (*inqMask)(grid_t *gridptr, int *mask);
-  int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
-  int (*inqXBounds)(grid_t *gridptr, double *xbounds);
-  int (*inqYBounds)(grid_t *gridptr, double *ybounds);
-  const double *(*inqXBoundsPtr)(grid_t *gridptr);
-  const double *(*inqYBoundsPtr)(grid_t *gridptr);
-};
+#if ! defined (O_BINARY)
+#define O_BINARY 0
+#endif
 
-struct grid_t {
-  int     self;
-  int     type;                   /* grid type                      */
-  int     prec;                   /* grid precision                 */
-  int     proj;                   /* grid projection                */
-  mask_t *mask;
-  mask_t *mask_gme;
-  double *xvals;
-  double *yvals;
-  double *area;
-  double *xbounds;
-  double *ybounds;
-  double  xfirst, yfirst;
-  double  xlast, ylast;
-  double  xinc, yinc;
-  double  lcc_originLon;          /* Lambert Conformal Conic        */
-  double  lcc_originLat;
-  double  lcc_lonParY;
-  double  lcc_lat1;
-  double  lcc_lat2;
-  double  lcc_xinc;
-  double  lcc_yinc;
-  int     lcc_projflag;
-  int     lcc_scanflag;
-  short   lcc_defined;
-  short   lcc2_defined;
-  int     laea_defined;
-  double  lcc2_lon_0;             /* Lambert Conformal Conic 2      */
-  double  lcc2_lat_0;
-  double  lcc2_lat_1;
-  double  lcc2_lat_2;
-  double  lcc2_a;
-  double  laea_lon_0;             /* Lambert Azimuthal Equal Area   */
-  double  laea_lat_0;
-  double  laea_a;
-  double  xpole, ypole, angle;    /* rotated north pole             */
-  short   isCyclic;               /* TRUE for global cyclic grids   */
-  short   isRotated;              /* TRUE for rotated grids         */
-  short   xdef;                   /* 0: undefined 1:xvals 2:x0+xinc */
-  short   ydef;                   /* 0: undefined 1:yvals 2:y0+yinc */
-  int     nd, ni, ni2, ni3;       /* parameter for GRID_GME         */
-  int     number, position;       /* parameter for GRID_REFERENCE   */
-  int     trunc;                  /* parameter for GRID_SPECTEAL    */
-  int     nvertex;
-  char   *reference;
-  unsigned char uuid[CDI_UUID_SIZE]; /* uuid for grid reference        */
-  int    *rowlon;
-  int     nrowlon;
-  int     size;
-  int     xsize;                  /* number of values along X */
-  int     ysize;                  /* number of values along Y */
-  int     np;                     /* number of parallels between a pole and the equator */
-  short   lcomplex;
-  short   hasdims;
-  const char *xstdname;
-  const char *ystdname;
-  char    xdimname[CDI_MAX_NAME];
-  char    ydimname[CDI_MAX_NAME];
-  char    vdimname[CDI_MAX_NAME];
-  char    xname[CDI_MAX_NAME];
-  char    yname[CDI_MAX_NAME];
-  char    xlongname[CDI_MAX_NAME];
-  char    ylongname[CDI_MAX_NAME];
-  char    xunits[CDI_MAX_NAME];
-  char    yunits[CDI_MAX_NAME];
-  char   *name;
-  const struct gridVirtTable *vtable;
-  void *extraData;
-};
+#ifndef strdupx
+#ifndef strdup
+char *strdup(const char *s);
+#endif
+#define strdupx  strdup
+/*
+#define strdupx(s)                                \
+({                                                \
+   const char *__old = (s);                       \
+   size_t __len = strlen(__old) + 1;              \
+   char *__new = (char *) Malloc(__len);          \
+   (char *) memcpy(__new, __old, __len);          \
+})
+*/
+#endif
 
 
-void grid_init(grid_t *gridptr);
-void
-cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
-void grid_free(grid_t *gridptr);
-grid_t *gridID2Ptr(int gridID);
-extern const struct gridVirtTable cdiGridVtable;
+#if defined (HAVE_MMAP)
+#  include <sys/mman.h> /* mmap() is defined in this header */
+#endif
 
-unsigned cdiGridCount(void);
 
-const double *gridInqXvalsPtr(int gridID);
-const double *gridInqYvalsPtr(int gridID);
+/* #define  MAX_FILES  FOPEN_MAX */
+#define  MAX_FILES  4096
 
-const double *gridInqXboundsPtr(int gridID);
-const double *gridInqYboundsPtr(int gridID);
-const double *gridInqAreaPtr(int gridID);
+static int _file_max = MAX_FILES;
 
-const char *gridInqXnamePtr(int gridID);
-const char *gridInqYnamePtr(int gridID);
+static void file_initialize(void);
 
-const char *gridInqReferencePtr(int gridID);
+static bool _file_init = false;
 
-int gridGenerate(const grid_t *grid);
+#if  defined  (HAVE_LIBPTHREAD)
+#include <pthread.h>
 
-void cdiGridGetIndexList(unsigned, int * );
+static pthread_once_t  _file_init_thread = PTHREAD_ONCE_INIT;
+static pthread_mutex_t _file_mutex;
 
-void
-gridUnpack(char * unpackBuffer, int unpackBufferSize,
-           int * unpackBufferPos, int originNamespace, void *context,
-           int force_id);
+#  define FILE_LOCK()         pthread_mutex_lock(&_file_mutex)
+#  define FILE_UNLOCK()       pthread_mutex_unlock(&_file_mutex)
+#  define FILE_INIT()        \
+   if ( _file_init == false ) pthread_once(&_file_init_thread, file_initialize)
 
-struct addIffNewRes
-{
-  int Id;
-  int isNew;
-};
+#else
 
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
+#  define FILE_LOCK()
+#  define FILE_UNLOCK()
+#  define FILE_INIT()        \
+   if ( _file_init == false ) file_initialize()
 
 #endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
-#define INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
 
-#ifdef HAVE_LIBGRIB_API
 
+typedef struct
+{
+  int        self;
+  int        flag;           /* access and error flag         */
+  int        eof;            /* end of file flag              */
+  int        fd;             /* file descriptor used for read */
+  FILE      *fp;             /* FILE pointer used for write   */
+  char      *name;           /* file name                     */
+  off_t      size;           /* file size                     */
+  off_t      position;       /* file position                 */
+  long       access;         /* file access                   */
+  off_t      byteTrans;      /*                               */
+  size_t     blockSize;      /* file block size               */
+  int        mode;           /* file access mode              */
+  short      type;           /* file type ( 1:open 2:fopen )  */
+  short      bufferType;     /* buffer type ( 1:std 2:mmap )  */
+  size_t     bufferSize;     /* file buffer size              */
+  size_t     mappedSize;     /* mmap buffer size              */
+  char      *buffer;         /* file buffer                   */
+  long       bufferNumFill;  /* number of buffer fill         */
+  char      *bufferPtr;      /* file buffer pointer           */
+  off_t      bufferPos;
+  off_t      bufferStart;
+  off_t      bufferEnd;
+  size_t     bufferCnt;
+  double     time_in_sec;
+}
+bfile_t;
 
-#include <grib_api.h>
 
-#include <stdbool.h>
+enum F_I_L_E_Flags
+  {
+    FILE_READ  =  01,
+    FILE_WRITE =  02,
+    FILE_UNBUF =  04,
+    FILE_EOF   = 010,
+    FILE_ERROR = 020
+  };
 
-char* gribCopyString(grib_handle* gribHandle, const char* key);
-bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue);
 
-bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue);
-long gribGetLong(grib_handle* gh, const char* key);
-long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue);
+static bool FileInfo = false;
 
-double gribGetDouble(grib_handle* gh, const char* key);
-double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue);
 
-size_t gribGetArraySize(grib_handle* gribHandle, const char* key);
-void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array);       //The caller is responsible to ensure a sufficiently large buffer.
-void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array);   //The caller is responsible to ensure a sufficiently large buffer.
+#if ! defined (MIN_BUF_SIZE)
+#  define  MIN_BUF_SIZE  131072L
+#endif
 
-long gribEditionNumber(grib_handle* gh);
-char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType);     //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
-int gribapiTimeIsFC(grib_handle *gh);
-int gribapiGetTsteptype(grib_handle *gh);
-int gribGetDatatype(grib_handle* gribHandle);
-int gribapiGetParam(grib_handle *gh);
-int gribapiGetGridType(grib_handle *gh);
-void gribapiGetGrid(grib_handle *gh, grid_t *grid);
 
-#endif
+static size_t FileBufferSizeMin = MIN_BUF_SIZE;
+static long   FileBufferSizeEnv = -1;
+static short  FileBufferTypeEnv =  0;
 
-#endif
+static short  FileTypeRead  = FILE_TYPE_OPEN;
+static short  FileTypeWrite = FILE_TYPE_FOPEN;
+static int    FileFlagWrite = 0;
+
+static int    FILE_Debug = 0;   /* If set to 1, debugging */
+
+
+static void file_table_print(void);
 
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
+ * A version string.
  */
-#if defined (HAVE_CONFIG_H)
-#endif
+#undef   LIBVERSION
+#define  LIBVERSION      1.8.3
+#define  XSTRING(x)	 #x
+#define  STRING(x) 	 XSTRING(x)
+static const char file_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__;
 
-#ifdef HAVE_LIBGRIB_API
+/*
+  21/05/2004  1.3.2 set min I/O Buffersize to 128k
+  31/05/2005  1.4.0 replace fileTable by _fileList
+  26/08/2005  1.4.1 fileClose with return value
+                    checks for all fileptr
+  01/09/2005  1.5.0 thread safe version
+  06/11/2005  1.5.1 add filePtrEOF, filePtr, filePtrGetc
+  03/02/2006  1.5.2 ansi C: define getpagesize and strdupx
+  27/12/2007  1.6.0 add FILE_TYPE_FOPEN
+  24/03/2008  1.6.1 add O_BINARY if available
+                    remove default HAVE_MMAP
+                    use HAVE_STRUCT_STAT_ST_BLKSIZE
+  22/08/2010  1.7.0 refactor
+  11/11/2010  1.7.1 update for changed interface of error.h
+  02/02/2012  1.8.0 cleanup
+  16/11/2012  1.8.1 added support for unbuffered write
+  27/06/2013  1.8.2 added env. var. FILE_TYPE_WRITE (1:open; 2:fopen)
+ */
+
+
+typedef struct _filePtrToIdx {
+  int idx;
+  bfile_t *ptr;
+  struct _filePtrToIdx *next;
+} filePtrToIdx;
 
 
+static filePtrToIdx *_fileList  = NULL;
+static filePtrToIdx *_fileAvail = NULL;
 
-#include <assert.h>
-#include <time.h>
+static
+void file_list_new(void)
+{
+  assert(_fileList == NULL);
 
-#define FAIL_ON_GRIB_ERROR(function, gribHandle, key, ...) do\
-{\
-  int errorCode = (int)function(gribHandle, key, __VA_ARGS__);  \
-  if(errorCode)\
-    {\
-      fprintf(stderr, "%s:%d: Error in function `%s`: `%s` returned error code %d for key \"%s\"", __FILE__, __LINE__, __func__, #function, errorCode, key);\
-      exit(errorCode);\
-    }\
-} while(0)
+  _fileList = (filePtrToIdx *) Malloc((size_t)_file_max*sizeof(filePtrToIdx));
+}
 
-//A simple wrapper for grib_get_string() that returns a newly allocated string.
-char* gribCopyString(grib_handle* gribHandle, const char* key)
+static
+void file_list_delete(void)
 {
-  char* result = NULL;
-  size_t length;
-#ifdef HAVE_GRIB_GET_LENGTH
-  if(!grib_get_length(gribHandle, key, &length))
+  if ( _fileList )
     {
-    char* result = (char *) Malloc(length);
-    if(!grib_get_string(gribHandle, key, result, &length))
-    result = (char *) Realloc(result, length);
-
-    else
-      {
-          Free(result);
-          result = NULL;
-      }
+      Free(_fileList);
+      _fileList = NULL;
     }
-#else
-  length = 1024;         /* there's an implementation limit
-                          * that makes strings longer than
-                          * this unlikely in grib_api versions
-                          * not providing grib_get_length */
-  int rc;
-  result = (char *) Malloc(length);
-  while ((rc = grib_get_string(gribHandle, key, result, &length))
-         == GRIB_BUFFER_TOO_SMALL || rc == GRIB_ARRAY_TOO_SMALL)
+}
+
+static
+void file_init_pointer(void)
+{
+  for ( int i = 0; i < _file_max; i++ )
     {
-      if (length <= 1024UL * 1024UL)
-        {
-          length *= 2;
-          result = Realloc(result, length);
-        }
-      else
-        break;
+      _fileList[i].next = _fileList + i + 1;
+      _fileList[i].idx  = i;
+      _fileList[i].ptr  = 0;
     }
-  if (!rc)
-    result = Realloc(result, length);
-  else
+
+  _fileList[_file_max-1].next = 0;
+
+  _fileAvail = _fileList;
+}
+
+static
+bfile_t *file_to_pointer(int idx)
+{
+  bfile_t *fileptr = NULL;
+
+  FILE_INIT();
+
+  if ( idx >= 0 && idx < _file_max )
     {
-      Free(result);
-      result = NULL;
+      FILE_LOCK();
+
+      fileptr = _fileList[idx].ptr;
+
+      FILE_UNLOCK();
     }
-#endif
-  return result;
+  else
+    Error("file index %d undefined!", idx);
+
+  return fileptr;
 }
 
-//A simple wrapper for grib_get_string() for the usecase that the result is only compared to a given constant string.
-//Returns true if the key exists and the value is equal to the given string.
-bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue)
+/* Create an index from a pointer */
+static
+int file_from_pointer(bfile_t *ptr)
 {
-  size_t expectedLength = strlen(expectedValue) + 1;
-#ifdef HAVE_GRIB_GET_LENGTH
-  size_t length;
-  if(grib_get_length(gribHandle, key, &length)) return false;
-  if(length != expectedLength) return false;
-  char *value = (char *) Malloc(length);
-  if(grib_get_string(gribHandle, key, value, &length)) return false;
-  int rc = !strcmp(value, expectedValue);
-  Free(value);
-#else
-  char *value = gribCopyString(gribHandle, key);
-  int rc;
-  if (value)
-  {
-    rc = strlen(value) + 1 == expectedLength ?
-      !strcmp(value, expectedValue)
-      : false;
-  }
+  int idx = -1;
+  filePtrToIdx *newptr;
+
+  if ( ptr )
+    {
+      FILE_LOCK();
+
+      if ( _fileAvail )
+	{
+	  newptr       = _fileAvail;
+	  _fileAvail   = _fileAvail->next;
+	  newptr->next = 0;
+	  idx	       = newptr->idx;
+	  newptr->ptr  = ptr;
+
+	  if ( FILE_Debug )
+	    Message("Pointer %p has idx %d from file list", ptr, idx);
+	}
+      else
+	Warning("Too many open files (limit is %d)!", _file_max);
+
+      FILE_UNLOCK();
+    }
   else
-    rc = false;
-  Free(value);
-#endif
-  return rc;
-}
+    Error("Internal problem (pointer %p undefined)", ptr);
 
-//A simple wrapper for grib_get_long() for the usecase that the result is only compared to a given constant value.
-//Returns true if the key exists and the value is equal to the given one.
-bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue)
-{
-  long value;
-  if(grib_get_long(gribHandle, key, &value)) return false;
-  return value == expectedValue;
+  return idx;
 }
 
-//A simple wrapper for grib_get_long() for the usecase that failure to fetch the value is fatal.
-long gribGetLong(grib_handle* gh, const char* key)
+static
+void file_init_entry(bfile_t *fileptr)
 {
-  long result;
-  FAIL_ON_GRIB_ERROR(grib_get_long, gh, key, &result);
-  return result;
-}
+  fileptr->self          = file_from_pointer(fileptr);
 
-//A simple wrapper for grib_get_long() for the usecase that a default value is used in the case that the operation fails.
-long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue)
-{
-  long result;
-  if(grib_get_long(gribHandle, key, &result)) return defaultValue;
-  if(result == GRIB_MISSING_LONG) return defaultValue;
-  return result;
+  fileptr->flag          = 0;
+  fileptr->fd            = -1;
+  fileptr->fp            = NULL;
+  fileptr->mode          = 0;
+  fileptr->size          = 0;
+  fileptr->name          = NULL;
+  fileptr->access        = 0;
+  fileptr->position      = 0;
+  fileptr->byteTrans     = 0;
+  fileptr->type          = 0;
+  fileptr->bufferType    = 0;
+  fileptr->bufferSize    = 0;
+  fileptr->mappedSize    = 0;
+  fileptr->buffer        = NULL;
+  fileptr->bufferNumFill = 0;
+  fileptr->bufferStart   = 0;
+  fileptr->bufferEnd     = -1;
+  fileptr->bufferPos     = 0;
+  fileptr->bufferCnt     = 0;
+  fileptr->bufferPtr     = NULL;
+  fileptr->time_in_sec   = 0.0;
 }
 
-//A simple wrapper for grib_get_double() for the usecase that failure to fetch the value is fatal.
-double gribGetDouble(grib_handle* gh, const char* key)
+static
+bfile_t *file_new_entry(void)
 {
-  double result;
-  FAIL_ON_GRIB_ERROR(grib_get_double, gh, key, &result);
-  return result;
-}
+  bfile_t *fileptr = (bfile_t *) Malloc(sizeof(bfile_t));
+  if ( fileptr ) file_init_entry(fileptr);
 
-//A sample wrapper for grib_get_double() for the usecase that a default value is used in the case that the operation fails.
-double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue)
-{
-  double result;
-  if(grib_get_double(gribHandle, key, &result)) return defaultValue;
-  if(IS_EQUAL(result, GRIB_MISSING_DOUBLE)) return defaultValue;
-  return result;
+  return fileptr;
 }
 
-//A simple wrapper for grib_get_size() for the usecase that failure to fetch the value is fatal.
-size_t gribGetArraySize(grib_handle* gribHandle, const char* key)
+static
+void file_delete_entry(bfile_t *fileptr)
 {
-  size_t result;
-  FAIL_ON_GRIB_ERROR(grib_get_size, gribHandle, key, &result);
-  return result;
-}
+  int idx = fileptr->self;
 
-//A simple wrapper for grib_get_double_array() for the usecase that failure to fetch the data is fatal.
-void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
-{
-  size_t valueCount = gribGetArraySize(gribHandle, key);
-  FAIL_ON_GRIB_ERROR(grib_get_double_array, gribHandle, key, array, &valueCount);
-}
+  FILE_LOCK();
 
-//A simple wrapper for grib_get_long_array() for the usecase that failure to fetch the data is fatal.
-void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array)
-{
-  size_t valueCount = gribGetArraySize(gribHandle, key);
-  FAIL_ON_GRIB_ERROR(grib_get_long_array, gribHandle, key, array, &valueCount);
-}
+  Free(fileptr);
+
+  _fileList[idx].next = _fileAvail;
+  _fileList[idx].ptr  = 0;
+  _fileAvail   	      = &_fileList[idx];
 
+  FILE_UNLOCK();
 
-//We need the edition number so frequently, that it's convenient to give it its own function.
-long gribEditionNumber(grib_handle* gh)
-{
-  return gribGetLong(gh, "editionNumber");
+  if ( FILE_Debug )
+    Message("Removed idx %d from file list", idx);
 }
 
-//This return value of this should be passed to a call to resetTz(), it is a malloc'ed string with the content of the TZ environment variable before the call (or NULL if that was not set).
-static char* setUtc()
+
+const char *fileLibraryVersion(void)
 {
-  char* temp = getenv("TZ"), *result = NULL;
-  if(temp) result = strdup(temp);
-  setenv("TZ", "UTC", 1);
-  return result;
+  return file_libvers;
 }
 
-//Undoes the effect of setUtc(), pass to it the return value of the corresponding setUtc() call, it will free the string.
-static void resetTz(char* savedTz)
+static
+int pagesize(void)
 {
-  if(savedTz)
-    {
-      setenv("TZ", savedTz, 1);
-      Free(savedTz);
-    }
-  else
-    {
-      unsetenv("TZ");
-    }
+#if defined(_SC_PAGESIZE)
+  return (int) sysconf(_SC_PAGESIZE);
+#else
+#ifndef POSIXIO_DEFAULT_PAGESIZE
+#define POSIXIO_DEFAULT_PAGESIZE 4096
+#endif
+  return (int) POSIXIO_DEFAULT_PAGESIZE;
+#endif
 }
 
-//This function uses the system functions to normalize the date representation according to the gregorian calendar.
-//Returns zero on success.
-static int normalizeDays(struct tm* me)
+static
+double file_time()
 {
-  char* savedTz = setUtc();     //Ensure that mktime() does not interprete the date according to our local time zone.
-
-  int result = mktime(me) == (time_t)-1;        //This does all the heavy lifting.
-
-  resetTz(savedTz);
-  return result;
+  struct timeval mytime;
+  gettimeofday(&mytime, NULL);
+  double tseconds = (double) mytime.tv_sec + (double) mytime.tv_usec*1.0e-6;
+  return tseconds;
 }
 
-//Returns zero on success.
-static int addSecondsToDate(struct tm* me, long long amount)
+void fileDebug(int debug)
 {
-  //It is irrelevant here whether days are zero or one based, the correction would have be undone again so that it is effectless.
-  long long seconds = ((me->tm_mday*24ll + me->tm_hour)*60 + me->tm_min)*60 + me->tm_sec;    //The portion of the date that uses fixed increments.
-  seconds += amount;
-  me->tm_mday = (int)(seconds / 24 / 60 / 60);
-  seconds -= (long long)me->tm_mday * 24 * 60 * 60;
-  me->tm_hour = (int)(seconds / 60 / 60);
-  seconds -= (long long)me->tm_hour * 60 * 60;
-  me->tm_min = (int)(seconds / 60);
-  seconds -= (long long)(me->tm_min * 60);
-  me->tm_sec = (int)seconds;
-  return normalizeDays(me);
+  FILE_Debug = debug;
+  if ( FILE_Debug ) Message("Debug level %d", debug);
 }
 
-static void addMonthsToDate(struct tm* me, long long amount)
+
+void *filePtr(int fileID)
 {
-  long long months = me->tm_year*12ll + me->tm_mon;
-  months += amount;
-  me->tm_year = (int)(months/12);
-  months -= (long long)me->tm_year*12;
-  me->tm_mon = (int)months;
+  return (void*)file_to_pointer(fileID);
 }
 
-//unit is a value according to code table 4.4 of the GRIB2 specification, returns non-zero on error
-static int addToDate(struct tm* me, long long amount, long unit)
+static
+void file_pointer_info(const char *caller, int fileID)
 {
-  switch(unit)
+  if ( FILE_Debug )
     {
-      case 0: return addSecondsToDate(me,       60*amount);   // minute
-      case 1: return addSecondsToDate(me,    60*60*amount);   // hour
-      case 2: return addSecondsToDate(me, 24*60*60*amount);   // day
-
-      case 3: addMonthsToDate(me,        amount); return 0;   // month
-      case 4: addMonthsToDate(me,     12*amount); return 0;   // year
-      case 5: addMonthsToDate(me,  10*12*amount); return 0;   // decade
-      case 6: addMonthsToDate(me,  30*12*amount); return 0;   // normal
-      case 7: addMonthsToDate(me, 100*12*amount); return 0;   // century
-
-      case 10: return addSecondsToDate(me,  3*60*60*amount);  // eighth of a day
-      case 11: return addSecondsToDate(me,  6*60*60*amount);  // quarter day
-      case 12: return addSecondsToDate(me, 12*60*60*amount);  // half day
-      case 13: return addSecondsToDate(me,          amount);  // second
-
-      default: return 1;        //reserved, unknown, or missing
+      fprintf(stdout, "%-18s : ", caller);
+      fprintf(stdout, "The fileID %d underlying pointer is not valid!", fileID);
+      fprintf(stdout, "\n");
     }
 }
 
-static char* makeDateString(struct tm* me)
-{
-  char *result
-    = (char *) Malloc(       4+1+ 2+1+ 2+1+ 2+1+ 2+1+ 2+ 4+ 1);
-  sprintf(result, "%04d-%02d-%02dT%02d:%02d:%02d.000", me->tm_year + 1900, me->tm_mon + 1, me->tm_mday, me->tm_hour, me->tm_min, me->tm_sec);
-  return result;
-}
 
-//FIXME: This ignores any calendar definition that might be present.
-//XXX: Identification templates are not implemented in grib_api-1.12.3, so even if I implemented the other calendars now, it wouldn't be possible to use them.
-static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecastTime, bool* outHaveTimeRange)
+int fileSetBufferType(int fileID, int type)
 {
-  switch(gribGetLong(gh, "productDefinitionTemplateNumber"))
+  int ret = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
+
+  if ( fileptr )
     {
-      case 20: case 30: case 31: case 254: case 311: case 2000:
-        *outHaveForecastTime = false, *outHaveTimeRange = false;
-        return 0;
+      switch (type)
+	{
+	case FILE_BUFTYPE_STD:
+	case FILE_BUFTYPE_MMAP:
+	  fileptr->bufferType = (short)type;
+	  break;
+	default:
+	  Error("File type %d not implemented!", type);
+	}
+    }
 
-      //case 55 and case 40455 are the same: 55 is the proposed standard value, 40455 is the value in the local use range that is used by the dwd until the standard is updated.
-      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 55: case 60: case 1000: case 1002: case 1100: case 40033: case 40455:
-        *outHaveForecastTime = true, *outHaveTimeRange = false;
-        return 0;
+#if ! defined (HAVE_MMAP)
+  if ( type == FILE_BUFTYPE_MMAP ) ret = 1;
+#endif
 
-      case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 34: case 42: case 43: case 46: case 47: case 61: case 91: case 1001: case 1101: case 40034:
-        *outHaveForecastTime = true, *outHaveTimeRange = true;
-        return 0;
+  return ret;
+}
 
-      default:
-        return 1;
-    }
+int fileFlush(int fileID)
+{
+  int retval = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
+  if ( fileptr ) retval = fflush(fileptr->fp);
+
+  return retval;
 }
 
-char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
+
+void fileClearerr(int fileID)
 {
-  //Get the parts of the reference date.
-  struct tm date;
-  date.tm_mon = (int)gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIB
-  date.tm_mday = (int)gribGetLong(gh, "day");
-  date.tm_hour = (int)gribGetLong(gh, "hour");
-  date.tm_min = (int)gribGetLong(gh, "minute");
+  bfile_t *fileptr = file_to_pointer(fileID);
 
-  if(gribEditionNumber(gh) == 1)
+  if ( fileptr )
     {
-      date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
+      if ( fileptr->mode != 'r' )
+	clearerr(fileptr->fp);
     }
-  else
-    {
-      date.tm_year = (int)gribGetLong(gh, "year") - 1900;   //years are -1900 based in struct tm and zero based in GRIB2
-      date.tm_sec = (int)gribGetLong(gh, "second");
+}
 
-      //If the start or end time are requested, we need to take the relative times into account.
-      if(timeType != kCdiTimeType_referenceTime)
-        {
-          //Determine whether we have a forecast time and a time range.
-          bool haveForecastTime, haveTimeRange;
-          if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
-          if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
 
-          //If we have relative times, apply the relative times to the date
-          if(haveForecastTime)
-            {
-              long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
-              long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
-              if(addToDate(&date, offset, offsetUnit)) return NULL;
-              if(timeType == kCdiTimeType_endTime)
-                {
-                  assert(haveTimeRange);
-                  long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
-                  long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
-                  if(addToDate(&date, range, rangeUnit)) return NULL;
-                }
-            }
-        }
-    }
+int filePtrEOF(void *vfileptr)
+{
+  int retval = 0;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
+  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
 
-  //Bake the date into a string.
-  return makeDateString(&date);
+  return retval;
 }
 
-int gribapiTimeIsFC(grib_handle *gh)
+
+int fileEOF(int fileID)
 {
-  if(gribEditionNumber(gh) <= 1) return true;
+  int retval = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
+  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
 
-  long sigofrtime;
-  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
-  return sigofrtime != 3;
+  return retval;
 }
 
-//Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range.
-int gribapiGetTsteptype(grib_handle *gh)
+void fileRewind(int fileID)
 {
-  int tsteptype = TSTEP_INSTANT;
-  static bool lprint = true;
+  fileSetPos(fileID, (off_t) 0, SEEK_SET);
+  fileClearerr(fileID);
+}
 
-  if ( gribapiTimeIsFC(gh) )
-    {
-      int status;
-      size_t len = 256;
-      char stepType[256];
 
-      status = grib_get_string(gh, "stepType", stepType, &len);
-      if ( status == 0 && len > 1 && len < 256 )
-        {
-          if      ( strncmp("instant", stepType, len) == 0 ) tsteptype = TSTEP_INSTANT;
-          else if ( strncmp("avg",     stepType, len) == 0 ) tsteptype = TSTEP_AVG;
-          else if ( strncmp("accum",   stepType, len) == 0 ) tsteptype = TSTEP_ACCUM;
-          else if ( strncmp("max",     stepType, len) == 0 ) tsteptype = TSTEP_MAX;
-          else if ( strncmp("min",     stepType, len) == 0 ) tsteptype = TSTEP_MIN;
-          else if ( strncmp("diff",    stepType, len) == 0 ) tsteptype = TSTEP_DIFF;
-          else if ( strncmp("rms",     stepType, len) == 0 ) tsteptype = TSTEP_RMS;
-          else if ( strncmp("sd",      stepType, len) == 0 ) tsteptype = TSTEP_SD;
-          else if ( strncmp("cov",     stepType, len) == 0 ) tsteptype = TSTEP_COV;
-          else if ( strncmp("ratio",   stepType, len) == 0 ) tsteptype = TSTEP_RATIO;
-          else if ( lprint )
-            {
-              Message("Time stepType %s unsupported, set to instant!", stepType);
-              lprint = false;
-            }
+off_t fileGetPos(int fileID)
+{
+  off_t filepos = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
 
-          // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
-        }
+  if ( fileptr )
+    {
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	filepos = fileptr->position;
+      else
+	filepos = ftell(fileptr->fp);
     }
 
-  return (tsteptype);
-}
+  if ( FILE_Debug ) Message("Position %ld", filepos);
 
-int gribGetDatatype(grib_handle* gribHandle)
-{
-  int datatype;
-  if(gribEditionNumber(gribHandle) > 1 && gribCheckString(gribHandle, "packingType", "grid_ieee"))
-    {
-      datatype = gribCheckLong(gribHandle, "precision", 1) ? DATATYPE_FLT32 : DATATYPE_FLT64;
-    }
-  else
-    {
-      long bitsPerValue;
-      datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : DATATYPE_PACK;
-    }
-  return datatype;
+  return filepos;
 }
 
-int gribapiGetParam(grib_handle *gh)
+
+int fileSetPos(int fileID, off_t offset, int whence)
 {
-  long pdis, pcat, pnum;
-  if ( gribEditionNumber(gh) <= 1 )
-    {
-      pdis = 255;
-      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "table2Version", &pcat);
-      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "indicatorOfParameter", &pnum);
-    }
-  else
+  int status = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
+
+  if ( FILE_Debug ) Message("Offset %8ld  Whence %3d", (long) offset, whence);
+
+  if ( fileptr == 0 )
     {
-      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "discipline", &pdis);
-      if(grib_get_long(gh, "parameterCategory", &pcat)) pcat = 0;
-      if(grib_get_long(gh, "parameterNumber", &pnum)) pnum = 0;
+      file_pointer_info(__func__, fileID);
+      return 1;
     }
-  return cdiEncodeParam((int)pnum, (int)pcat, (int)pdis);
-}
 
-int gribapiGetGridType(grib_handle *gh)
-{
-  int gridtype = GRID_GENERIC;
-  switch (gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1))
+  switch (whence)
     {
-      case  GRIB2_GTYPE_LATLON:
-        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GENERIC : GRID_LONLAT;
-        break;
+    case SEEK_SET:
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	{
+	  off_t position = offset;
+	  fileptr->position = position;
+	  if ( position < fileptr->bufferStart || position > fileptr->bufferEnd )
+	    {
+	      if ( fileptr->bufferType == FILE_BUFTYPE_STD )
+		fileptr->bufferPos = position;
+	      else
+		fileptr->bufferPos = position - position % pagesize();
 
-      case  GRIB2_GTYPE_GAUSSIAN:
-        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN;
-        break;
+	      fileptr->bufferCnt = 0;
+	      fileptr->bufferPtr = NULL;
+	    }
+	  else
+	    {
+	      if ( fileptr->bufferPos != fileptr->bufferEnd + 1 )
+		{
+		  if ( FILE_Debug )
+		    Message("Reset buffer pos from %ld to %ld",
+			    fileptr->bufferPos, fileptr->bufferEnd + 1);
 
-      case GRIB2_GTYPE_LATLON_ROT:   gridtype = GRID_LONLAT; break;
-      case GRIB2_GTYPE_LCC:          gridtype = GRID_LCC; break;
-      case GRIB2_GTYPE_SPECTRAL:     gridtype = GRID_SPECTRAL; break;
-      case GRIB2_GTYPE_GME:          gridtype = GRID_GME; break;
-      case GRIB2_GTYPE_UNSTRUCTURED: gridtype = GRID_UNSTRUCTURED; break;
+		  fileptr->bufferPos = fileptr->bufferEnd + 1;
+		}
+	      fileptr->bufferCnt = (size_t)(fileptr->bufferEnd - position) + 1;
+	      fileptr->bufferPtr = fileptr->buffer + position - fileptr->bufferStart;
+	    }
+	}
+      else
+	{
+	  status = fseek(fileptr->fp, offset, whence);
+	}
+      break;
+    case SEEK_CUR:
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	{
+	  fileptr->position += offset;
+	  off_t position = fileptr->position;
+	  if ( position < fileptr->bufferStart || position > fileptr->bufferEnd )
+	    {
+	      if ( fileptr->bufferType == FILE_BUFTYPE_STD )
+		fileptr->bufferPos = position;
+	      else
+		fileptr->bufferPos = position - position % pagesize();
+
+	      fileptr->bufferCnt = 0;
+	      fileptr->bufferPtr = NULL;
+	    }
+	  else
+	    {
+	      if ( fileptr->bufferPos != fileptr->bufferEnd + 1 )
+		{
+		  if ( FILE_Debug )
+		    Message("Reset buffer pos from %ld to %ld",
+			    fileptr->bufferPos, fileptr->bufferEnd + 1);
+
+		  fileptr->bufferPos = fileptr->bufferEnd + 1;
+		}
+	      fileptr->bufferCnt -= (size_t)offset;
+	      fileptr->bufferPtr += offset;
+	    }
+	}
+      else
+	{
+	  status = fseek(fileptr->fp, offset, whence);
+	}
+      break;
+    default:
+      Error("Whence = %d not implemented", whence);
     }
 
-  return gridtype;
+  if ( fileptr->position < fileptr->size )
+    if ( (fileptr->flag & FILE_EOF) != 0 )
+      fileptr->flag -= FILE_EOF;
+
+  return status;
 }
 
 static
-int gribapiGetIsRotated(grib_handle *gh)
+void file_table_print(void)
 {
-  return gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1) == GRIB2_GTYPE_LATLON_ROT;
-}
+  int lprintHeader = 1;
 
-//TODO: Simplify by use of the convenience functions (gribGetLong(), gribGetLongDefault(), etc.).
-void gribapiGetGrid(grib_handle *gh, grid_t *grid)
-{
-  long editionNumber = gribEditionNumber(gh);
-  int gridtype = gribapiGetGridType(gh);
-  /*
-  if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED )
+  for ( int fileID = 0; fileID < _file_max; fileID++ )
     {
-      gridtype = GRID_GAUSSIAN;
-      ISEC2_NumLon = 2*ISEC2_NumLat;
-      ISEC4_NumValues = ISEC2_NumLon*ISEC2_NumLat;
-    }
-  */
-  grid_init(grid);
-  cdiGridTypeInit(grid, gridtype, 0);
+      bfile_t *fileptr = file_to_pointer(fileID);
 
-  size_t datasize;
-  FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
-  long numberOfPoints;
-  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &numberOfPoints);
+      if ( fileptr )
+	{
+	  if ( lprintHeader )
+	    {
+	      fprintf(stderr, "\nFile table:\n");
+	      fprintf(stderr, "+-----+---------+");
+	      fprintf(stderr, "----------------------------------------------------+\n");
+	      fprintf(stderr, "|  ID |  Mode   |");
+	      fprintf(stderr, "  Name                                              |\n");
+	      fprintf(stderr, "+-----+---------+");
+	      fprintf(stderr, "----------------------------------------------------+\n");
+	      lprintHeader = 0;
+	    }
+
+	  fprintf(stderr, "| %3d | ", fileID);
+
+	  switch ( fileptr->mode )
+	    {
+	    case 'r':
+	      fprintf(stderr, "read   ");
+	      break;
+	    case 'w':
+	      fprintf(stderr, "write  ");
+	      break;
+	    case 'a':
+	      fprintf(stderr, "append ");
+	      break;
+	    default:
+	      fprintf(stderr, "unknown");
+	    }
 
-  switch (gridtype)
+          fprintf(stderr, " | %-51s|\n", fileptr->name);
+	}
+    }
+
+  if ( lprintHeader == 0 )
     {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-      {
-        long nlon, nlat;
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &nlon);
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &nlat);
+      fprintf(stderr, "+-----+---------+");
+      fprintf(stderr, "----------------------------------------------------+\n");
+    }
+}
 
-        if ( gridtype == GRID_GAUSSIAN )
-          {
-            long lpar;
-            FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
-            grid->np = (int)lpar;
-          }
 
-        if ( numberOfPoints != nlon*nlat )
-          Error("numberOfPoints (%ld) and gridSize (%ld) differ!", numberOfPoints, nlon*nlat);
-
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size  = (int)numberOfPoints;
-        grid->xsize = (int)nlon;
-        grid->ysize = (int)nlat;
-        grid->xinc  = 0;
-        grid->yinc  = 0;
-        grid->xdef  = 0;
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->xfirst);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->xlast);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->yfirst);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->ylast);
-        if ( nlon > 1 )
-          FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->xinc);
-        if ( gridtype == GRID_LONLAT && nlat > 1 )
-          FAIL_ON_GRIB_ERROR(grib_get_double, gh, "jDirectionIncrementInDegrees", &grid->yinc);
-
-        if ( grid->xinc < -999 || grid->xinc > 999 ) grid->xinc = 0;
-        if ( grid->yinc < -999 || grid->yinc > 999 ) grid->yinc = 0;
-
-        if ( grid->yinc > 0 && grid->yfirst > grid->ylast ) grid->yinc = -grid->yinc;
-
-        /* if ( IS_NOT_EQUAL(grid->xfirst, 0) || IS_NOT_EQUAL(grid->xlast, 0) ) */
-          {
-            if ( grid->xsize > 1 )
-              {
-                if ( (grid->xfirst >= grid->xlast) && (grid->xfirst >= 180) ) grid->xfirst -= 360;
+char *fileInqName(int fileID)
+{
+  char *name = NULL;
+  bfile_t *fileptr = file_to_pointer(fileID);
+  if ( fileptr ) name = fileptr->name;
 
-                if ( editionNumber <= 1 )
-                  {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
-                      {
-                        double xinc = 360. / grid->xsize;
+  return name;
+}
 
-                        if ( fabs(grid->xinc-xinc) > 0.0 )
-                          {
-                            grid->xinc = xinc;
-                            if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
-                          }
-                      }
-                  }
-              }
-            grid->xdef = 2;
-          }
-        grid->ydef = 0;
-        /* if ( IS_NOT_EQUAL(grid->yfirst, 0) || IS_NOT_EQUAL(grid->ylast, 0) ) */
-          {
-            if ( grid->ysize > 1 )
-              {
-                if ( editionNumber <= 1 )
-                  {
-                  }
-              }
-            grid->ydef = 2;
-          }
-        break;
-      }
-    case GRID_GAUSSIAN_REDUCED:
-      {
-        long lpar;
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
-        /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-        grid->np = (int)lpar;
-
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
-        /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-        int nlat = (int)lpar;
-
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size   = (int)numberOfPoints;
-
-        grid->nrowlon = nlat;
-        grid->rowlon = (int *) Malloc((size_t)nlat * sizeof (int));
-        long *pl     = (long *) Malloc((size_t)nlat * sizeof (long));
-        size_t dummy = (size_t)nlat;
-        FAIL_ON_GRIB_ERROR(grib_get_long_array, gh, "pl", pl, &dummy);
-        /* FIXME: assert(pl[i] >= INT_MIN && pl[i] <= INT_MIN) */
-        for ( int i = 0; i < nlat; ++i ) grid->rowlon[i] = (int)pl[i];
-        Free(pl);
-
-        grid->ysize  = nlat;
-        grid->xinc   = 0;
-        grid->yinc   = 0;
-        grid->xdef   = 0;
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->xfirst);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->xlast);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->yfirst);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->ylast);
-
-        // FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->xinc);
-        // if ( IS_EQUAL(grid->xinc, GRIB_MISSING_DOUBLE) ) grid->xinc = 0;
-
-        /* if ( IS_NOT_EQUAL(grid->xfirst, 0) || IS_NOT_EQUAL(grid->xlast, 0) ) */
-          {
-            if ( grid->xsize > 1 )
-              {
-                if ( (grid->xfirst > grid->xlast) && (grid->xfirst >= 180) ) grid->xfirst -= 360;
 
-                if ( editionNumber <= 1 )
-                  {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
-                      {
-                        double xinc = 360. / grid->xsize;
+int fileInqMode(int fileID)
+{
+  int mode = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
+  if ( fileptr ) mode = fileptr->mode;
 
-                        if ( fabs(grid->xinc-xinc) > 0.0 )
-                          {
-                            grid->xinc = xinc;
-                            if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
-                          }
-                      }
-                  }
-              }
-            grid->xdef = 2;
-          }
-        grid->ydef  = 0;
-        /* if ( IS_NOT_EQUAL(grid->yfirst, 0) || IS_NOT_EQUAL(grid->ylast, 0) ) */
-          {
-            if ( grid->ysize > 1 )
-              {
-                if ( editionNumber <= 1 )
-                  {
-                  }
-              }
-            grid->ydef = 2;
-          }
-        break;
-      }
-    case GRID_LCC:
-      {
-        int nlon, nlat;
-        long lpar;
+  return mode;
+}
 
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nx", &lpar);
-        nlon = (int)lpar;
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ny", &lpar);
-        nlat = (int)lpar;
+static
+long file_getenv(const char *envName)
+{
+  long envValue = -1;
+  long fact = 1;
 
-        if ( numberOfPoints != nlon*nlat )
-          Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
+  char *envString = getenv(envName);
 
-        grid->size  = (int)numberOfPoints;
-        grid->xsize = nlon;
-        grid->ysize = nlat;
+  if ( envString )
+    {
+      for ( int loop = 0; loop < (int) strlen(envString); loop++ )
+	{
+	  if ( ! isdigit((int) envString[loop]) )
+	    {
+	      switch ( tolower((int) envString[loop]) )
+		{
+		case 'k':  fact =       1024;  break;
+		case 'm':  fact =    1048576;  break;
+		case 'g':  fact = 1073741824;  break;
+		default:
+		  fact = 0;
+		  Message("Invalid number string in %s: %s", envName, envString);
+		  Warning("%s must comprise only digits [0-9].",envName);
+		}
+	      break;
+	    }
+	}
 
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DxInMetres", &grid->lcc_xinc);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DyInMetres", &grid->lcc_yinc);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->lcc_originLon);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees", &grid->lcc_originLat);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "LoVInDegrees", &grid->lcc_lonParY);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "Latin1InDegrees", &grid->lcc_lat1);
-        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "Latin2InDegrees", &grid->lcc_lat2);
+      if ( fact ) envValue = fact*atol(envString);
 
-        if ( editionNumber <= 1 )
-          {
-            FAIL_ON_GRIB_ERROR(grib_get_long, gh, "projectionCenterFlag", &lpar);
-            grid->lcc_projflag  = (int) lpar;
-            FAIL_ON_GRIB_ERROR(grib_get_long, gh, "scanningMode", &lpar);
-            grid->lcc_scanflag  = (int) lpar;
-          }
+      if ( FILE_Debug ) Message("Set %s to %ld", envName, envValue);
+    }
 
-        grid->xdef   = 0;
-        grid->ydef   = 0;
+  return envValue;
+}
 
-        break;
-      }
-    case GRID_SPECTRAL:
-      {
-        size_t len = 256;
-        char typeOfPacking[256];
-        FAIL_ON_GRIB_ERROR(grib_get_string, gh, "packingType", typeOfPacking, &len);
-        grid->lcomplex = 0;
-        if ( strncmp(typeOfPacking, "spectral_complex", len) == 0 ) grid->lcomplex = 1;
-
-        /* FIXME: assert(datasize >= INT_MIN && datasize <= INT_MAX) */
-        grid->size  = (int)datasize;
-        long lpar;
-        FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
-        /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-        grid->trunc = (int)lpar;
+static
+void file_initialize(void)
+{
+  long value;
 
-        break;
-      }
-    case GRID_GME:
-      {
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size  = (int)numberOfPoints;
-        long lpar;
-        /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-        if ( grib_get_long(gh, "nd", &lpar) == 0 ) grid->nd  = (int)lpar;
-        /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-        if ( grib_get_long(gh, "Ni", &lpar) == 0 ) grid->ni  = (int)lpar;
-        /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-        if ( grib_get_long(gh, "n2", &lpar) == 0 ) grid->ni2 = (int)lpar;
-        /* FIXME: assert(lpar >= INT_MIN && lpar <= INT_MAX) */
-        if ( grib_get_long(gh, "n3", &lpar) == 0 ) grid->ni3 = (int)lpar;
+#if  defined  (HAVE_LIBPTHREAD)
+  /* initialize global API mutex lock */
+  pthread_mutex_init(&_file_mutex, NULL);
+#endif
 
-        break;
-      }
-    case GRID_UNSTRUCTURED:
-      {
-        unsigned char uuid[CDI_UUID_SIZE];
-        /*
-        char reference_link[8192];
-        size_t len = sizeof(reference_link);
-        reference_link[0] = 0;
-        */
+  value = file_getenv("FILE_DEBUG");
+  if ( value >= 0 ) FILE_Debug = (int) value;
 
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-            grid->size  = (int)numberOfPoints;
-        long lpar;
-        if ( grib_get_long(gh, "numberOfGridUsed", &lpar) == 0 )
-          {
-            /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-            grid->number   = (int)lpar;
-            /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-            if ( grib_get_long(gh, "numberOfGridInReference", &lpar) == 0 )
-              grid->position = (int)lpar;
-            /*
-            if ( grib_get_string(gh, "gridDescriptionFile", reference_link, &len) == 0 )
-              {
-                if ( strncmp(reference_link, "file://", 7) == 0 )
-                  grid->reference = strdupx(reference_link);
-              }
-            */
-            size_t len = (size_t)CDI_UUID_SIZE;
-            if ( grib_get_bytes(gh, "uuidOfHGrid", uuid, &len) == 0)
-              {
-                memcpy(grid->uuid, uuid, CDI_UUID_SIZE);
-              }
-          }
-        break;
-      }
-    case GRID_GENERIC:
-      {
-        int nlon = 0, nlat = 0;
-        long lpar;
-        /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-        if ( grib_get_long(gh, "Ni", &lpar) == 0 ) nlon = (int)lpar;
-        /* FIXME: assert(lpar <= INT_MAX && lpar >= INT_MIN) */
-        if ( grib_get_long(gh, "Nj", &lpar) == 0 ) nlat = (int)lpar;
+  value = file_getenv("FILE_MAX");
+  if ( value >= 0 ) _file_max = (int) value;
 
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size  = (int)numberOfPoints;
+  if ( FILE_Debug )
+    Message("FILE_MAX = %d", _file_max);
 
-        if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
-          {
-            grid->xsize = nlon;
-            grid->ysize = nlat;
-          }
-        else
-          {
-            grid->xsize = 0;
-            grid->ysize = 0;
-          }
+  FileInfo = file_getenv("FILE_INFO") > 0;
 
-        break;
-      }
-    default:
-      {
-        Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-        break;
-      }
+  value  = file_getenv("FILE_BUFSIZE");
+  if ( value >= 0 ) FileBufferSizeEnv = value;
+  else
+    {
+      value  = file_getenv("GRIB_API_IO_BUFFER_SIZE");
+      if ( value >= 0 ) FileBufferSizeEnv = value;
     }
 
-  grid->isRotated = FALSE;
-  if ( gribapiGetIsRotated(gh) )
+  value = file_getenv("FILE_TYPE_READ");
+  if ( value > 0 )
     {
-      grid->isRotated = TRUE;
-      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfSouthernPoleInDegrees",  &grid->ypole);
-      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfSouthernPoleInDegrees", &grid->xpole);
-      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "angleOfRotation", &grid->angle);
-      /* change from south to north pole */
-      if ( fabs(grid->ypole) > 0 ) grid->ypole = -grid->ypole;
-      grid->xpole =  grid->xpole - 180;
-      if ( fabs(grid->angle) > 0 ) grid->angle = -grid->angle;
+      switch (value)
+	{
+	case FILE_TYPE_OPEN:
+	case FILE_TYPE_FOPEN:
+	  FileTypeRead = (short)value;
+	  break;
+	default:
+	  Warning("File type %d not implemented!", value);
+	}
     }
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  grid->type  = gridtype;
-}
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef CDI_UUID_H
-#define CDI_UUID_H
+  value = file_getenv("FILE_TYPE_WRITE");
+  if ( value > 0 )
+    {
+      switch (value)
+	{
+	case FILE_TYPE_OPEN:
+	case FILE_TYPE_FOPEN:
+	  FileTypeWrite = (short)value;
+	  break;
+	default:
+	  Warning("File type %d not implemented!", value);
+	}
+    }
 
-#if defined (HAVE_CONFIG_H)
+#if defined (O_NONBLOCK)
+  FileFlagWrite = O_NONBLOCK;
 #endif
-
-
-
-#ifdef __cplusplus
-extern "C" {
+  char *envString = getenv("FILE_FLAG_WRITE");
+  if ( envString )
+    {
+#if defined (O_NONBLOCK)
+      if ( strcmp(envString, "NONBLOCK") == 0 ) FileFlagWrite = O_NONBLOCK;
 #endif
+    }
 
-static inline int cdiUUIDIsNull(const unsigned char uuid[])
-{
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
-}
-
-void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
-
-void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
-int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
-
-#if defined (__cplusplus)
-}
+  value = file_getenv("FILE_BUFTYPE");
+#if ! defined (HAVE_MMAP)
+  if ( value == FILE_BUFTYPE_MMAP )
+    {
+      Warning("MMAP not available!");
+      value = 0;
+    }
 #endif
+  if ( value > 0 )
+    {
+      switch (value)
+	{
+	case FILE_BUFTYPE_STD:
+	case FILE_BUFTYPE_MMAP:
+	  FileBufferTypeEnv = (short)value;
+	  break;
+	default:
+	  Warning("File buffer type %d not implemented!", value);
+	}
+    }
 
-#endif
+  file_list_new();
+  atexit(file_list_delete);
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef RESOURCE_UNPACK_H
-#define RESOURCE_UNPACK_H
+  FILE_LOCK();
 
-#ifdef HAVE_CONFIG_H
-#endif
+  file_init_pointer();
 
-enum
-{ GRID      = 1,
-  ZAXIS     = 2,
-  TAXIS     = 3,
-  INSTITUTE = 4,
-  MODEL     = 5,
-  STREAM    = 6,
-  VLIST     = 7,
-  RESH_DELETE,
-  START     = 55555555,
-  END       = 99999999
-};
+  FILE_UNLOCK();
 
-int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
-                        void *context);
+  if ( FILE_Debug ) atexit(file_table_print);
 
-#endif
+  _file_init = true;
+}
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _VLIST_H
-#define _VLIST_H
+static
+void file_set_buffer(bfile_t *fileptr)
+{
+  size_t buffersize = 0;
 
-#ifdef HAVE_CONFIG_H
-#endif
+  if ( fileptr->mode == 'r' )
+    {
+      if ( FileBufferTypeEnv )
+	fileptr->bufferType = FileBufferTypeEnv;
+      else if ( fileptr->bufferType == 0 )
+	fileptr->bufferType = FILE_BUFTYPE_STD;
 
-#ifndef  _ERROR_H
-#endif
+      if ( FileBufferSizeEnv >= 0 )
+	buffersize = (size_t) FileBufferSizeEnv;
+      else if ( fileptr->bufferSize > 0 )
+	buffersize = fileptr->bufferSize;
+      else
+	{
+	  buffersize = fileptr->blockSize * 4;
+	  if ( buffersize < FileBufferSizeMin ) buffersize = FileBufferSizeMin;
+	}
 
-#include <stddef.h>  /* size_t */
+      if ( (size_t) fileptr->size < buffersize )
+	buffersize = (size_t) fileptr->size;
 
-#ifndef _CDI_LIMITS_H
-#endif
+      if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
+	{
+	  size_t blocksize = (size_t) pagesize();
+	  size_t minblocksize = 4 * blocksize;
+	  buffersize = buffersize - buffersize % minblocksize;
 
-#define VALIDMISS 1.e+303
+	  if ( buffersize < (size_t) fileptr->size && buffersize < minblocksize )
+	    buffersize = minblocksize;
+	}
 
-/*
- * CDI attribute
- */
-typedef struct {
-  size_t    xsz;	  /* amount of space at xvalue                      */
-  size_t    namesz;       /* size of name                                   */
-  char     *name;         /* attribute name                                 */
-  int       indtype;	  /* internal data type of xvalue (INT, FLT or TXT) */
-  int       exdtype;      /* external data type                             */
-                          /* indtype    exdtype                             */
-                          /* TXT        TXT                                 */
-                          /* INT        INT16, INT32                        */
-                          /* FLT        FLT32, FLT64                        */
-  size_t    nelems;    	  /* number of elements                             */
-  void     *xvalue;       /* the actual data                                */
-} cdi_att_t;
+      if ( buffersize == 0 ) buffersize = 1;
+    }
+  else
+    {
+      fileptr->bufferType = FILE_BUFTYPE_STD;
 
+      if ( FileBufferSizeEnv >= 0 )
+	buffersize = (size_t) FileBufferSizeEnv;
+      else if ( fileptr->bufferSize > 0 )
+	buffersize = fileptr->bufferSize;
+      else
+	{
+	  buffersize = fileptr->blockSize * 4;
+	  if ( buffersize < FileBufferSizeMin ) buffersize = FileBufferSizeMin;
+	}
+    }
 
-typedef struct {
-  size_t     nalloc;		/* number allocated >= nelems */
-  size_t     nelems;		/* length of the array */
-  cdi_att_t  value[MAX_ATTRIBUTES];
-} cdi_atts_t;
+  if ( fileptr->bufferType == FILE_BUFTYPE_STD || fileptr->type == FILE_TYPE_FOPEN )
+    {
+      if ( buffersize > 0 )
+        {
+          fileptr->buffer = (char *) Malloc(buffersize);
+          if ( fileptr->buffer == NULL )
+            SysError("Allocation of file buffer failed!");
+        }
+    }
 
+  if ( fileptr->type == FILE_TYPE_FOPEN )
+    if ( setvbuf(fileptr->fp, fileptr->buffer, fileptr->buffer ? _IOFBF : _IONBF, buffersize) )
+      SysError("setvbuf failed!");
 
-typedef struct
-{
-  int      flag;
-  int      index;
-  int      mlevelID;
-  int      flevelID;
+  fileptr->bufferSize = buffersize;
 }
-levinfo_t;
 
-#define DEFAULT_LEVINFO(levID) \
-  (levinfo_t){ 0, -1, levID, levID}
-/*
-#define DEFAULT_LEVINFO(levID) \
-  (levinfo_t){ .flag = 0, .index = -1, .flevelID = levID, .mlevelID = levID}
-*/
-typedef struct
+static
+int file_fill_buffer(bfile_t *fileptr)
 {
-  int ens_index;
-  int ens_count;
-  int forecast_init_type;
-}
-ensinfo_t;
-
-
+  ssize_t nread;
+  long offset = 0;
 
-typedef struct
-{
-  int         flag;
-  int         isUsed;
-  int         mvarID;
-  int         fvarID;
-  int         param;
-  int         gridID;
-  int         zaxisID;
-  int         tsteptype; /* TSTEP_* */
-  int         datatype;  /* DATATYPE_PACKX for GRIB data, else DATATYPE_FLT32 or DATATYPE_FLT64 */
-  int         instID;
-  int         modelID;
-  int         tableID;
-  int         timave;
-  int         timaccu;
-  int         typeOfGeneratingProcess;
-  int         productDefinitionTemplate;
-  int         chunktype;
-  int         xyz;
-  int         missvalused; /* TRUE if missval is defined */
-  int         lvalidrange;
-  char       *name;
-  char       *longname;
-  char       *stdname;
-  char       *units;
-  char       *extra;
-  double      missval;
-  double      scalefactor;
-  double      addoffset;
-  double      validrange[2];
-  levinfo_t  *levinfo;
-  int         comptype;     // compression type
-  int         complevel;    // compression level
-  ensinfo_t  *ensdata;      /* Ensemble information */
-  cdi_atts_t  atts;
-  int         iorank;
+  if ( FILE_Debug )
+    Message("file ptr = %p  Cnt = %ld", fileptr, fileptr->bufferCnt);
 
-  int         subtypeID;   /* subtype ID for tile-related meta-data, currently for GRIB-API only. */
+  if ( (fileptr->flag & FILE_EOF) != 0 ) return EOF;
 
-  int                 opt_grib_nentries;       /* current no. key-value pairs            */
-  int                 opt_grib_kvpair_size;    /* current allocated size                 */
-  opt_key_val_pair_t *opt_grib_kvpair;         /* (optional) list of keyword/value pairs */
-}
-var_t;
+  if ( fileptr->buffer == NULL ) file_set_buffer(fileptr);
 
+  if ( fileptr->bufferSize == 0 ) return EOF;
 
-typedef struct
-{
-  //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
-  bool    immutable;
-  //set if this vlist has been created by CDI itself, and must not be destroyed by the user, consequently
-  bool    internal;
-  int         self;
-  int         nvars;        /* number of variables                */
-  int         ngrids;
-  int         nzaxis;
-  int         nsubtypes;    /* no. of variable subtypes (e.g. sets of tiles) */
-  long        ntsteps;
-  int         taxisID;
-  int         tableID;
-  int         instID;
-  int         modelID;
-  int         varsAllocated;
-  int         gridIDs[MAX_GRIDS_PS];
-  int         zaxisIDs[MAX_ZAXES_PS];
-  int         subtypeIDs[MAX_SUBTYPES_PS];
-  var_t      *vars;
-  cdi_atts_t  atts;
-}
-vlist_t;
+  int fd = fileptr->fd;
 
+#if defined (HAVE_MMAP)
+  if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
+    {
+      if ( fileptr->bufferPos >= fileptr->size )
+	{
+	  nread = 0;
+	}
+      else
+	{
+          xassert(fileptr->bufferSize <= SSIZE_MAX);
+	  nread = (ssize_t)fileptr->bufferSize;
+	  if ( (nread + fileptr->bufferPos) > fileptr->size )
+	    nread = fileptr->size - fileptr->bufferPos;
 
-vlist_t *vlist_to_pointer(int vlistID);
-void cdiVlistMakeInternal(int vlistID);
-void cdiVlistMakeImmutable(int vlistID);
-void vlistCheckVarID(const char *caller, int vlistID, int varID);
-const char *vlistInqVarStdnamePtr(int vlistID, int varID);
-void     vlistDestroyVarName(int vlistID, int varID);
-void     vlistDestroyVarLongname(int vlistID, int varID);
-void     vlistDestroyVarStdname(int vlistID, int varID);
-void     vlistDestroyVarUnits(int vlistID, int varID);
-void     cdiVlistDestroy_(int vlistID);
-void     vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
-int      vlistInqVarMissvalUsed(int vlistID, int varID);
-int      vlistHasTime(int vlistID);
+	  if ( fileptr->buffer )
+	    {
+              int ret = munmap(fileptr->buffer, fileptr->mappedSize);
+	      if ( ret == -1 ) SysError("munmap error for read %s", fileptr->name);
+	      fileptr->buffer = NULL;
+	    }
 
-int      vlistDelAtts(int vlistID, int varID);
-int      vlistCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2);
+	  fileptr->mappedSize = (size_t)nread;
 
-void     vlistUnpack(char * buffer, int bufferSize, int * pos,
-                     int originNamespace, void *context, int force_id);
+	  fileptr->buffer = (char*) mmap(NULL, (size_t) nread, PROT_READ, MAP_PRIVATE, fd, fileptr->bufferPos);
 
-/*      vlistDefVarValidrange: Define the valid range of a Variable */
-void    vlistDefVarValidrange(int vlistID, int varID, const double *validrange);
+	  if ( fileptr->buffer == MAP_FAILED ) SysError("mmap error for read %s", fileptr->name);
 
-/*      vlistInqVarValidrange: Get the valid range of a Variable */
-int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
+	  offset = fileptr->position - fileptr->bufferPos;
+	}
+    }
+  else
+#endif
+    {
+      off_t retseek = lseek(fileptr->fd, fileptr->bufferPos, SEEK_SET);
+      if ( retseek == (off_t)-1 )
+	SysError("lseek error at pos %ld file %s", (long) fileptr->bufferPos, fileptr->name);
 
-void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
+      nread = read(fd, fileptr->buffer, fileptr->bufferSize);
+      if ( nread > 0 ) offset = fileptr->position - fileptr->bufferPos;
+    }
 
-int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
+  if ( nread <= 0 )
+    {
+      fileptr->flag |= (nread == 0) ? FILE_EOF : FILE_ERROR;
+      fileptr->bufferCnt = 0;
+      return EOF;
+    }
 
-void resize_opt_grib_entries(var_t *var, int nentries);
+  fileptr->bufferPtr = fileptr->buffer;
+  fileptr->bufferCnt = (size_t)nread;
 
+  fileptr->bufferStart = fileptr->bufferPos;
+  fileptr->bufferPos  += nread;
+  fileptr->bufferEnd   = fileptr->bufferPos - 1;
 
+  if ( FILE_Debug )
+    {
+      Message("fileID = %d  Val     = %d",  fileptr->self, (int) fileptr->buffer[0]);
+      Message("fileID = %d  Start   = %ld", fileptr->self, fileptr->bufferStart);
+      Message("fileID = %d  End     = %ld", fileptr->self, fileptr->bufferEnd);
+      Message("fileID = %d  nread   = %ld", fileptr->self, nread);
+      Message("fileID = %d  offset  = %ld", fileptr->self, offset);
+      Message("fileID = %d  Pos     = %ld", fileptr->self, fileptr->bufferPos);
+      Message("fileID = %d  postion = %ld", fileptr->self, fileptr->position);
+    }
 
-static inline void
-vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
-{
-  int index, ngrids = vlistptr->ngrids;
-  for ( index = 0; index < ngrids; index++ )
-    if (vlistptr->gridIDs[index] == gridID ) break;
-  if ( index == ngrids )
+  if ( offset > 0 )
     {
-      if (ngrids >= MAX_GRIDS_PS)
-        Error("Internal limit exceeded: more than %d grids.", MAX_GRIDS_PS);
-      ++(vlistptr->ngrids);
-      vlistptr->gridIDs[ngrids] = gridID;
+      if ( offset > nread )
+	Error("Internal problem with buffer handling. nread = %d offset = %d", nread, offset);
+
+      fileptr->bufferPtr += offset;
+      fileptr->bufferCnt -= (size_t)offset;
     }
+
+  fileptr->bufferNumFill++;
+
+  return (unsigned char) *fileptr->bufferPtr;
 }
 
-static inline void
-vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
+static
+void file_copy_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
 {
-  int index, nzaxis = vlistptr->nzaxis;
-  for ( index = 0; index < nzaxis; index++ )
-    if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
+  if ( FILE_Debug )
+    Message("size = %ld  Cnt = %ld", size, fileptr->bufferCnt);
 
-  if ( index == nzaxis )
+  if ( fileptr->bufferCnt < size )
+    Error("Buffer too small. bufferCnt = %d", fileptr->bufferCnt);
+
+  if ( size == 1 )
     {
-      if ( nzaxis >= MAX_ZAXES_PS )
-	Error("Internal limit exceeded: more than %d zaxis.", MAX_ZAXES_PS);
-      vlistptr->zaxisIDs[nzaxis] = zaxisID;
-      vlistptr->nzaxis++;
+      ((char *)ptr)[0] = fileptr->bufferPtr[0];
+
+      fileptr->bufferPtr++;
+      fileptr->bufferCnt--;
+    }
+  else
+    {
+      memcpy(ptr, fileptr->bufferPtr, size);
+
+      fileptr->bufferPtr += size;
+      fileptr->bufferCnt -= size;
     }
 }
 
-static inline void
-vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
+static
+size_t file_read_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
 {
-  if ( subtypeID == CDI_UNDEFID ) return;
+  size_t nread;
+  size_t offset = 0;
 
-  int index, nsubs = vlistptr->nsubtypes;
-  for ( index = 0; index < nsubs; index++ )
-    if (vlistptr->subtypeIDs[index] == subtypeID ) break;
-  if ( index == nsubs )
+  if ( FILE_Debug )
+    Message("size = %ld  Cnt = %ld", size, (long) fileptr->bufferCnt);
+
+  if ( ((long)fileptr->bufferCnt) < 0L )
+    Error("Internal problem. bufferCnt = %ld", (long) fileptr->bufferCnt);
+
+  size_t rsize = size;
+
+  while ( fileptr->bufferCnt < rsize )
     {
-      if (nsubs >= MAX_SUBTYPES_PS)
-        Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
-      ++(vlistptr->nsubtypes);
-      vlistptr->subtypeIDs[nsubs] = subtypeID;
+      nread = fileptr->bufferCnt;
+      /*
+      fprintf(stderr, "rsize = %d nread = %d\n", (int) rsize, (int) nread);
+      */
+      if ( nread > (size_t) 0 )
+	file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
+      offset += nread;
+      if ( nread < rsize )
+	rsize -= nread;
+      else
+	rsize = 0;
+
+      if ( file_fill_buffer(fileptr) == EOF ) break;
     }
-}
 
+  nread = size - offset;
 
+  if ( fileptr->bufferCnt < nread ) nread = fileptr->bufferCnt;
 
-#if  defined  (HAVE_LIBGRIB_API)
-extern int   cdiNAdditionalGRIBKeys;
-extern char* cdiAdditionalGRIBKeys[];
-#endif
+  if ( nread > (unsigned) 0 )
+    file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
 
-extern
-#ifndef __cplusplus
-const
-#endif
-resOps vlistOps;
+  return (nread+offset);
+}
+
+
+void fileSetBufferSize(int fileID, long buffersize)
+{
+  bfile_t *fileptr = file_to_pointer(fileID);
+  xassert(buffersize >= 0);
+  if ( fileptr ) fileptr->bufferSize = (size_t)buffersize;
+}
 
-#endif  /* _VLIST_H */
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
+ *   Open a file. Returns file ID, or -1 on error
  */
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <assert.h>
-#include <string.h>
-#include <float.h>  /* FLT_EPSILON */
-#include <limits.h> /* INT_MAX     */
+int fileOpen(const char *filename, const char *mode)
+{
+  int (*myFileOpen)(const char *filename, const char *mode)
+    = (int (*)(const char *, const char *))
+    namespaceSwitchGet(NSSWITCH_FILE_OPEN).func;
+  return myFileOpen(filename, mode);
+}
 
+int fileOpen_serial(const char *filename, const char *mode)
+{
+  FILE *fp = NULL;    /* file pointer    (used for write) */
+  int fd = -1;        /* file descriptor (used for read)  */
+  int fileID = FILE_UNDEFID;
+  struct stat filestat;
+  bfile_t *fileptr = NULL;
 
-#undef  UNDEFID
-#define UNDEFID -1
+  FILE_INIT();
 
-/* the value in the second pair of brackets must match the length of
- * the longest string (including terminating NUL) */
-static const char Grids[][17] = {
-  /*  0 */  "undefined",
-  /*  1 */  "generic",
-  /*  2 */  "gaussian",
-  /*  3 */  "gaussian reduced",
-  /*  4 */  "lonlat",
-  /*  5 */  "spectral",
-  /*  6 */  "fourier",
-  /*  7 */  "gme",
-  /*  8 */  "trajectory",
-  /*  9 */  "unstructured",
-  /* 10 */  "curvilinear",
-  /* 11 */  "lcc",
-  /* 12 */  "lcc2",
-  /* 13 */  "laea",
-  /* 14 */  "sinusoidal",
-  /* 15 */  "projection",
-};
+  int fmode = tolower((int) mode[0]);
 
-/* must match table below */
-enum xystdname_idx {
-  grid_xystdname_grid_latlon,
-  grid_xystdname_latlon,
-  grid_xystdname_projection,
-};
-static const char xystdname_tab[][2][24] = {
-  [grid_xystdname_grid_latlon] = { "grid_longitude",
-                                   "grid_latitude" },
-  [grid_xystdname_latlon] = { "longitude",
-                              "latitude" },
-  [grid_xystdname_projection] = { "projection_x_coordinate",
-                                  "projection_y_coordinate" },
+  switch ( fmode )
+    {
+    case 'r':
+      if ( FileTypeRead == FILE_TYPE_FOPEN )
+	fp = fopen(filename, "rb");
+      else
+	fd =  open(filename, O_RDONLY | O_BINARY);
+      break;
+    case 'x':  fp = fopen(filename, "rb");      break;
+    case 'w':
+      if ( FileTypeWrite == FILE_TYPE_FOPEN )
+        fp = fopen(filename, "wb");
+      else
+	fd =  open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY | FileFlagWrite, 0666);
+      break;
+    case 'a':  fp = fopen(filename, "ab");      break;
+    default:   Error("Mode %c unexpected!", fmode);
+    }
 
-};
+  if ( FILE_Debug )
+    if ( fp == NULL && fd == -1 )
+      Message("Open failed on %s mode %c errno %d", filename, fmode, errno);
 
+  if ( fp )
+    {
+      if ( stat(filename, &filestat) != 0 ) return fileID;
 
+      fileptr = file_new_entry();
+      if ( fileptr )
+	{
+	  fileID = fileptr->self;
+	  fileptr->fp = fp;
+	}
+    }
+  else if ( fd >= 0 )
+    {
+      if ( fstat(fd, &filestat) != 0 ) return fileID;
 
-static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
-static void   gridDestroyP    ( void * gridptr );
-static void   gridPrintP      ( void * gridptr, FILE * fp );
-static int    gridGetPackSize ( void * gridptr, void *context);
-static void   gridPack        ( void * gridptr, void * buff, int size,
-				int *position, void *context);
-static int    gridTxCode      ( void );
+      fileptr = file_new_entry();
+      if ( fileptr )
+	{
+	  fileID = fileptr->self;
+	  fileptr->fd = fd;
+	}
+    }
 
-static const resOps gridOps = {
-  gridCompareP,
-  gridDestroyP,
-  gridPrintP,
-  gridGetPackSize,
-  gridPack,
-  gridTxCode
-};
+  if ( fileID >= 0 )
+    {
+      fileptr->mode = fmode;
+      fileptr->name = strdupx(filename);
 
-static int  GRID_Debug = 0;   /* If set to 1, debugging */
+#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
+      fileptr->blockSize = (size_t) filestat.st_blksize;
+#else
+      fileptr->blockSize = (size_t) 4096;
+#endif
 
-grid_t *gridID2Ptr(int gridID)
-{
-  return (grid_t *)reshGetVal(gridID, &gridOps);
-}
-#define gridID2Ptr(gridID) (grid_t *)reshGetVal(gridID, &gridOps)
-#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
+      if ( fmode == 'r' )
+        fileptr->type = FileTypeRead;
+      else if ( fmode == 'w' )
+        fileptr->type = FileTypeWrite;
+      else
+	fileptr->type = FILE_TYPE_FOPEN;
 
+      if ( fmode == 'r' ) fileptr->size = filestat.st_size;
 
-void grid_init(grid_t *gridptr)
-{
-  gridptr->self          = CDI_UNDEFID;
-  gridptr->type          = CDI_UNDEFID;
-  gridptr->proj          = CDI_UNDEFID;
-  gridptr->mask          = NULL;
-  gridptr->mask_gme      = NULL;
-  gridptr->xvals         = NULL;
-  gridptr->yvals         = NULL;
-  gridptr->area          = NULL;
-  gridptr->xbounds       = NULL;
-  gridptr->ybounds       = NULL;
-  gridptr->rowlon        = NULL;
-  gridptr->nrowlon       = 0;
-  gridptr->xfirst        = 0.0;
-  gridptr->xlast         = 0.0;
-  gridptr->xinc          = 0.0;
-  gridptr->yfirst        = 0.0;
-  gridptr->ylast         = 0.0;
-  gridptr->yinc          = 0.0;
-  gridptr->lcc_originLon = 0.0;
-  gridptr->lcc_originLat = 0.0;
-  gridptr->lcc_lonParY   = 0.0;
-  gridptr->lcc_lat1      = 0.0;
-  gridptr->lcc_lat2      = 0.0;
-  gridptr->lcc_xinc      = 0.0;
-  gridptr->lcc_yinc      = 0.0;
-  gridptr->lcc_projflag  = 0;
-  gridptr->lcc_scanflag  = 0;
-  gridptr->lcc_defined   = FALSE;
-  gridptr->lcc2_lon_0    = 0.0;
-  gridptr->lcc2_lat_0    = 0.0;
-  gridptr->lcc2_lat_1    = 0.0;
-  gridptr->lcc2_lat_2    = 0.0;
-  gridptr->lcc2_a        = 0.0;
-  gridptr->lcc2_defined  = FALSE;
-  gridptr->laea_lon_0    = 0.0;
-  gridptr->laea_lat_0    = 0.0;
-  gridptr->laea_a        = 0.0;
-  gridptr->laea_defined  = FALSE;
-  gridptr->trunc         = 0;
-  gridptr->nvertex       = 0;
-  gridptr->nd            = 0;
-  gridptr->ni            = 0;
-  gridptr->ni2           = 0;
-  gridptr->ni3           = 0;
-  gridptr->number        = 0;
-  gridptr->position      = 0;
-  gridptr->reference     = NULL;
-  gridptr->prec          = 0;
-  gridptr->size          = 0;
-  gridptr->xsize         = 0;
-  gridptr->ysize         = 0;
-  gridptr->np            = 0;
-  gridptr->xdef          = 0;
-  gridptr->ydef          = 0;
-  gridptr->isCyclic      = CDI_UNDEFID;
-  gridptr->isRotated     = FALSE;
-  gridptr->xpole         = 0.0;
-  gridptr->ypole         = 0.0;
-  gridptr->angle         = 0.0;
-  gridptr->lcomplex      = 0;
-  gridptr->hasdims       = TRUE;
-  gridptr->xdimname[0]   = 0;
-  gridptr->ydimname[0]   = 0;
-  gridptr->vdimname[0]   = 0;
-  gridptr->xname[0]      = 0;
-  gridptr->yname[0]      = 0;
-  gridptr->xlongname[0]  = 0;
-  gridptr->ylongname[0]  = 0;
-  gridptr->xunits[0]     = 0;
-  gridptr->yunits[0]     = 0;
-  gridptr->xstdname      = NULL;
-  gridptr->ystdname      = NULL;
-  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
-  gridptr->name          = NULL;
-  gridptr->vtable        = &cdiGridVtable;
-  gridptr->extraData     = NULL;
-}
+      if ( fileptr->type == FILE_TYPE_FOPEN ) file_set_buffer(fileptr);
 
+      if ( FILE_Debug )
+	Message("File %s opened with ID %d", filename, fileID);
+    }
 
-static void
-grid_free_components(grid_t *gridptr)
-{
-  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
-                   gridptr->xvals, gridptr->yvals,
-                   gridptr->xbounds, gridptr->ybounds,
-                   gridptr->rowlon, gridptr->area,
-                   gridptr->reference, gridptr->name };
-  for (size_t i = 0; i < sizeof (p2free) / sizeof (p2free[0]); ++i)
-    if (p2free[i]) Free(p2free[i]);
+  return fileID;
 }
 
-void grid_free(grid_t *gridptr)
+/*
+ *   Close a file.
+ */
+int fileClose(int fileID)
 {
-  grid_free_components(gridptr);
-  grid_init(gridptr);
+  int (*myFileClose)(int fileID)
+    = (int (*)(int))namespaceSwitchGet(NSSWITCH_FILE_CLOSE).func;
+  return myFileClose(fileID);
 }
 
-static grid_t *
-gridNewEntry(cdiResH resH)
+int fileClose_serial(int fileID)
 {
-  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
-  grid_init(gridptr);
-  if (resH == CDI_UNDEFID)
-    gridptr->self = reshPut(gridptr, &gridOps);
-  else
+  int ret;
+  const char *fbtname[] = {"unknown", "standard", "mmap"};
+  const char *ftname[] = {"unknown", "open", "fopen"};
+  bfile_t *fileptr = file_to_pointer(fileID);
+  double rout = 0;
+
+  if ( fileptr == NULL )
     {
-      gridptr->self = resH;
-      reshReplace(resH, gridptr, &gridOps);
+      file_pointer_info(__func__, fileID);
+      return 1;
     }
-  return gridptr;
-}
 
-static
-void gridInit(void)
-{
-  static int gridInitialized = 0;
+  char *name = fileptr->name;
 
-  if ( gridInitialized ) return;
+  if ( FILE_Debug )
+    Message("fileID = %d  filename = %s", fileID, name);
 
-  gridInitialized = 1;
+  if ( FileInfo )
+    {
+      fprintf(stderr, "____________________________________________\n");
+      fprintf(stderr, " file ID          : %d\n",  fileID);
+      fprintf(stderr, " file name        : %s\n",  fileptr->name);
+      fprintf(stderr, " file type        : %d (%s)\n", fileptr->type, ftname[fileptr->type]);
 
-  const char *env = getenv("GRID_DEBUG");
-  if ( env ) GRID_Debug = atoi(env);
-}
+      if ( fileptr->type == FILE_TYPE_FOPEN )
+	fprintf(stderr, " file pointer     : %p\n",  (void *) fileptr->fp);
+      else
+        {
+          fprintf(stderr, " file descriptor  : %d\n",  fileptr->fd);
+          fprintf(stderr, " file flag        : %d\n", FileFlagWrite);
+        }
+      fprintf(stderr, " file mode        : %c\n",  fileptr->mode);
 
-static void
-grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
-{
-  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
-  gridptrDup->self = CDI_UNDEFID;
-  if (gridptrOrig->reference)
-    gridptrDup->reference = strdupx(gridptrOrig->reference);
-}
+      if ( sizeof(off_t) > sizeof(long) )
+	{
+#if defined (_WIN32)
+	  fprintf(stderr, " file size        : %I64d\n", (long long) fileptr->size);
+	  if ( fileptr->type == FILE_TYPE_OPEN )
+	    fprintf(stderr, " file position    : %I64d\n", (long long) fileptr->position);
+	  fprintf(stderr, " bytes transfered : %I64d\n", (long long) fileptr->byteTrans);
+#else
+	  fprintf(stderr, " file size        : %lld\n", (long long) fileptr->size);
+	  if ( fileptr->type == FILE_TYPE_OPEN )
+	    fprintf(stderr, " file position    : %lld\n", (long long) fileptr->position);
+	  fprintf(stderr, " bytes transfered : %lld\n", (long long) fileptr->byteTrans);
+#endif
+	}
+      else
+	{
+	  fprintf(stderr, " file size        : %ld\n", (long) fileptr->size);
+	  if ( fileptr->type == FILE_TYPE_OPEN )
+	    fprintf(stderr, " file position    : %ld\n", (long) fileptr->position);
+	  fprintf(stderr, " bytes transfered : %ld\n", (long) fileptr->byteTrans);
+	}
 
+      if ( fileptr->time_in_sec > 0 )
+        rout = (double)fileptr->byteTrans / (1024.*1024.*fileptr->time_in_sec);
 
-static grid_t *
-grid_copy_base(grid_t *gridptrOrig)
-{
-  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
-  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
-  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
-  return gridptrDup;
-}
+      fprintf(stderr, " wall time [s]    : %.2f\n", fileptr->time_in_sec);
+      fprintf(stderr, " data rate [MB/s] : %.1f\n", rout);
 
-unsigned cdiGridCount(void)
-{
-  return reshCountType(&gridOps);
-}
+      fprintf(stderr, " file access      : %ld\n", fileptr->access);
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	{
+	  fprintf(stderr, " buffer type      : %d (%s)\n", fileptr->bufferType, fbtname[fileptr->bufferType]);
+	  fprintf(stderr, " num buffer fill  : %ld\n", fileptr->bufferNumFill);
+	}
+      fprintf(stderr, " buffer size      : %lu\n", (unsigned long) fileptr->bufferSize);
+      fprintf(stderr, " block size       : %lu\n", (unsigned long) fileptr->blockSize);
+      fprintf(stderr, " page size        : %d\n",  pagesize());
+      fprintf(stderr, "--------------------------------------------\n");
+    }
 
-static inline
-void gridSetString(char *gridstrname, const char *name, size_t len)
-{
-  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
-  strncpy(gridstrname, name, len);
-  gridstrname[len - 1] = 0;
-}
+  if ( fileptr->type == FILE_TYPE_FOPEN )
+    {
+      ret = fclose(fileptr->fp);
+      if ( ret == EOF )
+	SysError("EOF returned for close of %s!", name);
+    }
+  else
+    {
+#if defined (HAVE_MMAP)
+      if ( fileptr->buffer && fileptr->mappedSize )
+	{
+	  ret = munmap(fileptr->buffer, fileptr->mappedSize);
+	  if ( ret == -1 ) SysError("munmap error for close %s", fileptr->name);
+	  fileptr->buffer = NULL;
+	}
+#endif
+      ret = close(fileptr->fd);
+      if ( ret == -1 )
+	SysError("EOF returned for close of %s!", name);
+    }
 
-static inline
-void gridGetString(char *name, const char *gridstrname, size_t len)
-{
-  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
-  strncpy(name, gridstrname, len);
-  name[len - 1] = 0;
-}
+  if ( fileptr->name )    Free((void*) fileptr->name);
+  if ( fileptr->buffer )  Free((void*) fileptr->buffer);
 
-static inline void
-gridSetName(char *gridstrname, const char *name)
-{
-  strncpy(gridstrname, name, CDI_MAX_NAME);
-  gridstrname[CDI_MAX_NAME - 1] = 0;
+  file_delete_entry(fileptr);
+
+  return 0;
 }
 
-void
-cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+
+int filePtrGetc(void *vfileptr)
 {
-  gridptr->type = gridtype;
-  gridptr->size = size;
+  int ivalue = EOF;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
 
-  switch (gridtype)
+  if ( fileptr )
     {
-    case GRID_CURVILINEAR:
-      gridptr->nvertex = 4;
-      /* Fall through */
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_TRAJECTORY:
-      {
-        if ( gridtype == GRID_TRAJECTORY )
-          {
-            if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "tlon");
-            if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "tlat");
-          }
-        else
-          {
-            if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "lon");
-            if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "lat");
-          }
-        gridSetName(gridptr->xlongname, "longitude");
-        gridSetName(gridptr->ylongname, "latitude");
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	{
+	  int fillret = (fileptr->bufferCnt == 0) ? file_fill_buffer(fileptr) : 0;
+	  if ( fillret >= 0 )
+	    {
+	      ivalue = (unsigned char) *fileptr->bufferPtr++;
+	      fileptr->bufferCnt--;
+	      fileptr->position++;
 
-        /*
-        if ( gridtype == GRID_CURVILINEAR )
-          {
-            gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
-            gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
-            gridDefXunits(gridID, "degrees");
-            gridDefYunits(gridID, "degrees");
-          }
-        else
-        */
-          {
-            gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
-            gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
-            gridSetName(gridptr->xunits, "degrees_east");
-            gridSetName(gridptr->yunits, "degrees_north");
-          }
+	      fileptr->byteTrans++;
+	      fileptr->access++;
+	    }
+	}
+      else
+	{
+	  ivalue = fgetc(fileptr->fp);
+	  if ( ivalue >= 0 )
+	    {
+	      fileptr->byteTrans++;
+	      fileptr->access++;
+	    }
+	  else
+	    fileptr->flag |= FILE_EOF;
+	}
+    }
 
-        break;
-      }
-    case GRID_UNSTRUCTURED:
-      gridptr->xsize = size;
-      /* Fall through */
-    case GRID_GME:
-      {
-        if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "lon");
-        if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "lat");
-        gridptr->xstdname = xystdname_tab[grid_xystdname_latlon][0];
-        gridptr->ystdname = xystdname_tab[grid_xystdname_latlon][1];
-        gridSetName(gridptr->xunits, "degrees_east");
-        gridSetName(gridptr->yunits, "degrees_north");
-        break;
-      }
-    case GRID_GENERIC:
-      {
+  return ivalue;
+}
 
-        /* gridptr->xsize = size; */
-        if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "x");
-        if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "y");
-        /*
-        strcpy(gridptr->xstdname, "grid_longitude");
-        strcpy(gridptr->ystdname, "grid_latitude");
-        gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
-        gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
-        gridDefXunits(gridID, "degrees");
-        gridDefYunits(gridID, "degrees");
-        */
-        break;
-      }
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
-      {
-        if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "x");
-        if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "y");
-        gridptr->xstdname = xystdname_tab[grid_xystdname_projection][0];
-        gridptr->ystdname = xystdname_tab[grid_xystdname_projection][1];
-        gridSetName(gridptr->xunits, "m");
-        gridSetName(gridptr->yunits, "m");
-        break;
-      }
-    }
+
+int fileGetc(int fileID)
+{
+  bfile_t *fileptr = file_to_pointer(fileID);
+  return filePtrGetc((void *)fileptr);
 }
 
 
-// used also in CDO
-void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
+size_t filePtrRead(void *vfileptr, void *restrict ptr, size_t size)
 {
-  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
+  size_t nread = 0;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
+
+  if ( fileptr )
     {
-      if ( xfirst >= xlast )
-        {
-          while ( xfirst >= xlast ) xlast += 360;
-          xinc = (xlast-xfirst)/(xsize);
-        }
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	nread = file_read_from_buffer(fileptr, ptr, size);
       else
-        {
-          xinc = (xlast-xfirst)/(xsize-1);
-        }
+	{
+	  nread = fread(ptr, 1, size, fileptr->fp);
+	  if ( nread != size )
+            fileptr->flag |= (nread == 0) ? FILE_EOF : FILE_ERROR;
+	}
+
+      fileptr->position  += (off_t)nread;
+      fileptr->byteTrans += (off_t)nread;
+      fileptr->access++;
     }
 
-  for ( int i = 0; i < xsize; ++i )
-    xvals[i] = xfirst + i*xinc;
+  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
+
+  return nread;
 }
 
-static
-void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
+
+size_t fileRead(int fileID, void *restrict ptr, size_t size)
 {
-  double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
-  gaussaw(yvals, yw, (size_t)ysize);
-  Free(yw);
-  for (int i = 0; i < ysize; i++ )
-    yvals[i] = asin(yvals[i])/M_PI*180.0;
+  size_t nread = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
 
-  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
+  if ( fileptr )
     {
-      int yhsize = ysize/2;
-      for (int i = 0; i < yhsize; i++ )
-        {
-          double ytmp = yvals[i];
-          yvals[i] = yvals[ysize-i-1];
-          yvals[ysize-i-1] = ytmp;
-        }
+      double t_begin = 0.0;
+
+      if ( FileInfo ) t_begin = file_time();
+
+      if ( fileptr->type == FILE_TYPE_OPEN )
+	nread = file_read_from_buffer(fileptr, ptr, size);
+      else
+	{
+	  nread = fread(ptr, 1, size, fileptr->fp);
+	  if ( nread != size )
+	    {
+	      if ( nread == 0 )
+		fileptr->flag |= FILE_EOF;
+	      else
+		fileptr->flag |= FILE_ERROR;
+	    }
+	}
+
+      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
+
+      fileptr->position  += (off_t)nread;
+      fileptr->byteTrans += (off_t)nread;
+      fileptr->access++;
     }
+
+  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
+
+  return nread;
 }
 
-// used also in CDO
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
+
+size_t fileWrite(int fileID, const void *restrict ptr, size_t size)
 {
-  const double deleps = 0.002;
+  size_t nwrite = 0;
+  bfile_t *fileptr = file_to_pointer(fileID);
 
-  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+  if ( fileptr )
     {
-      if ( ysize > 2 )
-	{
-	  calc_gaussgrid(yvals, ysize, yfirst, ylast);
-
-	  if ( ! (IS_EQUAL(yfirst, 0) && IS_EQUAL(ylast, 0)) )
-	    if ( fabs(yvals[0] - yfirst) > deleps || fabs(yvals[ysize-1] - ylast) > deleps )
-	      {
-		double *restrict ytmp = NULL;
-		int nstart, lfound = 0;
-		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
-		ny -= ny%2;
-		if ( ny > ysize && ny < 4096 )
-		  {
-		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
-		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
-                    {
-                      int i;
-                      for ( i = 0; i < (ny-ysize); i++ )
-                        if ( fabs(ytmp[i] - yfirst) < deleps ) break;
-                      nstart = i;
-                    }
-
-		    lfound = (nstart+ysize-1) < ny
-                      && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
-                    if ( lfound )
-                      {
-                        for (int i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
-                      }
-		  }
+      double t_begin = 0.0;
 
-		if ( !lfound )
-		  {
-		    Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
-		    for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
-		    yvals[0] = yfirst;
-		    yvals[ysize-1] = ylast;
-		  }
+      if ( FileInfo ) t_begin = file_time();
 
-		if ( ytmp ) Free(ytmp);
-	      }
-	}
+      if ( fileptr->type == FILE_TYPE_FOPEN )
+        nwrite = fwrite(ptr, 1, size, fileptr->fp);
       else
         {
-          yvals[0] = yfirst;
-          yvals[ysize-1] = ylast;
-        }
-    }
-  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
-  else
-    {
-      if ( (! (fabs(yinc) > 0)) && ysize > 1 )
-        {
-          if ( IS_EQUAL(yfirst, ylast) && IS_NOT_EQUAL(yfirst, 0) ) ylast *= -1;
-
-          if ( yfirst > ylast )
-            yinc = (yfirst-ylast)/(ysize-1);
-          else if ( yfirst < ylast )
-            yinc = (ylast-yfirst)/(ysize-1);
-          else
+          ssize_t temp = write(fileptr->fd, ptr, size);
+          if (temp == -1)
             {
-              if ( ysize%2 != 0 )
-                {
-                  yinc = 180.0/(ysize-1);
-                  yfirst = -90;
-                }
-              else
-                {
-                  yinc = 180.0/ysize;
-                  yfirst = -90 + yinc/2;
-                }
+              perror("error writing to file");
+              nwrite = 0;
             }
+          else
+            nwrite = (size_t)temp;
         }
 
-      if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;
+      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
 
-      for (int i = 0; i < ysize; i++ )
-        yvals[i] = yfirst + i*yinc;
+      fileptr->position  += (off_t)nwrite;
+      fileptr->byteTrans += (off_t)nwrite;
+      fileptr->access++;
     }
-  /*
-    else
-    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
-  */
+
+  return nwrite;
+}
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _GAUSSGRID_H
+#define _GAUSSGRID_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+bool isGaussGrid(size_t ysize, double yinc, const double *yvals);
+
+#if defined (__cplusplus)
 }
+#endif
 
+#endif  /* _GAUSSGRID_H */
 /*
- at Function  gridCreate
- at Title     Create a horizontal Grid
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
+#endif
 
- at Prototype int gridCreate(int gridtype, int size)
- at Parameter
-    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
-                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
-                     @func{GRID_LONLAT}, @func{GRID_LCC}, @func{GRID_SPECTRAL},
-                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
-    @Item  size      Number of gridpoints.
+#include <math.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
 
- at Description
-The function @func{gridCreate} creates a horizontal Grid.
 
- at Result
- at func{gridCreate} returns an identifier to the Grid.
 
- at Example
-Here is an example using @func{gridCreate} to create a regular lon/lat Grid:
 
- at Source
-   ...
-#define  nlon  12
-#define  nlat   6
-   ...
-double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
-double lats[nlat] = {-75, -45, -15, 15, 45, 75};
-int gridID;
-   ...
-gridID = gridCreate(GRID_LONLAT, nlon*nlat);
-gridDefXsize(gridID, nlon);
-gridDefYsize(gridID, nlat);
-gridDefXvals(gridID, lons);
-gridDefYvals(gridID, lats);
-   ...
- at EndSource
- at EndFunction
-*/
-int gridCreate(int gridtype, int size)
+static
+void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
+            double *pw, double *pdxn, double *pxmod)
 {
-  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
-
-  if ( size < 0 || size > INT_MAX ) Error("Grid size (%d) out of bounds (0 - %d)!", size, INT_MAX);
+  /* 1.0 Newton iteration step */
 
-  gridInit();
+  double zdlx = pdx;
+  double zdlk = 0.0;
+  if ( kodd == 0 ) zdlk = 0.5*pfn[0];
+  double zdlxn  = 0.0;
+  double zdlldn = 0.0;
 
-  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
-  if ( ! gridptr ) Error("No memory");
+  size_t ik = 1;
 
-  int gridID = gridptr->self;
+  if ( kflag == 0 )
+    {
+      for ( size_t jn = 2-kodd; jn <= kn; jn += 2 )
+	{
+	  /* normalised ordinary Legendre polynomial == \overbar{p_n}^0 */
+	  zdlk   = zdlk + pfn[ik]*cos((double)(jn)*zdlx);
+	  /* normalised derivative == d/d\theta(\overbar{p_n}^0) */
+	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
+	  ik++;
+	}
+      /* Newton method */
+      double zdlmod = -(zdlk/zdlldn);
+      zdlxn = zdlx + zdlmod;
+      *pdxn = zdlxn;
+      *pxmod = zdlmod;
+    }
 
-  if ( CDI_Debug ) Message("gridID: %d", gridID);
+  /* 2.0 Compute weights */
 
-  cdiGridTypeInit(gridptr, gridtype, size);
+  if ( kflag == 1 )
+    {
+      for ( size_t jn = 2-kodd; jn <= kn; jn += 2 )
+	{
+	  /* normalised derivative */
+	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
+	  ik++;
+	}
+      *pw = (double)(2*kn+1)/(zdlldn*zdlldn);
+    }
 
-  return gridID;
+  return;
 }
 
 static
-void gridDestroyKernel( grid_t * gridptr )
+void gawl(double *pfn, double *pl, double *pw, size_t kn)
 {
-  int id;
+  double pmod = 0;
+  double zw = 0;
+  double zdlxn = 0;
 
-  xassert ( gridptr );
+  /* 1.0 Initizialization */
 
-  id = gridptr->self;
+  int iflag  =  0;
+  int itemax = 20;
 
-  grid_free_components(gridptr);
-  Free( gridptr );
+  size_t iodd   = (kn % 2);
 
-  reshRemove ( id, &gridOps );
-}
+  double zdlx   =  *pl;
 
-/*
- at Function  gridDestroy
- at Title     Destroy a horizontal Grid
+  /* 2.0 Newton iteration */
 
- at Prototype void gridDestroy(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+  for ( int jter = 1; jter <= itemax+1; jter++ )
+    {
+      cpledn(kn, iodd, pfn, zdlx, iflag, &zw, &zdlxn, &pmod);
+      zdlx = zdlxn;
+      if (iflag == 1) break;
+      if (fabs(pmod) <= DBL_EPSILON*1000.0) iflag = 1;
+    }
 
- at EndFunction
-*/
-void gridDestroy(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->destroy(gridptr);
-}
+  *pl = zdlxn;
+  *pw = zw;
 
-void gridDestroyP ( void * gridptr )
-{
-  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
+  return;
 }
 
-
-const char *gridNamePtr(int gridtype)
+static
+void gauaw(size_t kn, double *restrict pl, double *restrict pw)
 {
-  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
+  /*
+   * 1.0 Initialize Fourier coefficients for ordinary Legendre polynomials
+   *
+   * Belousov, Swarztrauber, and ECHAM use zfn(0,0) = sqrt(2)
+   * IFS normalisation chosen to be 0.5*Integral(Pnm**2) = 1 (zfn(0,0) = 2.0)
+   */
+  double *zfn    = (double *) Malloc((kn+1) * (kn+1) * sizeof(double));
+  double *zfnlat = (double *) Malloc((kn/2+1+1)*sizeof(double));
 
-  const char *name = gridtype >= 0 && gridtype < size ? Grids[gridtype] : Grids[GRID_GENERIC];
+  zfn[0] = M_SQRT2;
+  for ( size_t jn = 1; jn <= kn; jn++ )
+    {
+      double zfnn = zfn[0];
+      for (size_t jgl = 1; jgl <= jn; jgl++)
+	{
+	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl)));
+	}
 
-  return name;
-}
+      zfn[jn*(kn+1)+jn] = zfnn;
 
+      size_t iodd = jn % 2;
+      for ( size_t jgl = 2; jgl <= jn-iodd; jgl += 2 )
+	{
+	  zfn[jn*(kn+1)+jn-jgl] = zfn[jn*(kn+1)+jn-jgl+2]
+	    *((double)((jgl-1)*(2*jn-jgl+2)))/((double)(jgl*(2*jn-jgl+1)));
+	}
+    }
 
-void gridName(int gridtype, char *gridname)
-{
-  strcpy(gridname, gridNamePtr(gridtype));
-}
 
-static
-char *grid_key_to_string(grid_t *gridptr, int key)
-{
-  char *gridstring = NULL;
+  /* 2.0 Gaussian latitudes and weights */
 
-  switch (key)
+  size_t iodd = kn % 2;
+  size_t ik = iodd;
+  for ( size_t jgl = iodd; jgl <= kn; jgl += 2 )
     {
-    case CDI_GRID_XDIMNAME: gridstring = gridptr->xdimname; break;
-    case CDI_GRID_YDIMNAME: gridstring = gridptr->ydimname; break;
-    case CDI_GRID_VDIMNAME: gridstring = gridptr->vdimname; break;
+      zfnlat[ik] = zfn[kn*(kn+1)+jgl];
+      ik++;
     }
 
-  return gridstring;
-}
+  /*
+   * 2.1 Find first approximation of the roots of the
+   *     Legendre polynomial of degree kn.
+   */
 
-/*
- at Function  cdiGridDefString
- at Title     Define a CDI grid string value from a key
+  size_t ins2 = kn/2+(kn % 2);
+  double z;
 
- at Prototype int cdiGridDefString(int gridID, int key, int size, const char *mesg)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  key      The key to be searched
-    @Item  size     The allocated length of the string on input
-    @Item  mesg     The address of a string where the data will be read
+  for ( size_t jgl = 1; jgl <= ins2; jgl++ )
+    {
+      z = ((double)(4*jgl-1))*M_PI/((double)(4*kn+2));
+      pl[jgl-1] = z+1.0/(tan(z)*((double)(8*kn*kn)));
+    }
 
- at Description
-The function @func{cdiGridDefString} defines a CDI grid string value from a key.
+  /* 2.2 Computes roots and weights for transformed theta */
 
- at Result
- at func{cdiGridDefString} returns 0 if OK and integer value on error.
+  for ( size_t jgl = ins2; jgl >= 1 ; jgl-- )
+    {
+      size_t jglm1 = jgl-1;
+      gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
+    }
 
- at EndFunction
-*/
-int cdiGridDefString(int gridID, int key, int size, const char *mesg)
-{
-  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
+  /* convert to physical latitude */
 
-  grid_t *gridptr = gridID2Ptr(gridID);
+  for ( size_t jgl = 0; jgl < ins2; jgl++ )
+    {
+      pl[jgl] = cos(pl[jgl]);
+    }
 
-  char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL )
+  for ( size_t jgl = 1; jgl <= kn/2; jgl++ )
     {
-      Warning("CDI grid string key %d not supported!", key);
-      return -1;
+      size_t jglm1 = jgl-1;
+      size_t isym =  kn-jgl;
+      pl[isym] =  -pl[jglm1];
+      pw[isym] =  pw[jglm1];
     }
 
-  gridSetString(gridstring, mesg, (size_t)size);
-  gridMark4Update(gridID);
+  Free(zfnlat);
+  Free(zfn);
 
-  return 0;
+  return;
 }
 
-/*
- at Function  cdiGridInqString
- at Title     Get a CDI grid string value from a key
-
- at Prototype int cdiGridInqString(int gridID, int key, int size, char *mesg)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  key      The key to be searched.
-    @Item  size     The allocated length of the string on input.
-    @Item  mesg     The address of a string where the data will be retrieved.
-                    The caller must allocate space for the returned string.
-                    The maximum possible length, in characters, of the string
-                    is given by the predefined constant @func{CDI_MAX_NAME}.
 
- at Description
-The function @func{cdiGridInqString} return a CDI grid string value from a key.
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
+{
+  //gauaw_old(pa, pw, nlat);
+  gauaw(nlat, pa, pw);
+}
 
- at Result
- at func{cdiGridInqString} returns 0 if OK and integer value on error.
 
- at EndFunction
-*/
-int cdiGridInqString(int gridID, int key, int size, char *mesg)
+bool isGaussGrid(size_t ysize, double yinc, const double *yvals)
 {
-  if ( size < 1 || mesg == NULL ) return -1;
+  bool lgauss = false;
 
-  grid_t *gridptr = gridID2Ptr(gridID);
-  const char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL)
+  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
     {
-      Warning("CDI grid string key %d not supported!", key);
-      return -1;
-    }
+      size_t i;
+      double *yv = (double *) Malloc(ysize*sizeof(double));
+      double *yw = (double *) Malloc(ysize*sizeof(double));
+      gaussaw(yv, yw, ysize);
+      Free(yw);
+      for ( i = 0; i < ysize; i++ )
+        yv[i] = asin(yv[i])/M_PI*180.0;
+
+      for ( i = 0; i < ysize; i++ )
+        if ( fabs(yv[i] - yvals[i]) >
+             ((yv[0] - yv[1])/500) ) break;
 
-  gridGetString(mesg, gridstring, (size_t)size);
+      if ( i == ysize ) lgauss = true;
 
-  return 0;
+      /* check S->N */
+      if ( lgauss == false )
+        {
+          for ( i = 0; i < ysize; i++ )
+            if ( fabs(yv[i] - yvals[ysize-i-1]) >
+                 ((yv[0] - yv[1])/500) ) break;
+
+          if ( i == ysize ) lgauss = true;
+        }
+
+      Free(yv);
+    }
+
+  return lgauss;
 }
 
 /*
- at Function  gridDefXname
- at Title     Define the name of a X-axis
+#define NGL  48
 
- at Prototype void gridDefXname(int gridID, const char *name)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  name     Name of the X-axis.
+int main (int rgc, char *argv[])
+{
+  int ngl = NGL;
+  double plo[NGL], pwo[NGL];
+  double pl[NGL], pw[NGL];
 
- at Description
-The function @func{gridDefXname} defines the name of a X-axis.
+  int i;
 
- at EndFunction
-*/
-void gridDefXname(int gridID, const char *xname)
-{
-  if ( xname && *xname )
+  gauaw(ngl, pl, pw);
+  for (i = 0; i < ngl; i++)
     {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xname, xname);
-      gridMark4Update(gridID);
+      pl[i]  = asin(pl[i])/M_PI*180.0;
+      plo[i] = asin(plo[i])/M_PI*180.0;
+    }
+
+  for (i = 0; i < ngl; i++)
+    {
+      fprintf(stderr, "%4d%25.18f%25.18f%25.18f%25.18f\n", i+1, pl[i], pw[i], pl[i]-plo[i], pw[i]-pwo[i]);
     }
-}
 
+  return 0;
+}
+*/
 /*
- at Function  gridDefXlongname
- at Title     Define the longname of a X-axis
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
- at Prototype void gridDefXlongname(int gridID, const char *longname)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  longname Longname of the X-axis.
+#if  defined  (HAVE_LIBGRIB_API)
+#  include <grib_api.h>
+#endif
 
- at Description
-The function @func{gridDefXlongname} defines the longname of a X-axis.
+#include <stdio.h>
 
- at EndFunction
-*/
-void gridDefXlongname(int gridID, const char *xlongname)
+
+static char gribapi_libvers[64] = "";
+#if  defined  (HAVE_LIBGRIB_API)
+static bool gribapi_libvers_init;
+#endif
+
+
+void gribapiLibraryVersion(int* major_version, int* minor_version, int* revision_version)
 {
-  if ( xlongname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xlongname, xlongname);
-      gridMark4Update(gridID);
-    }
+#if  defined  (HAVE_LIBGRIB_API)
+  long version = grib_get_api_version();
+  (*major_version)    = (int)(version/10000);
+  (*minor_version)    = (int)((version-(*major_version)*10000)/100);
+  (*revision_version) = (int)(version-(*major_version)*10000-(*minor_version)*100);
+#else
+  (*major_version)    = 0;
+  (*minor_version)    = 0;
+  (*revision_version) = 0;
+#endif
 }
 
-/*
- at Function  gridDefXunits
- at Title     Define the units of a X-axis
+const char *gribapiLibraryVersionString(void)
+{
+#if  defined  (HAVE_LIBGRIB_API)
+  if (!gribapi_libvers_init)
+    {
+      int major_version, minor_version, revision_version;
+
+      gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
 
- at Prototype void gridDefXunits(int gridID, const char *units)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  units    Units of the X-axis.
+      sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
+      gribapi_libvers_init = true;
+    }
+#endif
 
- at Description
-The function @func{gridDefXunits} defines the units of a X-axis.
+  return (gribapi_libvers);
+}
 
- at EndFunction
-*/
-void gridDefXunits(int gridID, const char *xunits)
+
+void gribContainersNew(stream_t * streamptr)
 {
-  if ( xunits )
+  int editionNumber = (streamptr->filetype == CDI_FILETYPE_GRB) ? 1 : 2;
+
+#if  defined  (HAVE_LIBCGRIBEX)
+  if ( editionNumber == 1 )
     {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xunits, xunits);
-      gridMark4Update(gridID);
     }
-}
+  else
+#endif
+    {
+      int nvars = streamptr->nvars;
 
-/*
- at Function  gridDefYname
- at Title     Define the name of a Y-axis
+#if defined (GRIBCONTAINER2D)
+      gribContainer_t **gribContainers;
+      gribContainers = (gribContainer_t **) Malloc(nvars*sizeof(gribContainer_t *));
 
- at Prototype void gridDefYname(int gridID, const char *name)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  name     Name of the Y-axis.
+      for ( int varID = 0; varID < nvars; ++varID )
+        {
+          int nlevs = streamptr->vars[varID].nlevs;
+          gribContainers[varID] = (gribContainer_t *) Malloc(nlevs*sizeof(gribContainer_t));
 
- at Description
-The function @func{gridDefYname} defines the name of a Y-axis.
+          for ( int levelID = 0; levelID < nlevs; ++levelID )
+            {
+              gribContainers[varID][levelID].gribHandle = gribHandleNew(editionNumber);
+              gribContainers[varID][levelID].init = false;
+            }
+	}
 
- at EndFunction
-*/
-void gridDefYname(int gridID, const char *yname)
-{
-  if ( yname && *yname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yname, yname);
-      gridMark4Update(gridID);
-    }
-}
+      streamptr->gribContainers = (void **) gribContainers;
+#else
+      gribContainer_t *gribContainers
+        = (gribContainer_t *) Malloc((size_t)nvars*sizeof(gribContainer_t));
 
-/*
- at Function  gridDefYlongname
- at Title     Define the longname of a Y-axis
+      for ( int varID = 0; varID < nvars; ++varID )
+        {
+          gribContainers[varID].gribHandle = gribHandleNew(editionNumber);
+          gribContainers[varID].init = false;
+	}
 
- at Prototype void gridDefYlongname(int gridID, const char *longname)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  longname Longname of the Y-axis.
+      streamptr->gribContainers = (void *) gribContainers;
+#endif
+    }
+}
 
- at Description
-The function @func{gridDefYlongname} defines the longname of a Y-axis.
 
- at EndFunction
-*/
-void gridDefYlongname(int gridID, const char *ylongname)
+void gribContainersDelete(stream_t * streamptr)
 {
-  if ( ylongname )
+  if ( streamptr->gribContainers )
     {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->ylongname, ylongname);
-      gridMark4Update(gridID);
-    }
-}
+      int nvars = streamptr->nvars;
 
-/*
- at Function  gridDefYunits
- at Title     Define the units of a Y-axis
+#if defined (GRIBCONTAINER2D)
+      gribContainer_t **gribContainers = (gribContainer_t **) streamptr->gribContainers;
 
- at Prototype void gridDefYunits(int gridID, const char *units)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  units    Units of the Y-axis.
+      for ( int varID = 0; varID < nvars; ++varID )
+	{
+          int nlevs = streamptr->vars[varID].nlevs;
+          for ( int levelID = 0; levelID < nlevs; ++levelID )
+            {
+              gribHandleDelete(gribContainers[varID][levelID].gribHandle);
+            }
+          Free(gribContainers[varID]);
+	}
+#else
+      gribContainer_t *gribContainers = (gribContainer_t *) streamptr->gribContainers;
 
- at Description
-The function @func{gridDefYunits} defines the units of a Y-axis.
+      for ( int varID = 0; varID < nvars; ++varID )
+	{
+          gribHandleDelete(gribContainers[varID].gribHandle);
+	}
+#endif
 
- at EndFunction
-*/
-void gridDefYunits(int gridID, const char *yunits)
-{
-  if ( yunits )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yunits, yunits);
-      gridMark4Update(gridID);
+      Free(gribContainers);
+
+      streamptr->gribContainers = NULL;
     }
 }
-
 /*
- at Function  gridInqXname
- at Title     Get the name of a X-axis
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
+#define INCLUDE_GUARD_CDI_GRIBAPI_UTILITIES_H
 
- at Prototype void gridInqXname(int gridID, char *name)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  name     Name of the X-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+#ifdef HAVE_LIBGRIB_API
 
- at Description
-The function @func{gridInqXname} returns the name of a X-axis.
 
- at Result
- at func{gridInqXname} returns the name of the X-axis to the parameter name.
+#include <grib_api.h>
 
- at EndFunction
-*/
-void gridInqXname(int gridID, char *xname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+#include <stdbool.h>
 
-  strcpy(xname, gridptr->xname);
-}
+char* gribCopyString(grib_handle* gribHandle, const char* key);
+bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue);
 
-const char *gridInqXnamePtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->xname;
-}
+bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue);
+long gribGetLong(grib_handle* gh, const char* key);
+long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue);
 
-/*
- at Function  gridInqXlongname
- at Title     Get the longname of a X-axis
+double gribGetDouble(grib_handle* gh, const char* key);
+double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue);
 
- at Prototype void gridInqXlongname(int gridID, char *longname)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  longname Longname of the X-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+size_t gribGetArraySize(grib_handle* gribHandle, const char* key);
+void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array);       //The caller is responsible to ensure a sufficiently large buffer.
+void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array);   //The caller is responsible to ensure a sufficiently large buffer.
 
- at Description
-The function @func{gridInqXlongname} returns the longname of a X-axis.
+long gribEditionNumber(grib_handle* gh);
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType);     //Returns NULL if timeType is kCdiTimeType_endTime and the field does not have an integration period (statistical data).
+int gribapiTimeIsFC(grib_handle *gh);
+int gribapiGetTsteptype(grib_handle *gh);
+int gribGetDatatype(grib_handle* gribHandle);
+int gribapiGetParam(grib_handle *gh);
+int gribapiGetGridType(grib_handle *gh);
+void gribapiGetGrid(grib_handle *gh, grid_t *grid);
 
- at Result
- at func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
+#ifdef HIRLAM_EXTENSIONS
+void gribapiSetDataTimeRangeIndicator(grib_handle *gh, int timeRangeIndicator);
+void gribapiGetDataTimeRangeIndicator(grib_handle *gh, int *timeRangeIndicator);
+#endif // #ifdef HIRLAM_EXTENSIONS
 
- at EndFunction
-*/
-void gridInqXlongname(int gridID, char *xlongname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+extern struct cdiGribAPI_ts_str_map_elem {
+  long productionTemplate;
+  const char sname[8];
+} cdiGribAPI_ts_str_map[];
 
-  strcpy(xlongname, gridptr->xlongname);
-}
+#endif
 
-/*
- at Function  gridInqXunits
- at Title     Get the units of a X-axis
+#endif
 
- at Prototype void gridInqXunits(int gridID, char *units)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  units    Units of the X-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
- at Description
-The function @func{gridInqXunits} returns the units of a X-axis.
+#ifdef HAVE_LIBGRIB_API
 
- at Result
- at func{gridInqXunits} returns the units of the X-axis to the parameter units.
 
- at EndFunction
-*/
-void gridInqXunits(int gridID, char *xunits)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
 
-  strcpy(xunits, gridptr->xunits);
-}
+#include <assert.h>
+#include <time.h>
 
+#define FAIL_ON_GRIB_ERROR(function, gribHandle, key, ...) do\
+{\
+  int errorCode = (int)function(gribHandle, key, __VA_ARGS__);  \
+  if(errorCode)\
+    {\
+      fprintf(stderr, "%s:%d: Error in function `%s`: `%s` returned error code %d for key \"%s\"", __FILE__, __LINE__, __func__, #function, errorCode, key);\
+      exit(errorCode);\
+    }\
+} while(0)
 
-void gridInqXstdname(int gridID, char *xstdname)
+//A simple wrapper for grib_get_string() that returns a newly allocated string.
+char* gribCopyString(grib_handle* gribHandle, const char* key)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->xstdname )
-    strcpy(xstdname, gridptr->xstdname);
+  size_t length;
+#ifdef HAVE_GRIB_GET_LENGTH
+  if (!grib_get_length(gribHandle, key, &length))
+    {
+      char *result = (char *)Malloc(length);
+      if (!grib_get_string(gribHandle, key, result, &length))
+        result = (char *) Realloc(result, length);
+      else
+        {
+          Free(result);
+          result = NULL;
+        }
+      return result;
+    }
+  else
+    return NULL;
+#else
+  length = 1024;         /* there's an implementation limit
+                          * that makes strings longer than
+                          * this unlikely in grib_api versions
+                          * not providing grib_get_length */
+  int rc;
+  char *result = (char *) Malloc(length);
+  while ((rc = grib_get_string(gribHandle, key, result, &length))
+         == GRIB_BUFFER_TOO_SMALL || rc == GRIB_ARRAY_TOO_SMALL)
+    {
+      if (length <= 1024UL * 1024UL)
+        {
+          length *= 2;
+          result = Realloc(result, length);
+        }
+      else
+        break;
+    }
+  if (!rc)
+    result = Realloc(result, length);
   else
-    xstdname[0] = 0;
+    {
+      Free(result);
+      result = NULL;
+    }
+  return result;
+#endif
 }
 
-/*
- at Function  gridInqYname
- at Title     Get the name of a Y-axis
-
- at Prototype void gridInqYname(int gridID, char *name)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  name     Name of the Y-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
-
- at Description
-The function @func{gridInqYname} returns the name of a Y-axis.
-
- at Result
- at func{gridInqYname} returns the name of the Y-axis to the parameter name.
-
- at EndFunction
-*/
-void gridInqYname(int gridID, char *yname)
+//A simple wrapper for grib_get_string() for the usecase that the result is only compared to a given constant string.
+//Returns true if the key exists and the value is equal to the given string.
+bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(yname, gridptr->yname);
+  size_t expectedLength = strlen(expectedValue) + 1;
+#ifdef HAVE_GRIB_GET_LENGTH
+  size_t length;
+  if(grib_get_length(gribHandle, key, &length)) return false;
+  if(length != expectedLength) return false;
+  char *value = (char *) Malloc(length);
+  if(grib_get_string(gribHandle, key, value, &length)) return false;
+  int rc = !strcmp(value, expectedValue);
+  Free(value);
+#else
+  char *value = gribCopyString(gribHandle, key);
+  int rc;
+  if (value)
+  {
+    rc = strlen(value) + 1 == expectedLength ?
+      !strcmp(value, expectedValue)
+      : false;
+  }
+  else
+    rc = false;
+  Free(value);
+#endif
+  return rc;
 }
 
-const char *gridInqYnamePtr(int gridID)
+//A simple wrapper for grib_get_long() for the usecase that the result is only compared to a given constant value.
+//Returns true if the key exists and the value is equal to the given one.
+bool gribCheckLong(grib_handle* gribHandle, const char* key, long expectedValue)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->yname;
+  long value;
+  if(grib_get_long(gribHandle, key, &value)) return false;
+  return value == expectedValue;
 }
 
-/*
- at Function  gridInqYlongname
- at Title     Get the longname of a Y-axis
-
- at Prototype void gridInqXlongname(int gridID, char *longname)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  longname Longname of the Y-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
-
- at Description
-The function @func{gridInqYlongname} returns the longname of a Y-axis.
+//A simple wrapper for grib_get_long() for the usecase that failure to fetch the value is fatal.
+long gribGetLong(grib_handle* gh, const char* key)
+{
+  long result;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, key, &result);
+  return result;
+}
 
- at Result
- at func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
+//A simple wrapper for grib_get_long() for the usecase that a default value is used in the case that the operation fails.
+long gribGetLongDefault(grib_handle* gribHandle, const char* key, long defaultValue)
+{
+  long result;
+  if ( grib_get_long(gribHandle, key, &result) || result == GRIB_MISSING_LONG )
+    result = defaultValue;
+  return result;
+}
 
- at EndFunction
-*/
-void gridInqYlongname(int gridID, char *ylongname)
+//A simple wrapper for grib_get_double() for the usecase that failure to fetch the value is fatal.
+double gribGetDouble(grib_handle* gh, const char* key)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  double result;
+  FAIL_ON_GRIB_ERROR(grib_get_double, gh, key, &result);
+  return result;
+}
 
-  strcpy(ylongname, gridptr->ylongname);
+//A sample wrapper for grib_get_double() for the usecase that a default value is used in the case that the operation fails.
+double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue)
+{
+  double result;
+  if ( grib_get_double(gribHandle, key, &result)
+       || IS_EQUAL(result, GRIB_MISSING_DOUBLE) )
+    result = defaultValue;
+  return result;
 }
 
-/*
- at Function  gridInqYunits
- at Title     Get the units of a Y-axis
+//A simple wrapper for grib_get_size() for the usecase that failure to fetch the value is fatal.
+size_t gribGetArraySize(grib_handle* gribHandle, const char* key)
+{
+  size_t result;
+  FAIL_ON_GRIB_ERROR(grib_get_size, gribHandle, key, &result);
+  return result;
+}
 
- at Prototype void gridInqYunits(int gridID, char *units)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  units    Units of the Y-axis. The caller must allocate space for the
-                    returned string. The maximum possible length, in characters, of
-                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+//A simple wrapper for grib_get_double_array() for the usecase that failure to fetch the data is fatal.
+void gribGetDoubleArray(grib_handle* gribHandle, const char* key, double* array)
+{
+  size_t valueCount = gribGetArraySize(gribHandle, key);
+  FAIL_ON_GRIB_ERROR(grib_get_double_array, gribHandle, key, array, &valueCount);
+}
 
- at Description
-The function @func{gridInqYunits} returns the units of a Y-axis.
+//A simple wrapper for grib_get_long_array() for the usecase that failure to fetch the data is fatal.
+void gribGetLongArray(grib_handle* gribHandle, const char* key, long* array)
+{
+  size_t valueCount = gribGetArraySize(gribHandle, key);
+  FAIL_ON_GRIB_ERROR(grib_get_long_array, gribHandle, key, array, &valueCount);
+}
 
- at Result
- at func{gridInqYunits} returns the units of the Y-axis to the parameter units.
 
- at EndFunction
-*/
-void gridInqYunits(int gridID, char *yunits)
+//We need the edition number so frequently, that it's convenient to give it its own function.
+long gribEditionNumber(grib_handle* gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  return gribGetLong(gh, "editionNumber");
+}
 
-  strcpy(yunits, gridptr->yunits);
+//This return value of this should be passed to a call to resetTz(), it is a malloc'ed string with the content of the TZ environment variable before the call (or NULL if that was not set).
+static char* setUtc()
+{
+  char* temp = getenv("TZ"), *result = NULL;
+  if(temp) result = strdup(temp);
+  setenv("TZ", "UTC", 1);
+  return result;
 }
 
-void gridInqYstdname(int gridID, char *ystdname)
+//Undoes the effect of setUtc(), pass to it the return value of the corresponding setUtc() call, it will free the string.
+static void resetTz(char* savedTz)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->ystdname )
-    strcpy(ystdname, gridptr->ystdname);
+  if(savedTz)
+    {
+      setenv("TZ", savedTz, 1);
+      Free(savedTz);
+    }
   else
-    ystdname[0] = 0;
+    {
+      unsetenv("TZ");
+    }
 }
 
-/*
- at Function  gridInqType
- at Title     Get the type of a Grid
-
- at Prototype int gridInqType(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+//This function uses the system functions to normalize the date representation according to the gregorian calendar.
+//Returns zero on success.
+static int normalizeDays(struct tm* me)
+{
+  char* savedTz = setUtc();     //Ensure that mktime() does not interprete the date according to our local time zone.
 
- at Description
-The function @func{gridInqType} returns the type of a Grid.
+  int result = mktime(me) == (time_t)-1;        //This does all the heavy lifting.
 
- at Result
- at func{gridInqType} returns the type of the grid,
-one of the set of predefined CDI grid types.
-The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
- at func{GRID_LONLAT}, @func{GRID_LCC}, @func{GRID_SPECTRAL}, @func{GRID_GME},
- at func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
+  resetTz(savedTz);
+  return result;
+}
 
- at EndFunction
-*/
-int gridInqType(int gridID)
+//Returns zero on success.
+static int addSecondsToDate(struct tm* me, long long amount)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->type;
+  //It is irrelevant here whether days are zero or one based, the correction would have be undone again so that it is effectless.
+  long long seconds = ((me->tm_mday*24ll + me->tm_hour)*60 + me->tm_min)*60 + me->tm_sec;    //The portion of the date that uses fixed increments.
+  seconds += amount;
+  me->tm_mday = (int)(seconds / 24 / 60 / 60);
+  seconds -= (long long)me->tm_mday * 24 * 60 * 60;
+  me->tm_hour = (int)(seconds / 60 / 60);
+  seconds -= (long long)me->tm_hour * 60 * 60;
+  me->tm_min = (int)(seconds / 60);
+  seconds -= (long long)(me->tm_min * 60);
+  me->tm_sec = (int)seconds;
+  return normalizeDays(me);
 }
 
-
-/*
- at Function  gridInqSize
- at Title     Get the size of a Grid
-
- at Prototype int gridInqSize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqSize} returns the size of a Grid.
-
- at Result
- at func{gridInqSize} returns the number of grid points of a Grid.
-
- at EndFunction
-*/
-int gridInqSize(int gridID)
+static void addMonthsToDate(struct tm* me, long long amount)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  int size = gridptr->size;
+  long long months = me->tm_year*12ll + me->tm_mon;
+  months += amount;
+  me->tm_year = (int)(months/12);
+  months -= (long long)me->tm_year*12;
+  me->tm_mon = (int)months;
+}
 
-  if ( size == 0 )
+//unit is a value according to code table 4.4 of the GRIB2 specification, returns non-zero on error
+static int addToDate(struct tm* me, long long amount, long unit)
+{
+  switch(unit)
     {
-      int xsize = gridptr->xsize;
-      int ysize = gridptr->ysize;
+      case 0: return addSecondsToDate(me,       60*amount);   // minute
+      case 1: return addSecondsToDate(me,    60*60*amount);   // hour
+      case 2: return addSecondsToDate(me, 24*60*60*amount);   // day
 
-      if ( ysize )
-        size = xsize * ysize;
-      else
-        size = xsize;
+      case 3: addMonthsToDate(me,        amount); return 0;   // month
+      case 4: addMonthsToDate(me,     12*amount); return 0;   // year
+      case 5: addMonthsToDate(me,  10*12*amount); return 0;   // decade
+      case 6: addMonthsToDate(me,  30*12*amount); return 0;   // normal
+      case 7: addMonthsToDate(me, 100*12*amount); return 0;   // century
+
+      case 10: return addSecondsToDate(me,  3*60*60*amount);  // eighth of a day
+      case 11: return addSecondsToDate(me,  6*60*60*amount);  // quarter day
+      case 12: return addSecondsToDate(me, 12*60*60*amount);  // half day
+      case 13: return addSecondsToDate(me,          amount);  // second
 
-      gridptr->size = size;
+      default: return 1;        //reserved, unknown, or missing
     }
-
-  return size;
 }
 
-static
-int nsp2trunc(int nsp)
+static char* makeDateString(struct tm* me)
 {
-  /*  nsp = (trunc+1)*(trunc+1)              */
-  /*      => trunc^2 + 3*trunc - (x-2) = 0   */
-  /*                                         */
-  /*  with:  y^2 + p*y + q = 0               */
-  /*         y = -p/2 +- sqrt((p/2)^2 - q)   */
-  /*         p = 3 and q = - (x-2)           */
-  int trunc = (int) (sqrt(nsp*4 + 1.) - 3) / 2;
-  return trunc;
+  char *result
+    = (char *) Malloc(       4+1+ 2+1+ 2+1+ 2+1+ 2+1+ 2+ 4+ 1);
+  sprintf(result, "%04d-%02d-%02dT%02d:%02d:%02d.000", me->tm_year + 1900, me->tm_mon + 1, me->tm_mday, me->tm_hour, me->tm_min, me->tm_sec);
+  return result;
 }
 
-
-int gridInqTrunc(int gridID)
+//FIXME: This ignores any calendar definition that might be present.
+//XXX: Identification templates are not implemented in grib_api-1.12.3, so even if I implemented the other calendars now, it wouldn't be possible to use them.
+static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecastTime, bool* outHaveTimeRange)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->trunc == 0 )
+  switch(gribGetLong(gh, "productDefinitionTemplateNumber"))
     {
-      if ( gridptr->type == GRID_SPECTRAL )
-        gridptr->trunc = nsp2trunc(gridptr->size);
-      /*
-      else if      ( gridptr->type == GRID_GAUSSIAN )
-        gridptr->trunc = nlat2trunc(gridptr->ysize);
-      */
-    }
-
-  return gridptr->trunc;
-}
+      case 20: case 30: case 31: case 254: case 311: case 2000:
+        *outHaveForecastTime = false, *outHaveTimeRange = false;
+        return 0;
 
+      //case 55 and case 40455 are the same: 55 is the proposed standard value, 40455 is the value in the local use range that is used by the dwd until the standard is updated.
+      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 15: case 32: case 33: case 40: case 41: case 44: case 45: case 48: case 51: case 53: case 54: case 55: case 56: case 60: case 1000: case 1002: case 1100: case 40033: case 40455: case 40456:
+        *outHaveForecastTime = true, *outHaveTimeRange = false;
+        return 0;
 
-void gridDefTrunc(int gridID, int trunc)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 34: case 42: case 43: case 46: case 47: case 61: case 91: case 1001: case 1101: case 40034:
+        *outHaveForecastTime = true, *outHaveTimeRange = true;
+        return 0;
 
-  if ( gridptr->trunc != trunc )
-    {
-      gridMark4Update(gridID);
-      gridptr->trunc = trunc;
+      default:
+        return 1;
     }
 }
 
-/*
- at Function  gridDefXsize
- at Title     Define the number of values of a X-axis
-
- at Prototype void gridDefXsize(int gridID, int xsize)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  xsize    Number of values of a X-axis.
-
- at Description
-The function @func{gridDefXsize} defines the number of values of a X-axis.
 
- at EndFunction
-*/
-void gridDefXsize(int gridID, int xsize)
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  int gridSize = gridInqSize(gridID);
-  if ( xsize > gridSize )
-    Error("xsize %d is greater then gridsize %d", xsize, gridSize);
-
-  int gridType = gridInqType(gridID);
-  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
-    Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
+  //Get the parts of the reference date.
+  struct tm date;
+  date.tm_mon = (int)gribGetLong(gh, "month") - 1;   //months are zero based in struct tm and one based in GRIB
+  date.tm_mday = (int)gribGetLong(gh, "day");
+  date.tm_hour = (int)gribGetLong(gh, "hour");
+  date.tm_min = (int)gribGetLong(gh, "minute");
 
-  if ( gridptr->xsize != xsize )
+  if(gribEditionNumber(gh) == 1)
     {
-      gridMark4Update(gridID);
-      gridptr->xsize = xsize;
+      date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
     }
-
-  if ( gridType != GRID_UNSTRUCTURED )
+  else
     {
-      long axisproduct = gridptr->xsize*gridptr->ysize;
-      if ( axisproduct > 0 && axisproduct != gridSize )
-        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
-              gridptr->xsize, gridptr->ysize, gridSize);
-    }
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
+      date.tm_year = (int)gribGetLong(gh, "year") - 1900;   //years are -1900 based in struct tm and zero based in GRIB2
+      date.tm_sec = (int)gribGetLong(gh, "second");
 
- at EndFunction
-*/
-void gridDefPrec(int gridID, int prec)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      //If the start or end time are requested, we need to take the relative times into account.
+      if(timeType != kCdiTimeType_referenceTime)
+        {
+          //Determine whether we have a forecast time and a time range.
+          bool haveForecastTime, haveTimeRange;
+          if(getAvailabilityOfRelativeTimes(gh, &haveForecastTime, &haveTimeRange)) return NULL;
+          if(timeType == kCdiTimeType_endTime && !haveTimeRange) return NULL;     //tell the caller that the requested time does not exist
 
-  if ( gridptr->prec != prec )
-    {
-      gridMark4Update(gridID);
-      gridptr->prec = prec;
+          //If we have relative times, apply the relative times to the date
+          if(haveForecastTime)
+            {
+              long offset = gribGetLongDefault(gh, "forecastTime", 0);  //if(stepUnits == indicatorOfUnitOfTimeRange) assert(startStep == forecastTime)
+              long offsetUnit = gribGetLongDefault(gh, "indicatorOfUnitOfTimeRange", 255);
+              if(addToDate(&date, offset, offsetUnit)) return NULL;
+              if(timeType == kCdiTimeType_endTime)
+                {
+                  assert(haveTimeRange);
+                  long range = gribGetLongDefault(gh, "lengthOfTimeRange", 0);       //if(stepUnits == indicatorOfUnitForTimeRange) assert(endStep == startStep + lengthOfTimeRange)
+                  long rangeUnit = gribGetLongDefault(gh, "indicatorOfUnitForTimeRange", 255);
+                  if(addToDate(&date, range, rangeUnit)) return NULL;
+                }
+            }
+        }
     }
-}
 
-/*
- at Function
- at Title
+  //Bake the date into a string.
+  return makeDateString(&date);
+}
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-int gridInqPrec(int gridID)
+int gribapiTimeIsFC(grib_handle *gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if (gribEditionNumber(gh) <= 1) return true;
 
-  return gridptr->prec;
+  long sigofrtime;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
+  return sigofrtime != 3;
 }
 
-/*
- at Function  gridInqXsize
- at Title     Get the number of values of a X-axis
-
- at Prototype int gridInqXsize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqXsize} returns the number of values of a X-axis.
+struct cdiGribAPI_ts_str_map_elem cdiGribAPI_ts_str_map[] = {
+  [TSTEP_INSTANT] = {  0, "instant" },
+  [TSTEP_AVG] = { 8, "avg" },
+  [TSTEP_ACCUM] = {  8, "accum" },
+  [TSTEP_MAX] = {  8, "max" },
+  [TSTEP_MIN] = {  8, "min" },
+  [TSTEP_DIFF] = {  8, "diff" },
+  [TSTEP_RMS] = {  8, "rms" },
+  [TSTEP_SD] = {  8, "sd" },
+  [TSTEP_COV] = { 8, "cov" },
+  [TSTEP_RATIO] = {  8, "ratio" },
+  { 0, "" }
+};
 
- at Result
- at func{gridInqXsize} returns the number of values of a X-axis.
 
- at EndFunction
-*/
-int gridInqXsize(int gridID)
+//Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range.
+int gribapiGetTsteptype(grib_handle *gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int tsteptype = TSTEP_INSTANT;
+  static bool lprint = true;
 
-  return gridptr->xsize;
-}
+  if ( gribapiTimeIsFC(gh) )
+    {
+      int status;
+      size_t len = 256;
+      char stepType[256];
 
-/*
- at Function  gridDefYsize
- at Title     Define the number of values of a Y-axis
+      status = grib_get_string(gh, "stepType", stepType, &len);
+      if ( status == 0 && len > 1 && len < 256 )
+        {
+          for (int i = TSTEP_INSTANT; cdiGribAPI_ts_str_map[i].sname[0]; ++i)
+            if ( strncmp(cdiGribAPI_ts_str_map[i].sname, stepType, len) == 0 )
+              {
+                tsteptype = i;
+                goto tsteptypeFound;
+              }
 
- at Prototype void gridDefYsize(int gridID, int ysize)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  ysize    Number of values of a Y-axis.
+          if ( lprint )
+            {
+              Message("Time stepType %s unsupported, set to instant!", stepType);
+              lprint = false;
+            }
+          // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
+        }
+#ifdef HIRLAM_EXTENSIONS
+      {
+      // Normaly cdo looks in grib for attribute called "stepType", see above.
+      // BUT NWP models such as Hirlam and Harmonie 37h1.2, use "timeRangeIndicator" instead!
+      // Where for example:       0: for instanteneous fields; 4: for accumulated fields
+      //  0:   Forecast product valid at reference time + P1
+      //  2:   Product with a valid time ranging between reference time + P1 and reference time + P2
+      //  4:   Accumulation (reference time + P1 to reference time + P2)
+      //  5:   Difference(reference time + P2 minus reference time + P1) product considered valid at reference time + P2
+      // More details on WMO standards:
+      //               http://www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html
+      //tsteptype = TSTEP_INSTANT;  // default value for any case
+      long timeRangeIND = 0; // typically 0: for instanteneous fields; 4: for accumulated fields
+      int rc = grib_get_long(gh, "timeRangeIndicator", &timeRangeIND);
+      if (rc != 0) {
+            //if ( lprint )
+            Warning("Could not get 'stepType' either 'timeRangeIndicator'. Using defualt!");
+            return (tsteptype);
+      }
+      extern int cdiGribUseTimeRangeIndicator;
+      cdiGribUseTimeRangeIndicator = 1;
+      switch ( timeRangeIND )
+          {
+              case 0:  tsteptype = TSTEP_INSTANT; break;
+              case 2:  tsteptype = TSTEP_INSTANT2;
+                       strcpy(stepType, "instant2");  // was incorrectly set before into accum
+                       break;
+              case 4:  tsteptype = TSTEP_ACCUM; break;
+              case 5:  tsteptype = TSTEP_DIFF; break;
+              default:
+                if ( lprint )
+                {
+                  if (CDI_Debug)
+                      Warning("timeRangeIND = %d;  stepType= %s; tsteptype=%d unsupported timeRangeIND at the moment, set to instant!", timeRangeIND, stepType, tsteptype);
+                  lprint = false;
+                }
+                break;
+          }
+      if (CDI_Debug)
+          Warning("timeRangeIND = %d;  stepType= %s; tsteptype=%d", timeRangeIND, stepType, tsteptype);
+      }
+#endif // HIRLAM_EXTENSIONS
+    }
+  tsteptypeFound:
+  return tsteptype;
+}
 
- at Description
-The function @func{gridDefYsize} defines the number of values of a Y-axis.
 
- at EndFunction
-*/
-void gridDefYsize(int gridID, int ysize)
+int gribGetDatatype(grib_handle* gribHandle)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  int gridSize = gridInqSize(gridID);
-
-  if ( ysize > gridSize )
-    Error("ysize %d is greater then gridsize %d", ysize, gridSize);
-
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ysize != gridSize )
-    Error("ysize %d must be equal gridsize %d for gridtype: UNSTRUCTURED", ysize, gridSize);
-
-  if ( gridptr->ysize != ysize )
+  int datatype;
+  if(gribEditionNumber(gribHandle) > 1 && gribCheckString(gribHandle, "packingType", "grid_ieee"))
     {
-      gridMark4Update(gridID);
-      gridptr->ysize = ysize;
+      datatype = gribCheckLong(gribHandle, "precision", 1) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
     }
-
-  if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
+  else
     {
-      long axisproduct = gridptr->xsize*gridptr->ysize;
-      if ( axisproduct > 0 && axisproduct != gridSize )
-        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
-              gridptr->xsize, gridptr->ysize, gridSize);
+      long bitsPerValue;
+      datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : CDI_DATATYPE_PACK;
     }
+  return datatype;
 }
 
-/*
- at Function  gridInqYsize
- at Title     Get the number of values of a Y-axis
-
- at Prototype int gridInqYsize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqYsize} returns the number of values of a Y-axis.
-
- at Result
- at func{gridInqYsize} returns the number of values of a Y-axis.
 
- at EndFunction
-*/
-int gridInqYsize(int gridID)
+int gribapiGetParam(grib_handle *gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ysize;
+  long pdis, pcat, pnum;
+  if ( gribEditionNumber(gh) <= 1 )
+    {
+      pdis = 255;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "table2Version", &pcat);
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "indicatorOfParameter", &pnum);
+    }
+  else
+    {
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "discipline", &pdis);
+      if(grib_get_long(gh, "parameterCategory", &pcat)) pcat = 0;
+      if(grib_get_long(gh, "parameterNumber", &pnum)) pnum = 0;
+    }
+  return cdiEncodeParam((int)pnum, (int)pcat, (int)pdis);
 }
 
-/*
- at Function  gridDefNP
- at Title     Define the number of parallels between a pole and the equator
 
- at Prototype void gridDefNP(int gridID, int np)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  np       Number of parallels between a pole and the equator.
+int gribapiGetGridType(grib_handle *gh)
+{
+  int gridtype = GRID_GENERIC;
+  switch (gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1))
+    {
+      case  GRIB2_GTYPE_LATLON:
+        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GENERIC : GRID_LONLAT;
+        break;
+      case  GRIB2_GTYPE_GAUSSIAN:
+        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN;
+        break;
+      case GRIB2_GTYPE_LATLON_ROT:   gridtype = GRID_PROJECTION; break;
+      case GRIB2_GTYPE_LCC:          gridtype = GRID_LCC; break;
+      case GRIB2_GTYPE_SPECTRAL:     gridtype = GRID_SPECTRAL; break;
+      case GRIB2_GTYPE_GME:          gridtype = GRID_GME; break;
+      case GRIB2_GTYPE_UNSTRUCTURED: gridtype = GRID_UNSTRUCTURED; break;
+    }
 
- at Description
-The function @func{gridDefNP} defines the number of parallels between a pole and the equator
-of a Gaussian grid.
+  return gridtype;
+}
 
- at EndFunction
-*/
-void gridDefNP(int gridID, int np)
+static
+int gribapiGetIsRotated(grib_handle *gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  return gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1) == GRIB2_GTYPE_LATLON_ROT;
+}
 
-  if ( gridptr->np != np )
+//TODO: Simplify by use of the convenience functions (gribGetLong(), gribGetLongDefault(), etc.).
+void gribapiGetGrid(grib_handle *gh, grid_t *grid)
+{
+  long editionNumber = gribEditionNumber(gh);
+  int gridtype = gribapiGetGridType(gh);
+  int projtype = (gridtype == GRID_PROJECTION && gribapiGetIsRotated(gh)) ? CDI_PROJ_RLL : CDI_UNDEFID;
+  if ( gridtype == GRID_LCC )
     {
-      gridMark4Update(gridID);
-      gridptr->np = np;
+      gridtype = GRID_PROJECTION;
+      projtype = CDI_PROJ_LCC;
     }
-}
+  /*
+  if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      gridtype = GRID_GAUSSIAN;
+      ISEC2_NumLon = 2*ISEC2_NumLat;
+      ISEC4_NumValues = ISEC2_NumLon*ISEC2_NumLat;
+    }
+  */
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
 
-/*
- at Function  gridInqNP
- at Title     Get the number of parallels between a pole and the equator
+  size_t datasize;
+  FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
+  long lpar;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &lpar);
+  size_t numberOfPoints = (size_t) lpar;
 
- at Prototype int gridInqNP(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
- at Description
-The function @func{gridInqNP} returns the number of parallels between a pole and the equator
-of a Gaussian grid.
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
+    {
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &lpar);
+      size_t nlon = (size_t) lpar;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
+      size_t nlat = (size_t) lpar;
 
- at Result
- at func{gridInqNP} returns the number of parallels between a pole and the equator.
+      if ( gridtype == GRID_GAUSSIAN )
+        {
+          FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
+          grid->np = (int)lpar;
+        }
 
- at EndFunction
-*/
-int gridInqNP(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      if ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
+
+      grid->size   = numberOfPoints;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
+      grid->x.inc  = 0;
+      grid->y.inc  = 0;
+      grid->x.flag = 0;
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->x.first);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->x.last);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->y.first);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->y.last);
+      if ( nlon > 1 )
+        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->x.inc);
+      if ( gridtype == GRID_LONLAT && nlat > 1 )
+        FAIL_ON_GRIB_ERROR(grib_get_double, gh, "jDirectionIncrementInDegrees", &grid->y.inc);
+
+      long iscan, jscan;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "iScansNegatively", &iscan);
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "jScansPositively", &jscan);
+      if (  iscan ) grid->x.inc = - grid->x.inc;
+      if ( !jscan ) grid->y.inc = - grid->y.inc;
+
+      if ( grid->x.inc < -999 || grid->x.inc > 999 ) grid->x.inc = 0;
+      if ( grid->y.inc < -999 || grid->y.inc > 999 ) grid->y.inc = 0;
+
+      /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
+      {
+        if ( grid->x.size > 1 )
+          {
+            if ( editionNumber <= 1 )
+              {
+                /* correct xinc if necessary */
+                if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 )
+                  {
+                    double xinc = 360. / grid->x.size;
+                    if ( fabs(grid->x.inc-xinc) > 0.0 )
+                      {
+                        grid->x.inc = xinc;
+                        if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
+                      }
+                  }
+              }
+          }
+        grid->x.flag = 2;
+      }
+      grid->y.flag = 0;
+      /* if ( IS_NOT_EQUAL(grid->y.first, 0) || IS_NOT_EQUAL(grid->y.last, 0) ) */
+      {
+        if ( grid->y.size > 1 )
+          {
+            if ( editionNumber <= 1 )
+              {
+              }
+          }
+        grid->y.flag = 2;
+      }
+    }
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
+      grid->np = (int)lpar;
 
-  return gridptr->np;
-}
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
+      int nlat = (int)lpar;
 
-/*
- at Function
- at Title
+      grid->size   = numberOfPoints;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+      grid->nrowlon = nlat;
+      grid->rowlon = (int *) Malloc((size_t)nlat * sizeof (int));
+      long *pl     = (long *) Malloc((size_t)nlat * sizeof (long));
+      size_t dummy = (size_t)nlat;
+      FAIL_ON_GRIB_ERROR(grib_get_long_array, gh, "pl", pl, &dummy);
+      for ( int i = 0; i < nlat; ++i ) grid->rowlon[i] = (int)pl[i];
+      Free(pl);
 
- at EndFunction
-*/
-void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      grid->y.size  = (size_t)nlat;
+      grid->x.inc   = 0;
+      grid->y.inc   = 0;
+      grid->x.flag  = 0;
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfFirstGridPointInDegrees", &grid->x.first);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "longitudeOfLastGridPointInDegrees",  &grid->x.last);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfFirstGridPointInDegrees",  &grid->y.first);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "latitudeOfLastGridPointInDegrees",   &grid->y.last);
 
-  gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
-  gridptr->nrowlon = nrowlon;
-  memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
-  gridMark4Update(gridID);
-}
+      // FAIL_ON_GRIB_ERROR(grib_get_double, gh, "iDirectionIncrementInDegrees", &grid->x.inc);
+      // if ( IS_EQUAL(grid->x.inc, GRIB_MISSING_DOUBLE) ) grid->x.inc = 0;
 
-/*
- at Function
- at Title
+      /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
+      {
+        if ( grid->x.size > 1 )
+          {
+            if ( (grid->x.first > grid->x.last) && (grid->x.first >= 180) ) grid->x.first -= 360;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+            if ( editionNumber <= 1 )
+              {
+                /* correct xinc if necessary */
+                if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 )
+                  {
+                    double xinc = 360. / grid->x.size;
+                    if ( fabs(grid->x.inc-xinc) > 0.0 )
+                      {
+                        grid->x.inc = xinc;
+                        if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
+                      }
+                  }
+              }
+          }
+        grid->x.flag = 2;
+      }
+      grid->y.flag = 0;
+      /* if ( IS_NOT_EQUAL(grid->y.first, 0) || IS_NOT_EQUAL(grid->y.last, 0) ) */
+      {
+        if ( grid->y.size > 1 )
+          {
+            if ( editionNumber <= 1 )
+              {
+              }
+          }
+        grid->y.flag = 2;
+      }
+    }
+  else if ( projtype == CDI_PROJ_LCC )
+    {
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nx", &lpar);
+      size_t nlon = (size_t)lpar;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ny", &lpar);
+      size_t nlat = (size_t)lpar;
 
- at EndFunction
-*/
-void gridInqRowlon(int gridID, int *rowlon)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      if ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
 
-  if ( gridptr->rowlon == 0 )  Error("undefined pointer!");
+      grid->size  = numberOfPoints;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
 
-  memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
-}
+      double xinc, yinc;
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DxInMetres", &xinc);
+      FAIL_ON_GRIB_ERROR(grib_get_double, gh, "DyInMetres", &yinc);
 
-static int
-gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
-                        int *restrict mask)
-{
-  long size = gridptr->size;
+      grid->x.first = 0;
+      grid->x.last  = 0;
+      grid->x.inc   = xinc;
+      grid->y.first = 0;
+      grid->y.last  = 0;
+      grid->y.inc   = yinc;
+      grid->x.flag  = 2;
+      grid->y.flag  = 2;
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      size_t len = 256;
+      char typeOfPacking[256];
+      FAIL_ON_GRIB_ERROR(grib_get_string, gh, "packingType", typeOfPacking, &len);
+      grid->lcomplex = 0;
+      if ( strncmp(typeOfPacking, "spectral_complex", len) == 0 ) grid->lcomplex = 1;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridptr->self);
+      grid->size = datasize;
 
-  const mask_t *restrict mask_src = *internalMask;
-  if ( mask_src )
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
+      grid->trunc = (int)lpar;
+    }
+  else if ( gridtype == GRID_GME )
     {
-      if (mask && size > 0)
-        for (size_t i = 0; i < (size_t)size; ++i)
-          mask[i] = (int)mask_src[i];
+      grid->size = numberOfPoints;
+      if ( grib_get_long(gh, "nd", &lpar) == 0 ) grid->gme.nd  = (int)lpar;
+      if ( grib_get_long(gh, "Ni", &lpar) == 0 ) grid->gme.ni  = (int)lpar;
+      if ( grib_get_long(gh, "n2", &lpar) == 0 ) grid->gme.ni2 = (int)lpar;
+      if ( grib_get_long(gh, "n3", &lpar) == 0 ) grid->gme.ni3 = (int)lpar;
     }
-  else
-    size = 0;
-
-  return (int)size;
-}
-
-static int
-gridInqMaskSerial(grid_t *gridptr, int *mask)
-{
-  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
-}
-
-
-int gridInqMask(int gridID, int *mask)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqMask(gridptr, mask);
-}
+  else if ( gridtype == GRID_UNSTRUCTURED )
+    {
+      unsigned char uuid[CDI_UUID_SIZE];
+      /*
+        char reference_link[8192];
+        size_t len = sizeof(reference_link);
+        reference_link[0] = 0;
+      */
+      grid->size = numberOfPoints;
 
-static void
-gridDefMaskSerial(grid_t *gridptr, const int *mask)
-{
-  long size = gridptr->size;
+      if ( grib_get_long(gh, "numberOfGridUsed", &lpar) == 0 )
+        {
+          grid->number   = (int)lpar;
+          if ( grib_get_long(gh, "numberOfGridInReference", &lpar) == 0 )
+            grid->position = (int)lpar;
+          /*
+            if ( grib_get_string(gh, "gridDescriptionFile", reference_link, &len) == 0 )
+            {
+            if ( strncmp(reference_link, "file://", 7) == 0 )
+            grid->reference = strdupx(reference_link);
+            }
+          */
+          size_t len = (size_t)CDI_UUID_SIZE;
+          if ( grib_get_bytes(gh, "uuidOfHGrid", uuid, &len) == 0)
+            {
+              memcpy(grid->uuid, uuid, CDI_UUID_SIZE);
+            }
+        }
+    }
+  else if ( gridtype == GRID_GENERIC )
+    {
+      size_t nlon = 0, nlat = 0;
+      if ( grib_get_long(gh, "Ni", &lpar) == 0 ) nlon = (size_t)lpar;
+      if ( grib_get_long(gh, "Nj", &lpar) == 0 ) nlat = (size_t)lpar;
 
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
+      grid->size = numberOfPoints;
 
-  if ( mask == NULL )
-    {
-      if ( gridptr->mask )
-	{
-	  Free(gridptr->mask);
-	  gridptr->mask = NULL;
-	}
+      if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
+        {
+          grid->x.size = nlon;
+          grid->y.size = nlat;
+        }
+      else
+        {
+          grid->x.size = 0;
+          grid->y.size = 0;
+        }
     }
   else
     {
-      if ( gridptr->mask == NULL )
-	gridptr->mask = (mask_t *) Malloc((size_t)size*sizeof(mask_t));
-      else if ( CDI_Debug )
-	Warning("grid mask already defined!");
-
-      for (long i = 0; i < size; ++i )
-	gridptr->mask[i] = (mask_t)(mask[i] != 0);
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
-}
 
-void gridDefMask(int gridID, const int *mask)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defMask(gridptr, mask);
-  gridMark4Update(gridID);
-}
+  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION )
+    {
+      long temp;
+      GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &temp), 0);
+      assert(temp == 0 || temp == 1);
+      grid->uvRelativeToGrid = (bool)temp;
+    }
 
-static int
-gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
-{
-  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
-}
+  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT || gridtype == GRID_PROJECTION )
+    {
+      long temp;
+      GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &temp), 0);
+      grid->iScansNegatively = (bool)temp;
+      GRIB_CHECK(grib_get_long(gh, "jScansPositively", &temp), 0);
+      grid->jScansPositively = (bool)temp;
+      GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &temp), 0);
+      grid->jPointsAreConsecutive = (bool)temp;
+      grid->scanningMode = 128*grid->iScansNegatively + 64*grid->jScansPositively + 32*grid->jPointsAreConsecutive;
+      /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
+                   64  = 128 * 0                + 64 *        1         + 32 * 0
+                   00  = 128 * 0                + 64 *        0         + 32 * 0
+                   96  = 128 * 0                + 64 *        1         + 32 * 1
+         Default / implicit scanning mode is 64:
+                            i and j scan positively, i points are consecutive (row-major)        */
+#ifdef HIRLAM_EXTENSIONS
+      if (cdiDebugExt>=30)
+      {
+        //  indicatorOfParameter=33,indicatorOfTypeOfLevel=105,level
+        long paramId, levelTypeId, levelId;
+        GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
+        GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
+        GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
+        Message("(param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d -> bits:(%1d.%1d.%1d)*32;  uvRelativeToGrid = %02d",\
+                (int)paramId, (int)levelTypeId, (int)levelId,
+                grid->scanningMode,grid->jPointsAreConsecutive,
+                grid->jScansPositively,grid->iScansNegatively,
+                grid->uvRelativeToGrid);
+      }
+#endif //HIRLAM_EXTENSIONS
+    }
 
-int gridInqMaskGME(int gridID, int *mask)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqMaskGME(gridptr, mask);
+  grid->type  = gridtype;
+  grid->projtype  = projtype;
 }
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef CDI_UUID_H
+#define CDI_UUID_H
 
-static void
-gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
-{
-  long size = gridptr->size;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
-
-  if ( gridptr->mask_gme == NULL )
-    gridptr->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
-  else if ( CDI_Debug )
-    Warning("mask already defined!");
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  for (long i = 0; i < size; ++i)
-    gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
-}
 
-void gridDefMaskGME(int gridID, const int *mask)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defMaskGME(gridptr, mask);
-  gridMark4Update(gridID);
-}
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-static int
-gridInqXValsSerial(grid_t *gridptr, double *xvals)
+static inline int cdiUUIDIsNull(const unsigned char uuid[])
 {
-  long size;
-  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
-    size = gridptr->size;
-  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
-    size = 2;
-  else
-    size = gridptr->xsize;
+  int isNull = 1;
+  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
+    isNull &= (uuid[i] == 0);
+  return isNull;
+}
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d", gridptr->self);
+void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
 
-  if ( gridptr->xvals )
-    {
-      if ( size && xvals )
-        {
-          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
-          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
-        }
-    }
-  else
-    size = 0;
+void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
+int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
 
-  return (int)size;
+#if defined (__cplusplus)
 }
+#endif
 
-/*
- at Function  gridInqXvals
- at Title     Get all values of a X-axis
+#endif
 
- at Prototype int gridInqXvals(int gridID, double *xvals)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  xvals    Pointer to the location into which the X-values are read.
-                    The caller must allocate space for the returned values.
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef RESOURCE_UNPACK_H
+#define RESOURCE_UNPACK_H
 
- at Description
-The function @func{gridInqXvals} returns all values of the X-axis.
+#ifdef HAVE_CONFIG_H
+#endif
 
- at Result
-Upon successful completion @func{gridInqXvals} returns the number of values and
-the values are stored in @func{xvals}.
-Otherwise, 0 is returned and @func{xvals} is empty.
+enum
+{ GRID      = 1,
+  ZAXIS     = 2,
+  TAXIS     = 3,
+  INSTITUTE = 4,
+  MODEL     = 5,
+  STREAM    = 6,
+  VLIST     = 7,
+  RESH_DELETE,
+  START     = 55555555,
+  END       = 99999999
+};
 
- at EndFunction
-*/
-int gridInqXvals(int gridID, double *xvals)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXVals(gridptr, xvals);
-}
+int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
+                        void *context);
 
+#endif
 
-static void
-gridDefXValsSerial(grid_t *gridptr, const double *xvals)
-{
-  int gridtype = gridptr->type;
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _VLIST_H
+#define _VLIST_H
 
-  long size;
-  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    size = gridptr->size;
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    size = 2;
-  else
-    size = gridptr->xsize;
+#ifdef HAVE_CONFIG_H
+#endif
 
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
+#ifndef  ERROR_H
+#endif
 
-  if (gridptr->xvals && CDI_Debug)
-    Warning("values already defined!");
-  gridptr->xvals = (double *)Realloc(gridptr->xvals,
-                                      (size_t)size * sizeof(double));
-  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
-}
+#include <stddef.h>  /* size_t */
 
-/*
- at Function  gridDefXvals
- at Title     Define the values of a X-axis
+#ifndef _CDI_LIMITS_H
+#endif
 
- at Prototype void gridDefXvals(int gridID, const double *xvals)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  xvals    X-values of the grid.
+#define VALIDMISS 1.e+303
 
- at Description
-The function @func{gridDefXvals} defines all values of the X-axis.
 
- at EndFunction
-*/
-void gridDefXvals(int gridID, const double *xvals)
+typedef struct
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defXVals(gridptr, xvals);
-  gridMark4Update(gridID);
+  bool     flag;
+  int      index;
+  int      mlevelID;
+  int      flevelID;
 }
+levinfo_t;
 
-static int
-gridInqYValsSerial(grid_t *gridptr, double *yvals)
+#define DEFAULT_LEVINFO(levID) \
+  (levinfo_t){ 0, -1, levID, levID}
+/*
+#define DEFAULT_LEVINFO(levID) \
+  (levinfo_t){ .flag = 0, .index = -1, .flevelID = levID, .mlevelID = levID}
+*/
+typedef struct
 {
-  int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
-
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d!", gridptr->self);
+  int ens_index;
+  int ens_count;
+  int forecast_init_type;
+}
+ensinfo_t;
 
-  if ( gridptr->yvals )
-    {
-      if ( size && yvals )
-        {
-          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
-          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
-        }
-    }
-  else
-    size = 0;
 
-  return (int)size;
-}
 
-/*
- at Function  gridInqYvals
- at Title     Get all values of a Y-axis
+typedef struct
+{
+  bool        isUsed;
+  bool        flag;
+  int         mvarID;
+  int         fvarID;
+  int         param;
+  int         gridID;
+  int         zaxisID;
+  int         timetype;  /* TIME_* */
+  int         tsteptype; /* TSTEP_* */
+  int         datatype;  /* CDI_DATATYPE_PACKX for GRIB data, else CDI_DATATYPE_FLT32 or CDI_DATATYPE_FLT64 */
+  int         instID;
+  int         modelID;
+  int         tableID;
+  int         timave;
+  int         timaccu;
+  int         typeOfGeneratingProcess;
+  int         productDefinitionTemplate;
+  int         chunktype;
+  int         xyz;
+  bool        missvalused; /* true if missval is defined */
+  bool        lvalidrange;
+  char       *name;
+  char       *longname;
+  char       *stdname;
+  char       *units;
+  char       *extra;
+  double      missval;
+  double      scalefactor;
+  double      addoffset;
+  double      validrange[2];
+  levinfo_t  *levinfo;
+  int         comptype;     // compression type
+  int         complevel;    // compression level
+  ensinfo_t  *ensdata;      /* Ensemble information */
+  cdi_atts_t  atts;
+  int         iorank;
 
- at Prototype int gridInqYvals(int gridID, double *yvals)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  yvals    Pointer to the location into which the Y-values are read.
-                    The caller must allocate space for the returned values.
+  int         subtypeID;   /* subtype ID for tile-related meta-data, currently for GRIB-API only. */
 
- at Description
-The function @func{gridInqYvals} returns all values of the Y-axis.
+  int                 opt_grib_nentries;       /* current no. key-value pairs            */
+  int                 opt_grib_kvpair_size;    /* current allocated size                 */
+  opt_key_val_pair_t *opt_grib_kvpair;         /* (optional) list of keyword/value pairs */
+}
+var_t;
 
- at Result
-Upon successful completion @func{gridInqYvals} returns the number of values and
-the values are stored in @func{yvals}.
-Otherwise, 0 is returned and @func{yvals} is empty.
 
- at EndFunction
-*/
-int gridInqYvals(int gridID, double *yvals)
+typedef struct
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYVals(gridptr, yvals);
+  //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
+  bool        immutable;
+  //set if this vlist has been created by CDI itself, and must not be destroyed by the user, consequently
+  bool        internal;
+  int         self;
+  int         nvars;        /* number of variables                */
+  int         ngrids;
+  int         nzaxis;
+  int         nsubtypes;    /* no. of variable subtypes (e.g. sets of tiles) */
+  long        ntsteps;
+  int         taxisID;
+  int         tableID;
+  int         instID;
+  int         modelID;
+  int         varsAllocated;
+  int         gridIDs[MAX_GRIDS_PS];
+  int         zaxisIDs[MAX_ZAXES_PS];
+  int         subtypeIDs[MAX_SUBTYPES_PS];
+  var_t      *vars;
+  cdi_atts_t  atts;
 }
+vlist_t;
 
-static void
-gridDefYValsSerial(grid_t *gridptr, const double *yvals)
-{
-  int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
 
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d!", gridptr->self);
+vlist_t *vlist_to_pointer(int vlistID);
+void cdiVlistMakeInternal(int vlistID);
+void cdiVlistMakeImmutable(int vlistID);
+void vlistCheckVarID(const char *caller, int vlistID, int varID);
+void     vlistDestroyVarName(int vlistID, int varID);
+void     vlistDestroyVarLongname(int vlistID, int varID);
+void     vlistDestroyVarStdname(int vlistID, int varID);
+void     vlistDestroyVarUnits(int vlistID, int varID);
+void     cdiVlistDestroy_(int vlistID);
+int      vlistInqVarMissvalUsed(int vlistID, int varID);
+int      vlistHasTime(int vlistID);
 
-  if (gridptr->yvals && CDI_Debug)
-    Warning("Values already defined!");
+int      cdiDelAtts(int vlistID, int varID);
 
-  gridptr->yvals = (double *)Realloc(gridptr->yvals, (size_t)size * sizeof (double));
-  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
-}
+void     vlistUnpack(char * buffer, int bufferSize, int * pos,
+                     int originNamespace, void *context, int force_id);
 
+/*      vlistDefVarValidrange: Define the valid range of a Variable */
+void    vlistDefVarValidrange(int vlistID, int varID, const double *validrange);
 
-/*
- at Function  gridDefYvals
- at Title     Define the values of a Y-axis
+/*      vlistInqVarValidrange: Get the valid range of a Variable */
+int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
 
- at Prototype void gridDefYvals(int gridID, const double *yvals)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  yvals    Y-values of the grid.
+void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
 
- at Description
-The function @func{gridDefYvals} defines all values of the Y-axis.
+int cdi_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
 
- at EndFunction
-*/
-void gridDefYvals(int gridID, const double *yvals)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defYVals(gridptr, yvals);
-  gridMark4Update(gridID);
-}
+void resize_opt_grib_entries(var_t *var, int nentries);
 
-static double
-gridInqXValSerial(grid_t *gridptr, int index)
-{
-  double xval = gridptr->xvals ? gridptr->xvals[index] : 0;
-  return xval;
-}
 
 
-double gridInqXval(int gridID, int index)
+static inline
+void vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXVal(gridptr, index);
-}
+  int index, ngrids = vlistptr->ngrids;
+  for ( index = 0; index < ngrids; index++ )
+    {
+      if ( vlistptr->gridIDs[index] == gridID ) break;
+      //      if ( gridIsEqual(vlistptr->gridIDs[index], gridID) ) break;
+    }
 
-static double
-gridInqYValSerial(grid_t *gridptr, int index)
-{
-  double yval = gridptr->yvals ? gridptr->yvals[index] : 0;
-  return yval;
+  if ( index == ngrids )
+    {
+      if ( ngrids >= MAX_GRIDS_PS )
+        Error("Internal limit exceeded: more than %d grids.", MAX_GRIDS_PS);
+      vlistptr->gridIDs[ngrids] = gridID;
+      ++(vlistptr->ngrids);
+    }
 }
 
-/*
- at Function
- at Title
+static inline
+void vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
+{
+  int index, nzaxis = vlistptr->nzaxis;
+  for ( index = 0; index < nzaxis; index++ )
+    if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+  if ( index == nzaxis )
+    {
+      if ( nzaxis >= MAX_ZAXES_PS )
+	Error("Internal limit exceeded: more than %d zaxis.", MAX_ZAXES_PS);
+      vlistptr->zaxisIDs[nzaxis] = zaxisID;
+      ++(vlistptr->nzaxis);
+    }
+}
 
- at EndFunction
-*/
-double gridInqYval(int gridID, int index)
+static inline
+void vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYVal(gridptr, index);
-}
+  if ( subtypeID == CDI_UNDEFID ) return;
 
-/*
- at Function
- at Title
+  int index, nsubs = vlistptr->nsubtypes;
+  for ( index = 0; index < nsubs; index++ )
+    if ( vlistptr->subtypeIDs[index] == subtypeID ) break;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+  if ( index == nsubs )
+    {
+      if ( nsubs >= MAX_SUBTYPES_PS )
+        Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
+      vlistptr->subtypeIDs[nsubs] = subtypeID;
+      ++(vlistptr->nsubtypes);
+    }
+}
 
- at EndFunction
-*/
-double gridInqXinc(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double xinc = gridptr->xinc;
-  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
-  if ( (! (fabs(xinc) > 0)) && xvals )
-    {
-      int xsize = gridptr->xsize;
-      if ( xsize > 1 )
-        {
-          xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-          for (size_t i = 2; i < (size_t)xsize; i++ )
-            if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
-              {
-                xinc = 0;
-                break;
-              }
 
-          gridptr->xinc = xinc;
-        }
-    }
+#if  defined  (HAVE_LIBGRIB_API)
+extern int   cdiNAdditionalGRIBKeys;
+extern char* cdiAdditionalGRIBKeys[];
+#endif
 
-  return xinc;
-}
+extern
+#ifndef __cplusplus
+const
+#endif
+resOps vlistOps;
 
+#endif  /* _VLIST_H */
 /*
- at Function
- at Title
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+#include <assert.h>
+#include <string.h>
 
- at EndFunction
-*/
-double gridInqYinc(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double yinc = gridptr->yinc;
-  const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
 
-  if ( (! (fabs(yinc) > 0)) && yvals )
-    {
-      int ysize = gridptr->ysize;
-      if ( ysize > 1 )
-        {
-          yinc = yvals[1] - yvals[0];
-          double abs_yinc = fabs(yinc);
-          for ( size_t i = 2; i < (size_t)ysize; i++ )
-            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
-              {
-                yinc = 0;
-                break;
-              }
+double grid_missval = -9999.;
+int (*proj_lonlat_to_lcc_func)() = NULL;
+int (*proj_lcc_to_lonlat_func)() = NULL;
 
-          gridptr->yinc = yinc;
-        }
-    }
+/* the value in the second pair of brackets must match the length of
+ * the longest string (including terminating NUL) */
+static const char Grids[][17] = {
+  /*  0 */  "undefined",
+  /*  1 */  "generic",
+  /*  2 */  "gaussian",
+  /*  3 */  "gaussian reduced",
+  /*  4 */  "lonlat",
+  /*  5 */  "spectral",
+  /*  6 */  "fourier",
+  /*  7 */  "gme",
+  /*  8 */  "trajectory",
+  /*  9 */  "unstructured",
+  /* 10 */  "curvilinear",
+  /* 11 */  "lcc",
+  /* 12 */  "projection",
+  /* 13 */  "characterXY",
+};
 
-  return yinc;
-}
+/* must match table below */
+enum xystdname_idx {
+  grid_xystdname_grid_latlon,
+  grid_xystdname_latlon,
+  grid_xystdname_projection,
+  grid_xystdname_char,
+};
+static const char xystdname_tab[][2][24] = {
+  [grid_xystdname_grid_latlon] = { "grid_longitude",
+                                   "grid_latitude" },
+  [grid_xystdname_latlon] = { "longitude",
+                              "latitude" },
+  [grid_xystdname_projection] = { "projection_x_coordinate",
+                                  "projection_y_coordinate" },
+  [grid_xystdname_char] = { "region",
+                            "region" },
+};
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-double gridInqXpole(int gridID)
-{
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+static int    gridCompareP    ( void * gridptr1, void * gridptr2 );
+static void   gridDestroyP    ( void * gridptr );
+static void   gridPrintP      ( void * gridptr, FILE * fp );
+static int    gridGetPackSize ( void * gridptr, void *context);
+static void   gridPack        ( void * gridptr, void * buff, int size, int *position, void *context);
+static int    gridTxCode      ( void );
 
-  return gridptr->xpole;
-}
+static const resOps gridOps = {
+  gridCompareP,
+  gridDestroyP,
+  gridPrintP,
+  gridGetPackSize,
+  gridPack,
+  gridTxCode
+};
 
-/*
- at Function
- at Title
+static int  GRID_Debug = 0;   /* If set to 1, debugging */
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-void gridDefXpole(int gridID, double xpole)
+grid_t *grid_to_pointer(int gridID)
 {
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+  return (grid_t *)reshGetVal(gridID, &gridOps);
+}
+
+#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
 
-  if ( gridptr->xstdname && memcmp(gridptr->xstdname, "grid", 4) != 0 )
-    gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+static
+bool cdiInqAttConvertedToFloat(int gridID, int atttype, const char *attname, int attlen, double *attflt)
+{
+  bool status = true;
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->xpole, xpole) )
+  if ( atttype == CDI_DATATYPE_INT32 )
     {
-      gridptr->isRotated = TRUE;
-      gridptr->xpole = xpole;
-      gridMark4Update(gridID);
+      int attint[attlen];
+      cdiInqAttInt(gridID, CDI_GLOBAL, attname, attlen, attint);
+      for ( int i = 0; i < attlen; ++i ) attflt[i] = (double)attint[i];
+    }
+  else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+    {
+      cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
+    }
+  else
+    {
+      status = false;
     }
-}
 
-/*
- at Function
- at Title
+  return status;
+}
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-double gridInqYpole(int gridID)
+void grid_init(grid_t *gridptr)
 {
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ypole;
-}
-
-/*
- at Function
- at Title
+  gridptr->self          = CDI_UNDEFID;
+  gridptr->type          = CDI_UNDEFID;
+  gridptr->proj          = CDI_UNDEFID;
+  gridptr->projtype      = CDI_UNDEFID;
+  gridptr->mask          = NULL;
+  gridptr->mask_gme      = NULL;
+  gridptr->x.vals        = NULL;
+  gridptr->x.cvals       = NULL;
+  gridptr->x.clength     = 0;
+  gridptr->y.vals        = NULL;
+  gridptr->y.cvals       = NULL;
+  gridptr->y.clength     = 0;
+  gridptr->x.bounds      = NULL;
+  gridptr->y.bounds      = NULL;
+  gridptr->area          = NULL;
+  gridptr->rowlon        = NULL;
+  gridptr->nrowlon       = 0;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+  gridptr->x.first       = 0.0;
+  gridptr->x.last        = 0.0;
+  gridptr->x.inc         = 0.0;
+  gridptr->y.first       = 0.0;
+  gridptr->y.last        = 0.0;
+  gridptr->y.inc         = 0.0;
 
- at EndFunction
-*/
-void gridDefYpole(int gridID, double ypole)
-{
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->gme.nd        = 0;
+  gridptr->gme.ni        = 0;
+  gridptr->gme.ni2       = 0;
+  gridptr->gme.ni3       = 0;
 
-  if ( gridptr->ystdname && memcmp(gridptr->ystdname, "grid", 4) != 0 )
-    gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+  gridptr->trunc         = 0;
+  gridptr->nvertex       = 0;
+  gridptr->number        = 0;
+  gridptr->position      = 0;
+  gridptr->reference     = NULL;
+  gridptr->datatype      = 0;
+  gridptr->size          = 0;
+  gridptr->x.size        = 0;
+  gridptr->y.size        = 0;
+  gridptr->np            = 0;
+  gridptr->x.flag        = 0;
+  gridptr->y.flag        = 0;
+  gridptr->isCyclic      = CDI_UNDEFID;
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->ypole, ypole) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->ypole = ypole;
-      gridMark4Update(gridID);
-    }
+  gridptr->lcomplex      = false;
+  gridptr->hasdims       = true;
+  gridptr->x.dimname[0]  = 0;
+  gridptr->y.dimname[0]  = 0;
+  gridptr->x.name[0]     = 0;
+  gridptr->y.name[0]     = 0;
+  gridptr->x.longname[0] = 0;
+  gridptr->y.longname[0] = 0;
+  gridptr->x.units[0]    = 0;
+  gridptr->y.units[0]    = 0;
+  gridptr->x.stdname     = NULL;
+  gridptr->y.stdname     = NULL;
+  gridptr->vdimname[0]   = 0;
+  gridptr->mapname[0]    = 0;
+  gridptr->mapping[0]    = 0;
+  memset(gridptr->uuid, 0, CDI_UUID_SIZE);
+  gridptr->name          = NULL;
+  gridptr->vtable        = &cdiGridVtable;
+  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
+  gridptr->atts.nelems   = 0;
+  gridptr->uvRelativeToGrid      = 0;   // Some models deliver wind U,V relative to the grid-cell
+  gridptr->iScansNegatively      = 0;
+  gridptr->jScansPositively      = 1;
+  gridptr->jPointsAreConsecutive = 0;
+  gridptr->scanningMode          = 128*gridptr->iScansNegatively + 64*gridptr->jScansPositively + 32*gridptr->jPointsAreConsecutive;
+  /* scanningMode  = 128 * iScansNegatively + 64 * jScansPositively + 32 * jPointsAreConsecutive;
+               64  = 128 * 0                + 64 *        1         + 32 * 0
+               00  = 128 * 0                + 64 *        0         + 32 * 0
+               96  = 128 * 0                + 64 *        1         + 32 * 1
+     Default / implicit scanning mode is 64:
+                        i and j scan positively, i points are consecutive (row-major)        */
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-double gridInqAngle(int gridID)
+static
+void grid_free_components(grid_t *gridptr)
 {
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
+                     gridptr->x.vals, gridptr->y.vals,
+                     gridptr->x.cvals, gridptr->y.cvals,
+                     gridptr->x.bounds, gridptr->y.bounds,
+                     gridptr->rowlon, gridptr->area,
+                     gridptr->reference, gridptr->name};
 
-  return gridptr->angle;
+  for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
+    if ( p2free[i] ) Free(p2free[i]);
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
+void grid_free(grid_t *gridptr)
+{
+  grid_free_components(gridptr);
+  grid_init(gridptr);
+}
 
- at EndFunction<
-*/
-void gridDefAngle(int gridID, double angle)
+static
+grid_t *gridNewEntry(cdiResH resH)
 {
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
+  grid_init(gridptr);
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->angle, angle) )
+  if ( resH == CDI_UNDEFID )
+    gridptr->self = reshPut(gridptr, &gridOps);
+  else
     {
-      gridptr->isRotated = TRUE;
-      gridptr->angle = angle;
-      gridMark4Update(gridID);
+      gridptr->self = resH;
+      reshReplace(resH, gridptr, &gridOps);
     }
-}
-
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+  return gridptr;
+}
 
- at EndFunction
-*/
-int gridInqGMEnd(int gridID)
+static
+void gridInit(void)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  static bool gridInitialized = false;
+  if ( gridInitialized ) return;
+  gridInitialized = true;
 
-  return gridptr->nd;
+  const char *env = getenv("GRID_DEBUG");
+  if ( env ) GRID_Debug = atoi(env);
 }
 
-/*
- at Function
- at Title
+static
+void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
+  gridptrDup->self = CDI_UNDEFID;
+  if ( gridptrOrig->reference )
+    gridptrDup->reference = strdupx(gridptrOrig->reference);
+}
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-void gridDefGMEnd(int gridID, int nd)
+static
+grid_t *grid_copy_base(grid_t *gridptrOrig)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if (gridptr->nd != nd)
-    {
-      gridptr->nd = nd;
-      gridMark4Update(gridID);
-    }
+  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
+  return gridptrDup;
 }
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+unsigned cdiGridCount(void)
+{
+  return reshCountType(&gridOps);
+}
 
- at EndFunction
-*/
-int gridInqGMEni(int gridID)
+static inline
+void gridSetString(char *gridstrname, const char *name, size_t len)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
+  strncpy(gridstrname, name, len);
+  gridstrname[len - 1] = 0;
+}
 
-  return gridptr->ni;
+static inline
+void gridGetString(char *name, const char *gridstrname, size_t len)
+{
+  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
+  strncpy(name, gridstrname, len);
+  name[len - 1] = 0;
 }
 
-/*
- at Function
- at Title
+static inline
+void gridSetName(char *gridstrname, const char *name)
+{
+  strncpy(gridstrname, name, CDI_MAX_NAME);
+  gridstrname[CDI_MAX_NAME - 1] = 0;
+}
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-void gridDefGMEni(int gridID, int ni)
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  gridptr->type = gridtype;
+  gridptr->size = size;
 
-  if ( gridptr->ni != ni )
-    {
-      gridptr->ni = ni;
-      gridMark4Update(gridID);
-    }
-}
+  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
+  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;
 
-/*
- at Function
- at Title
+  switch (gridtype)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_TRAJECTORY:
+    case GRID_CURVILINEAR:
+    case GRID_UNSTRUCTURED:
+    case GRID_GME:
+      {
+        if ( gridtype == GRID_TRAJECTORY )
+          {
+            if ( !gridptr->x.name[0] ) gridSetName(gridptr->x.name, "tlon");
+            if ( !gridptr->y.name[0] ) gridSetName(gridptr->y.name, "tlat");
+          }
+        else
+          {
+            if ( !gridptr->x.name[0] ) gridSetName(gridptr->x.name, "lon");
+            if ( !gridptr->y.name[0] ) gridSetName(gridptr->y.name, "lat");
+          }
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+        if ( !gridptr->x.longname[0] ) gridSetName(gridptr->x.longname, "longitude");
+        if ( !gridptr->y.longname[0] ) gridSetName(gridptr->y.longname, "latitude");
 
- at EndFunction
-*/
-int gridInqGMEni2(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+        if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "degrees_east");
+        if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "degrees_north");
 
-  return gridptr->ni2;
-}
+        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
+        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
 
-/*
- at Function
- at Title
+        break;
+      }
+    case GRID_CHARXY:
+      {
+        if ( gridptr->x.cvals ) gridptr->x.stdname = xystdname_tab[grid_xystdname_char][0];
+        if ( gridptr->y.cvals ) gridptr->y.stdname = xystdname_tab[grid_xystdname_char][0];
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+        break;
+     }
+    case GRID_GENERIC:
+    case GRID_PROJECTION:
+      {
+        if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "x");
+        if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "y");
+        if ( gridtype == GRID_PROJECTION )
+          {
+            gridSetName(gridptr->mapname, "Projection");
 
- at EndFunction
-*/
-void gridDefGMEni2(int gridID, int ni2)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
+            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
 
-  if ( gridptr->ni2 != ni2 )
-    {
-      gridptr->ni2 = ni2;
-      gridMark4Update(gridID);
+            if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "m");
+            if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "m");
+          }
+        break;
+      }
     }
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-int gridInqGMEni3(int gridID)
+// used also in CDO
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
+    {
+      if ( xfirst >= xlast )
+        {
+          while ( xfirst >= xlast ) xlast += 360;
+          xinc = (xlast-xfirst)/(xsize);
+        }
+      else
+        {
+          xinc = (xlast-xfirst)/(xsize-1);
+        }
+    }
 
-  return gridptr->ni3;
+  for ( int i = 0; i < xsize; ++i )
+    xvals[i] = xfirst + i*xinc;
 }
 
-void gridDefGMEni3(int gridID, int ni3)
+static
+void calc_gaussgrid(double *restrict yvals, size_t ysize, double yfirst, double ylast)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  double *restrict yw = (double *) Malloc(ysize * sizeof(double));
+  gaussaw(yvals, yw, ysize);
+  Free(yw);
+  for (size_t i = 0; i < ysize; i++ )
+    yvals[i] = asin(yvals[i])/M_PI*180.0;
 
-  if ( gridptr->ni3 != ni3 )
+  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
     {
-      gridptr->ni3 = ni3;
-      gridMark4Update(gridID);
+      size_t yhsize = ysize/2;
+      for (size_t i = 0; i < yhsize; i++ )
+        {
+          double ytmp = yvals[i];
+          yvals[i] = yvals[ysize-i-1];
+          yvals[ysize-i-1] = ytmp;
+        }
     }
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridChangeType(int gridID, int gridtype)
+// used also in CDO
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( CDI_Debug )
-    Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
+  const double deleps = 0.002;
 
-  if (gridptr->type != gridtype)
+  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
     {
-      gridptr->type = gridtype;
-      gridMark4Update(gridID);
-    }
-}
+      if ( ysize > 2 )
+	{
+	  calc_gaussgrid(yvals, ysize, yfirst, ylast);
 
-static
-void grid_check_cyclic(grid_t *gridptr)
-{
-  gridptr->isCyclic = FALSE;
-  enum { numVertices = 4 };
-  size_t xsize = gridptr->xsize >= 0 ? (size_t)gridptr->xsize : 0,
-    ysize = gridptr->ysize >= 0 ? (size_t)gridptr->ysize : 0;
-  const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
-    (*xbounds)[numVertices]
-    = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
+	  if ( ! (IS_EQUAL(yfirst, 0) && IS_EQUAL(ylast, 0)) )
+	    if ( fabs(yvals[0] - yfirst) > deleps || fabs(yvals[ysize-1] - ylast) > deleps )
+	      {
+		double *restrict ytmp = NULL;
+		int nstart;
+                bool lfound = false;
+		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
+		ny -= ny%2;
+		if ( ny > ysize && ny < 4096 )
+		  {
+		    ytmp = (double *) Malloc((size_t)ny * sizeof (double));
+		    calc_gaussgrid(ytmp, ny, yfirst, ylast);
+                    {
+                      int i;
+                      for ( i = 0; i < (ny-ysize); i++ )
+                        if ( fabs(ytmp[i] - yfirst) < deleps ) break;
+                      nstart = i;
+                    }
 
-  if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
-    {
-      if ( xvals && xsize > 1 )
-        {
-          double xinc = xvals[1] - xvals[0];
-          if ( IS_EQUAL(xinc, 0) )
-            xinc = (xvals[xsize-1] - xvals[0])/(double)(xsize-1);
+		    lfound = (nstart+ysize-1) < ny
+                      && fabs(ytmp[nstart+ysize-1] - ylast) < deleps;
+                    if ( lfound )
+                      {
+                        for (int i = 0; i < ysize; i++) yvals[i] = ytmp[i+nstart];
+                      }
+		  }
 
-          double x0 = 2*xvals[xsize-1]-xvals[xsize-2]-360;
+		if ( !lfound )
+		  {
+		    Warning("Cannot calculate gaussian latitudes for lat1 = %g latn = %g!", yfirst, ylast);
+		    for (int i = 0; i < ysize; i++ ) yvals[i] = 0;
+		    yvals[0] = yfirst;
+		    yvals[ysize-1] = ylast;
+		  }
 
-          if ( IS_NOT_EQUAL(xvals[0], xvals[xsize-1]) )
-            if ( fabs(x0 - xvals[0]) < 0.01*xinc ) gridptr->isCyclic = TRUE;
+		if ( ytmp ) Free(ytmp);
+	      }
+	}
+      else
+        {
+          yvals[0] = yfirst;
+          yvals[ysize-1] = ylast;
         }
     }
-  else if ( gridptr->type == GRID_CURVILINEAR )
+  /*     else if ( gridtype == GRID_LONLAT || gridtype == GRID_GENERIC ) */
+  else
     {
-      if ( xvals && xsize > 1 )
+      if ( (! (fabs(yinc) > 0)) && ysize > 1 )
         {
-          size_t nc = 0;
-          for ( size_t j = 0; j < ysize; ++j )
-            {
-              size_t i1 = j*xsize,
-                i2 = j*xsize+1,
-                in = j*xsize+(xsize-1);
-              double val1 = xvals[i1],
-                val2 = xvals[i2],
-                valn = xvals[in];
-
-              double xinc = fabs(val2-val1);
-
-	      if ( val1 <    1 && valn > 300 ) val1 += 360;
-	      if ( valn <    1 && val1 > 300 ) valn += 360;
-	      if ( val1 < -179 && valn > 120 ) val1 += 360;
-	      if ( valn < -179 && val1 > 120 ) valn += 360;
-              if ( fabs(valn-val1) > 180 ) val1 += 360;
-
-              double x0 = valn + copysign(xinc, val1 - valn);
+          if ( IS_EQUAL(yfirst, ylast) && IS_NOT_EQUAL(yfirst, 0) ) ylast *= -1;
 
-              nc += fabs(x0-val1) < 0.5*xinc;
+          if ( yfirst > ylast )
+            yinc = (yfirst-ylast)/(ysize-1);
+          else if ( yfirst < ylast )
+            yinc = (ylast-yfirst)/(ysize-1);
+          else
+            {
+              if ( ysize%2 != 0 )
+                {
+                  yinc = 180.0/(ysize-1);
+                  yfirst = -90;
+                }
+              else
+                {
+                  yinc = 180.0/ysize;
+                  yfirst = -90 + yinc/2;
+                }
             }
-          gridptr->isCyclic = nc > ysize/2 ? TRUE : FALSE;
         }
 
-      if ( xbounds && xsize > 1 )
-	{
-          bool isCyclic = true;
-	  for ( size_t j = 0; j < ysize; ++j )
-	    {
-	      size_t i1 = j*xsize,
-                i2 = j*xsize+(xsize-1);
-	      for (size_t k1 = 0; k1 < numVertices; ++k1 )
-		{
-		  double val1 = xbounds[i1][k1];
-		  for (size_t k2 = 0; k2 < numVertices; ++k2 )
-		    {
-		      double val2 = xbounds[i2][k2];
-
-		      if ( val1 <    1 && val2 > 300 ) val1 += 360;
-		      if ( val2 <    1 && val1 > 300 ) val2 += 360;
-		      if ( val1 < -179 && val2 > 120 ) val1 += 360;
-		      if ( val2 < -179 && val1 > 120 ) val2 += 360;
-                      if ( fabs(val2-val1) > 180 ) val1 += 360;
+      if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;
 
-		      if ( fabs(val1-val2) < 0.001 )
-                        goto foundCloseVertices;
-		    }
-		}
-              /* all vertices more than 0.001 degrees apart */
-              isCyclic = false;
-              break;
-              foundCloseVertices:
-              ;
-	    }
-          gridptr->isCyclic = (int) isCyclic;
-	}
+      for (int i = 0; i < ysize; i++ )
+        yvals[i] = yfirst + i*yinc;
     }
+  /*
+    else
+    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
+  */
 }
 
+/*
+ at Function  gridCreate
+ at Title     Create a horizontal Grid
 
-int gridIsCircular(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+ at Prototype int gridCreate(int gridtype, size_t size)
+ at Parameter
+    @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
+                     The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
+                     @func{GRID_LONLAT}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL},
+                     @func{GRID_GME}, @func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
+    @Item  size      Number of gridpoints.
 
-  if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
+ at Description
+The function @func{gridCreate} creates a horizontal Grid.
 
-  return gridptr->isCyclic;
-}
+ at Result
+ at func{gridCreate} returns an identifier to the Grid.
 
+ at Example
+Here is an example using @func{gridCreate} to create a regular lon/lat Grid:
 
-int gridIsRotated(int gridID)
+ at Source
+   ...
+#define  nlon  12
+#define  nlat   6
+   ...
+double lons[nlon] = {0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330};
+double lats[nlat] = {-75, -45, -15, 15, 45, 75};
+int gridID;
+   ...
+gridID = gridCreate(GRID_LONLAT, nlon*nlat);
+gridDefXsize(gridID, nlon);
+gridDefYsize(gridID, nlat);
+gridDefXvals(gridID, lons);
+gridDefYvals(gridID, lats);
+   ...
+ at EndSource
+ at EndFunction
+*/
+int gridCreate(int gridtype, size_t size)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( CDI_Debug ) Message("gridtype=%s  size=%zu", gridNamePtr(gridtype), size);
 
-  return gridptr->isRotated;
-}
+  gridInit();
 
-static
-bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
-{
-  bool differ = false;
+  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
+  if ( ! gridptr ) Error("No memory");
 
-  int xsizeTest = gridTest->xsize, ysizeTest = gridTest->ysize;
-  if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
-    {
-      const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
-        *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
+  int gridID = gridptr->self;
 
-      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
-	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
-	  {
-	    differ = true;
-	    break;
-	  }
-    }
+  if ( CDI_Debug ) Message("gridID: %d", gridID);
 
-  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
-    {
-      const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
-        *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
-      for ( size_t i = 0; i < (size_t)ysizeTest; ++i )
-	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
-	  {
-	    differ = true;
-	    break;
-	  }
-    }
+  cdiGridTypeInit(gridptr, gridtype, size);
 
-  return differ;
+  return gridID;
 }
 
 static
-bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
+void gridDestroyKernel( grid_t * gridptr )
 {
-  int gridsize = gridTest->size;
-  bool differ
-    = ((gridTest->xvals == NULL) ^ (gridRef->xvals == NULL))
-    || ((gridTest->yvals == NULL) ^ (gridRef->yvals == NULL));
-
-  typedef double (*inqVal)(grid_t *grid, int index);
-  inqVal inqXValRef = gridRef->vtable->inqXVal,
-    inqYValRef = gridRef->vtable->inqXVal,
-    inqXValTest = gridTest->vtable->inqXVal,
-    inqYValTest = gridTest->vtable->inqYVal;
+  xassert ( gridptr );
 
-  if ( !differ && gridTest->xvals )
-    differ = fabs(inqXValTest(gridTest, 0) - inqXValRef(gridRef, 0)) > 1.e-9
-      || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
+  int id = gridptr->self;
 
-  if ( !differ && gridTest->yvals )
-    differ = fabs(inqYValTest(gridTest, 0) - inqYValRef(gridRef, 0)) > 1.e-9
-      || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
+  grid_free_components(gridptr);
+  Free( gridptr );
 
-  return differ;
+  reshRemove ( id, &gridOps );
 }
 
-static
-bool gridCompare(int gridID, const grid_t *grid)
-{
-  bool differ = true;
-  grid_t *gridRef = gridID2Ptr(gridID);
-
-  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
-    {
-      if ( grid->size == gridRef->size )
-	{
-	  differ = false;
-	  if ( grid->type == GRID_LONLAT )
-	    {
-	      /*
-	      printf("gridID      %d\n", gridID);
-	      printf("grid.xdef   %d\n", grid->xdef);
-	      printf("grid.ydef   %d\n", grid->ydef);
-	      printf("grid.xsize  %d\n", grid->xsize);
-	      printf("grid.ysize  %d\n", grid->ysize);
-	      printf("grid.xfirst %f\n", grid->xfirst);
-	      printf("grid.yfirst %f\n", grid->yfirst);
-	      printf("grid.xfirst %f\n", gridInqXval(gridID, 0));
-	      printf("grid.yfirst %f\n", gridInqYval(gridID, 0));
-	      printf("grid.xinc   %f\n", grid->xinc);
-	      printf("grid.yinc   %f\n", grid->yinc);
-	      printf("grid.xinc   %f\n", gridInqXinc(gridID));
-	      printf("grid.yinc   %f\n", gridInqYinc(gridID));
-	      */
-	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
-		{
-		  if ( grid->xdef == 2 && grid->ydef == 2 )
-		    {
-		      if ( ! (IS_EQUAL(grid->xfirst, 0) && IS_EQUAL(grid->xlast, 0) && IS_EQUAL(grid->xinc, 0)) &&
-			   ! (IS_EQUAL(grid->yfirst, 0) && IS_EQUAL(grid->ylast, 0) && IS_EQUAL(grid->yinc, 0)) &&
-			   IS_NOT_EQUAL(grid->xfirst, grid->xlast) && IS_NOT_EQUAL(grid->yfirst, grid->ylast) )
-			{
-			  if ( IS_NOT_EQUAL(grid->xfirst, gridInqXval(gridID, 0)) ||
-			       IS_NOT_EQUAL(grid->yfirst, gridInqYval(gridID, 0)))
-			    {
-			      differ = true;
-			    }
-			  if ( !differ && fabs(grid->xinc) > 0 &&
-			       fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000))
-			    {
-			      differ = true;
-			    }
-			  if ( !differ && fabs(grid->yinc) > 0 &&
-			       fabs(fabs(grid->yinc) - fabs(gridRef->yinc)) > fabs(grid->yinc/1000))
-			    {
-			      differ = true;
-			    }
-			}
-		    }
-		  else if ( grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
-		}
-	      else
-		differ = true;
-	    }
-	  else if ( grid->type == GRID_GENERIC )
-	    {
-	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
-		{
-		  if ( grid->xdef == 1 && grid->ydef == 1
-                       && grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
-		}
-	      else if ( (grid->ysize == 0 || grid->ysize == 1) &&
-			grid->xsize == gridRef->xsize*gridRef->ysize )
-		{
-		}
-	      else
-		differ = true;
-	    }
-	  else if ( grid->type == GRID_GAUSSIAN )
-	    {
-	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
-		{
-		  if ( grid->xdef == 2 && grid->ydef == 2 )
-		    {
-		      if ( ! (IS_EQUAL(grid->xfirst, 0) && IS_EQUAL(grid->xlast, 0) && IS_EQUAL(grid->xinc, 0)) &&
-			   ! (IS_EQUAL(grid->yfirst, 0) && IS_EQUAL(grid->ylast, 0)) )
-			if ( fabs(grid->xfirst - gridInqXval(gridID, 0)) > 0.0015 ||
-			     fabs(grid->yfirst - gridInqYval(gridID, 0)) > 0.0015 ||
-			     (fabs(grid->xinc)>0 && fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000)) )
-			  {
-			    differ = true;
-			  }
-		    }
-		  else if ( grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
-		}
-	      else
-		differ = true;
-	    }
-	  else if ( grid->type == GRID_CURVILINEAR )
-	    {
-	      /*
-	      printf("gridID      %d\n", gridID);
-	      printf("grid.xsize  %d\n", grid->xsize);
-	      printf("grid.ysize  %d\n", grid->ysize);
-	      printf("grid.xfirst %f\n", grid->xvals[0]);
-	      printf("grid.yfirst %f\n", grid->yvals[0]);
-	      printf("grid xfirst %f\n", gridInqXval(gridID, 0));
-	      printf("grid yfirst %f\n", gridInqYval(gridID, 0));
-	      printf("grid.xlast  %f\n", grid->xvals[grid->size-1]);
-	      printf("grid.ylast  %f\n", grid->yvals[grid->size-1]);
-	      printf("grid xlast  %f\n", gridInqXval(gridID, grid->size-1));
-	      printf("grid ylast  %f\n", gridInqYval(gridID, grid->size-1));
-	      printf("grid.nv     %d\n", grid->nvertex);
-	      printf("grid nv     %d\n", gridInqNvertex(gridID));
-	      */
-	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
-                differ = gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
-	    }
-	  else if ( grid->type == GRID_UNSTRUCTURED )
-	    {
-              /* FIXME: not octet 0 but octet 7 is guaranteed  non-zero
-               * for any non-NULL UUID */
-              differ = differ || ( gridRef->uuid[0] && grid->uuid[0] && memcmp(gridRef->uuid, grid->uuid, CDI_UUID_SIZE) != 0 );
+/*
+ at Function  gridDestroy
+ at Title     Destroy a horizontal Grid
 
-              if ( !differ &&
-                   ((grid->xvals == NULL) ^ (gridRef->xvals == NULL)) &&
-                   ((grid->yvals == NULL) ^ (gridRef->yvals == NULL)) )
-                {
-                  int nvertexA, nvertexB, numberA, numberB;
-                  differ = ( (nvertexA = grid->nvertex)
-                             && (nvertexB = gridRef->nvertex)
-                             && (nvertexA != nvertexB) )
-                    || (numberA = grid->number, numberB = gridRef->number,
-                        ( (numberA)
-                          && numberB
-                          && (numberA != numberB) )
-                        || ( (numberA && numberB)
-                             && (grid->position) != (gridRef->position) ) );
-                }
-              else if ( !differ )
-                {
-                  differ = grid->nvertex != gridRef->nvertex
-                    || grid->number != gridRef->number
-                    || (grid->number > 0 && grid->position != gridRef->position)
-                    || gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
-                }
-              }
-	}
-    }
+ at Prototype void gridDestroy(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
 
-  return differ;
+ at EndFunction
+*/
+void gridDestroy(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->destroy(gridptr);
+}
+
+static
+void gridDestroyP(void * gridptr)
+{
+  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
 }
 
 
-int gridCompareP ( void * gridptr1, void * gridptr2 )
+const char *gridNamePtr(int gridtype)
 {
-  grid_t * g1 = ( grid_t * ) gridptr1;
-  grid_t * g2 = ( grid_t * ) gridptr2;
-  enum { equal = 0,
-         differ = -1 };
-  int i, size;
+  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
 
-  xassert ( g1 );
-  xassert ( g2 );
+  const char *name = (gridtype >= 0 && gridtype < size) ? Grids[gridtype] : Grids[GRID_GENERIC];
 
-  if ( g1->type          != g2->type         ) return differ;
-  if ( g1->prec          != g2->prec         ) return differ;
-  if ( g1->lcc_projflag  != g2->lcc_projflag ) return differ;
-  if ( g1->lcc_scanflag  != g2->lcc_scanflag ) return differ;
-  if ( g1->lcc_defined   != g2->lcc_defined  ) return differ;
-  if ( g1->lcc2_defined  != g2->lcc2_defined ) return differ;
-  if ( g1->laea_defined  != g2->laea_defined ) return differ;
-  if ( g1->isCyclic      != g2->isCyclic     ) return differ;
-  if ( g1->isRotated     != g2->isRotated    ) return differ;
-  if ( g1->xdef          != g2->xdef         ) return differ;
-  if ( g1->ydef          != g2->ydef         ) return differ;
-  if ( g1->nd            != g2->nd           ) return differ;
-  if ( g1->ni            != g2->ni           ) return differ;
-  if ( g1->ni2           != g2->ni2          ) return differ;
-  if ( g1->ni3           != g2->ni3          ) return differ;
-  if ( g1->number        != g2->number       ) return differ;
-  if ( g1->position      != g2->position     ) return differ;
-  if ( g1->trunc         != g2->trunc        ) return differ;
-  if ( g1->nvertex       != g2->nvertex      ) return differ;
-  if ( g1->nrowlon       != g2->nrowlon      ) return differ;
-  if ( g1->size          != g2->size         ) return differ;
-  if ( g1->xsize         != g2->xsize        ) return differ;
-  if ( g1->ysize         != g2->ysize        ) return differ;
-  if ( g1->lcomplex      != g2->lcomplex     ) return differ;
+  return name;
+}
 
-  if ( IS_NOT_EQUAL(g1->xfirst        , g2->xfirst)        ) return differ;
-  if ( IS_NOT_EQUAL(g1->yfirst	      , g2->yfirst)        ) return differ;
-  if ( IS_NOT_EQUAL(g1->xlast         , g2->xlast)         ) return differ;
-  if ( IS_NOT_EQUAL(g1->ylast         , g2->ylast)         ) return differ;
-  if ( IS_NOT_EQUAL(g1->xinc	      , g2->xinc)          ) return differ;
-  if ( IS_NOT_EQUAL(g1->yinc	      , g2->yinc)          ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_originLon , g2->lcc_originLon) ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_originLat , g2->lcc_originLat) ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_lonParY   , g2->lcc_lonParY)   ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_lat1      , g2->lcc_lat1)      ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_lat2      , g2->lcc_lat2)      ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_xinc      , g2->lcc_xinc)      ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc_yinc      , g2->lcc_yinc)      ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc2_lon_0    , g2->lcc2_lon_0)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc2_lat_0    , g2->lcc2_lat_0)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc2_lat_1    , g2->lcc2_lat_1)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc2_lat_2    , g2->lcc2_lat_2)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->lcc2_a        , g2->lcc2_a)        ) return differ;
-  if ( IS_NOT_EQUAL(g1->laea_lon_0    , g2->laea_lon_0)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->laea_lat_0    , g2->laea_lat_0)    ) return differ;
-  if ( IS_NOT_EQUAL(g1->laea_a        , g2->laea_a)        ) return differ;
-  if ( IS_NOT_EQUAL(g1->xpole         , g2->xpole)         ) return differ;
-  if ( IS_NOT_EQUAL(g1->ypole         , g2->ypole)         ) return differ;
-  if ( IS_NOT_EQUAL(g1->angle         , g2->angle)         ) return differ;
 
-  const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
-    *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
-  if ( g1_xvals )
-    {
-      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
-        size = g1->size;
-      else
-        size = g1->xsize;
-      xassert ( size );
+void gridName(int gridtype, char *gridname)
+{
+  strcpy(gridname, gridNamePtr(gridtype));
+}
 
-      if ( !g2_xvals ) return differ;
+static
+void *grid_key_to_ptr(grid_t *gridptr, int key)
+{
+  void *keyptr = NULL;
 
-      for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
+  switch (key)
+    {
+    case CDI_KEY_XNAME:      keyptr = (void*)gridptr->x.name; break;
+    case CDI_KEY_XLONGNAME:  keyptr = (void*)gridptr->x.longname; break;
+    case CDI_KEY_XUNITS:     keyptr = (void*)gridptr->x.units; break;
+    case CDI_KEY_YNAME:      keyptr = (void*)gridptr->y.name; break;
+    case CDI_KEY_YLONGNAME:  keyptr = (void*)gridptr->y.longname; break;
+    case CDI_KEY_YUNITS:     keyptr = (void*)gridptr->y.units; break;
+    case CDI_KEY_XDIMNAME:   keyptr = (void*)gridptr->x.dimname; break;
+    case CDI_KEY_YDIMNAME:   keyptr = (void*)gridptr->y.dimname; break;
+    case CDI_KEY_VDIMNAME:   keyptr = (void*)gridptr->vdimname; break;
+    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapname; break;
+    case CDI_KEY_MAPNAME:    keyptr = (void*)gridptr->mapping; break;
     }
-  else if ( g2_xvals )
-    return differ;
 
-  const double *restrict g1_yvals = g1->vtable->inqYValsPtr(g1),
-    *restrict g2_yvals = g2->vtable->inqYValsPtr(g2);
-  if ( g1_yvals )
-    {
-      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
-	size = g1->size;
-      else
-	size = g1->ysize;
-      xassert ( size );
+  return keyptr;
+}
 
-      if ( !g2_yvals ) return differ;
+/*
+ at Function  cdiGridDefKeyStr
+ at Title     Define a CDI grid string value from a key
 
-      for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
-    }
-  else if ( g2_yvals )
-    return differ;
+ at Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  key      The key to be searched
+    @Item  size     The allocated length of the string on input
+    @Item  mesg     The address of a string where the data will be read
 
-  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
-    *restrict g2_area = g2->vtable->inqAreaPtr(g2);
-  if ( g1_area )
-    {
-      xassert ( g1->size );
+ at Description
+The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
 
-      if ( !g2_area ) return differ;
+ at Result
+ at func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
 
-      for ( i = 0; i < g1->size; i++ )
-	if ( IS_NOT_EQUAL(g1_area[i], g2_area[i]) ) return differ;
+ at EndFunction
+*/
+int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
+{
+  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
+
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL )
+    {
+      Warning("CDI grid string key %d not supported!", key);
+      return -1;
     }
-  else if ( g2_area )
-    return differ;
 
-  {
-    const double *restrict g1_xbounds, *restrict g2_xbounds;
-    if ( (g1_xbounds = g1->vtable->inqXBoundsPtr(g1)) )
-      {
-        xassert ( g1->nvertex );
-        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-          size = g1->nvertex * g1->size;
-        else
-          size = g1->nvertex * g1->xsize;
-        xassert ( size );
+  gridSetString(keyptr, mesg, (size_t)size);
+  gridMark4Update(gridID);
 
-        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
+  return 0;
+}
 
-        for ( i = 0; i < size; i++ )
-          if ( IS_NOT_EQUAL(g1_xbounds[i], g2_xbounds[i]) ) return differ;
-      }
-    else if ( g2->vtable->inqXBoundsPtr(g2) )
-      return differ;
-  }
+/*
+ at Function  cdiGridInqKeyStr
+ at Title     Get a CDI grid string value from a key
 
-  {
-    const double *restrict g1_ybounds, *restrict g2_ybounds;
-    if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
-      {
-        xassert ( g1->nvertex );
-        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
-          size = g1->nvertex * g1->size;
-        else
-          size = g1->nvertex * g1->ysize;
-        xassert ( size );
+ at Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  key      The key to be searched.
+    @Item  size     The allocated length of the string on input.
+    @Item  mesg     The address of a string where the data will be retrieved.
+                    The caller must allocate space for the returned string.
+                    The maximum possible length, in characters, of the string
+                    is given by the predefined constant @func{CDI_MAX_NAME}.
 
-        if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
+ at Description
+The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
 
-        for ( i = 0; i < size; i++ )
-          if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
-      }
-    else if ( g2->vtable->inqYBoundsPtr(g2) )
-      return differ;
-  }
+ at Result
+ at func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
 
-  if (strcmp(g1->xname, g2->xname)) return differ;
-  if (strcmp(g1->yname, g2->yname)) return differ;
-  if (strcmp(g1->xlongname, g2->xlongname)) return differ;
-  if (strcmp(g1->ylongname, g2->ylongname)) return differ;
-  if (g1->xstdname != g2->xstdname) return differ;
-  if (g1->ystdname != g2->ystdname) return differ;
-  if (strcmp(g1->xunits, g2->xunits)) return differ;
-  if (strcmp(g1->yunits, g2->yunits)) return differ;
+ at EndFunction
+*/
+int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
+{
+  if ( size < 1 || mesg == NULL ) return -1;
 
-  if ( g1->reference )
+  grid_t *gridptr = grid_to_pointer(gridID);
+  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL)
     {
-      if ( !g2->reference ) return differ;
-      if ( strcmp(g1->reference, g2->reference) ) return differ;
+      Warning("CDI grid string key %d not supported!", key);
+      return -1;
     }
-  else if ( g2->reference )
-    return differ;
 
-  if ( g1->mask )
-    {
-      xassert ( g1->size );
-      if ( !g2->mask ) return differ;
-      if ( memcmp ( g1->mask, g2->mask, (size_t)g1->size * sizeof(mask_t)) ) return differ;
-    }
-  else if ( g2->mask )
-    return differ;
+  gridGetString(mesg, keyptr, (size_t)size);
 
-  if ( g1->mask_gme )
-    {
-      xassert ( g1->size );
-      if ( !g2->mask_gme ) return differ;
-      if ( memcmp ( g1->mask_gme, g2->mask_gme, (size_t)g1->size * sizeof(mask_t)) ) return differ;
-    }
-  else if ( g2->mask_gme )
-    return differ;
+  return 0;
+}
 
-  if (memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE))
-    return differ;
+/*
+ at Function  gridDefXname
+ at Title     Define the name of a X-axis
 
-  return equal;
+ at Prototype void gridDefXname(int gridID, const char *name)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  name     Name of the X-axis.
+
+ at Description
+The function @func{gridDefXname} defines the name of a X-axis.
+
+ at EndFunction
+*/
+void gridDefXname(int gridID, const char *xname)
+{
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
 }
 
-static void gridComplete(grid_t *grid)
+/*
+ at Function  gridDefXlongname
+ at Title     Define the longname of a X-axis
+
+ at Prototype void gridDefXlongname(int gridID, const char *longname)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  longname Longname of the X-axis.
+
+ at Description
+The function @func{gridDefXlongname} defines the longname of a X-axis.
+
+ at EndFunction
+*/
+void gridDefXlongname(int gridID, const char *xlongname)
 {
-  int gridID = grid->self;
-  gridDefPrec(gridID, grid->prec);
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
+}
 
-  int gridtype = grid->type;
-  switch (gridtype)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_UNSTRUCTURED:
-    case GRID_CURVILINEAR:
-    case GRID_GENERIC:
-    case GRID_LCC:
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
-    case GRID_PROJECTION:
-      {
-	if ( grid->xsize > 0 ) gridDefXsize(gridID, grid->xsize);
-	if ( grid->ysize > 0 ) gridDefYsize(gridID, grid->ysize);
+/*
+ at Function  gridDefXunits
+ at Title     Define the units of a X-axis
 
-        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
+ at Prototype void gridDefXunits(int gridID, const char *units)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  units    Units of the X-axis.
 
-	if ( grid->nvertex > 0 )
-	  gridDefNvertex(gridID, grid->nvertex);
+ at Description
+The function @func{gridDefXunits} defines the units of a X-axis.
 
-	if ( grid->xdef == 2 )
-	  {
-            assert(gridtype != GRID_UNSTRUCTURED
-                   && gridtype != GRID_CURVILINEAR);
-	    double *xvals
-              = (double *) Malloc((size_t)grid->xsize * sizeof (double));
-	    gridGenXvals(grid->xsize, grid->xfirst, grid->xlast, grid->xinc, xvals);
-	    grid->xvals = xvals;
-	    /*
-	    gridDefXinc(gridID, grid->xinc);
-	    */
-	  }
+ at EndFunction
+*/
+void gridDefXunits(int gridID, const char *xunits)
+{
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+}
 
-	if ( grid->ydef == 2 )
-	  {
-            assert(gridtype != GRID_UNSTRUCTURED
-                   && gridtype != GRID_CURVILINEAR);
-	    double *yvals
-              = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-	    grid->yvals = yvals;
-	    /*
-	    gridDefYinc(gridID, grid->yinc);
-	    */
-	  }
+/*
+ at Function  gridDefYname
+ at Title     Define the name of a Y-axis
 
-	if ( grid->isRotated )
-	  {
-	    gridDefXname(gridID, "rlon");
-	    gridDefYname(gridID, "rlat");
-	    gridDefXlongname(gridID, "longitude in rotated pole grid");
-	    gridDefYlongname(gridID, "latitude in rotated pole grid");
-            grid->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
-            grid->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
-	    gridDefXunits(gridID, "degrees");
-	    gridDefYunits(gridID, "degrees");
-
-	    gridDefXpole(gridID, grid->xpole);
-	    gridDefYpole(gridID, grid->ypole);
-	    gridDefAngle(gridID, grid->angle);
-	  }
+ at Prototype void gridDefYname(int gridID, const char *name)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  name     Name of the Y-axis.
 
-        switch (gridtype)
-          {
-          case GRID_LAEA:
-            gridDefLaea(gridID, grid->laea_a, grid->laea_lon_0, grid->laea_lat_0);
-            break;
-          case GRID_LCC2:
-            gridDefLcc2(gridID, grid->lcc2_a, grid->lcc2_lon_0, grid->lcc2_lat_0, grid->lcc2_lat_1, grid->lcc2_lat_2);
-            break;
-          case GRID_LCC:
-            gridDefLCC(gridID, grid->lcc_originLon, grid->lcc_originLat, grid->lcc_lonParY,
-                       grid->lcc_lat1, grid->lcc_lat2, grid->lcc_xinc, grid->lcc_yinc,
-                       grid->lcc_projflag, grid->lcc_scanflag);
-            break;
-          case GRID_UNSTRUCTURED:
-            {
-              int number = grid->number;
-              int position = grid->position >= 0 ? grid->position : 0;
-              if ( number > 0 )
-                {
-                  gridDefNumber(gridID, number);
-                  gridDefPosition(gridID, position);
-                }
-            }
-            break;
-	  }
+ at Description
+The function @func{gridDefYname} defines the name of a Y-axis.
 
-	break;
-      }
-    case GRID_GAUSSIAN_REDUCED:
-      {
-	gridDefNP(gridID, grid->np);
-	gridDefYsize(gridID, grid->ysize);
-        if ( grid->xdef == 2 )
-          {
-            double xvals[2] = { grid->xfirst, grid->xlast };
-            gridDefXvals(gridID, xvals);
-          }
+ at EndFunction
+*/
+void gridDefYname(int gridID, const char *yname)
+{
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
+}
 
-        if ( grid->ydef == 2 )
-	  {
-	    double *yvals
-              = (double *) Malloc((size_t)grid->ysize * sizeof (double));
-	    gridGenYvals(gridtype, grid->ysize, grid->yfirst, grid->ylast, grid->yinc, yvals);
-            grid->yvals = yvals;
-	    /*
-	    gridDefYinc(gridID, grid->yinc);
-	    */
-	  }
-	break;
-      }
-    case GRID_SPECTRAL:
-      {
-        gridDefTrunc(gridID, grid->trunc);
-        if ( grid->lcomplex ) gridDefComplexPacking(gridID, 1);
-        break;
-      }
-    case GRID_FOURIER:
-      {
-	gridDefTrunc(gridID, grid->trunc);
-	break;
-      }
-    case GRID_GME:
-      {
-        gridDefGMEnd(gridID, grid->nd);
-        gridDefGMEni(gridID, grid->ni);
-        gridDefGMEni2(gridID, grid->ni2);
-        gridDefGMEni3(gridID, grid->ni3);
-        break;
-      }
-      /*
-    case GRID_GENERIC:
-      {
-        if ( grid->xsize > 0 && grid->ysize > 0 )
-          {
-            gridDefXsize(gridID, grid->xsize);
-            gridDefYsize(gridID, grid->ysize);
-            if ( grid->xvals ) gridDefXvals(gridID, grid->xvals);
-            if ( grid->yvals ) gridDefYvals(gridID, grid->yvals);
-          }
-        break;
-      }
-      */
-    case GRID_TRAJECTORY:
-      {
-        gridDefXsize(gridID, 1);
-        gridDefYsize(gridID, 1);
-        break;
-      }
-    default:
-      {
-	Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
-	break;
-      }
-    }
+/*
+ at Function  gridDefYlongname
+ at Title     Define the longname of a Y-axis
+
+ at Prototype void gridDefYlongname(int gridID, const char *longname)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  longname Longname of the Y-axis.
 
-  grid->xname[CDI_MAX_NAME - 1] = 0;
-  grid->xlongname[CDI_MAX_NAME - 1] = 0;
-  grid->xunits[CDI_MAX_NAME - 1] = 0;
-  grid->yname[CDI_MAX_NAME - 1] = 0;
-  grid->ylongname[CDI_MAX_NAME - 1] = 0;
-  grid->yunits[CDI_MAX_NAME - 1] = 0;
+ at Description
+The function @func{gridDefYlongname} defines the longname of a Y-axis.
+
+ at EndFunction
+*/
+void gridDefYlongname(int gridID, const char *ylongname)
+{
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
 }
 
-#define GRID_STR_SERIALIZE(gridP) { gridP->xdimname, gridP->ydimname,  \
-    gridP->vdimname, gridP->xname, gridP->yname,  \
-    gridP->xlongname, gridP->ylongname, \
-    gridP->xunits, gridP->yunits }
+/*
+ at Function  gridDefYunits
+ at Title     Define the units of a Y-axis
 
-int gridGenerate(const grid_t *grid)
+ at Prototype void gridDefYunits(int gridID, const char *units)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  units    Units of the Y-axis.
+
+ at Description
+The function @func{gridDefYunits} defines the units of a Y-axis.
+
+ at EndFunction
+*/
+void gridDefYunits(int gridID, const char *yunits)
 {
-  int gridtype = grid->type;
-  int gridID = gridCreate(gridtype, grid->size);
-  grid_t *restrict gridptr = gridID2Ptr(gridID);
-  gridptr->prec = grid->prec;
-  gridptr->xsize = grid->xsize;
-  gridptr->ysize = grid->ysize;
-  gridptr->np = grid->np;
-  gridptr->nvertex = grid->nvertex;
-  gridptr->xdef = grid->xdef;
-  int valdef_group1 = 0;
-  static const int valdef_group1_tab[] = {
-    GRID_LONLAT, GRID_GAUSSIAN, GRID_UNSTRUCTURED, GRID_CURVILINEAR,
-    GRID_GENERIC, GRID_LCC, GRID_LCC2, GRID_SINUSOIDAL, GRID_LAEA,
-    GRID_PROJECTION
-  };
-  for ( size_t i = 0; i < sizeof (valdef_group1_tab) / sizeof (valdef_group1_tab[0]); ++i)
-    valdef_group1 |= (gridtype == valdef_group1_tab[i]);
-  if ( valdef_group1 && grid->xdef == 1 )
-    {
-      gridDefXvals(gridID, grid->xvals);
-      if ( grid->xbounds )
-        gridDefXbounds(gridID, grid->xbounds);
-    }
-  gridptr->xfirst = grid->xfirst;
-  gridptr->xlast = grid->xlast;
-  gridptr->xinc = grid->xinc;
-  gridptr->ydef = grid->ydef;
-  if ( (valdef_group1 || gridtype == GRID_GAUSSIAN_REDUCED) && grid->ydef == 1)
-    {
-      gridDefYvals(gridID, grid->yvals);
-      if ( grid->ybounds )
-        gridDefYbounds(gridID, grid->ybounds);
-    }
-  gridptr->yfirst = grid->yfirst;
-  gridptr->ylast = grid->ylast;
-  gridptr->yinc = grid->yinc;
-  gridptr->isRotated = grid->isRotated;
-  gridptr->xpole = grid->xpole;
-  gridptr->ypole = grid->ypole;
-  gridptr->angle = grid->angle;
-  if ( valdef_group1 && grid->area)
-    gridDefArea(gridID, grid->area);
-  gridptr->laea_a = grid->laea_a;
-  gridptr->laea_lon_0 = grid->laea_lon_0;
-  gridptr->laea_lat_0 = grid->laea_lat_0;
-  gridptr->lcc2_a = grid->lcc2_a;
-  gridptr->lcc2_lon_0 = grid->lcc2_lon_0;
-  gridptr->lcc2_lat_0 = grid->lcc2_lat_0;
-  gridptr->lcc2_lat_1 = grid->lcc2_lat_1;
-  gridptr->lcc2_lat_2 = grid->lcc2_lat_2;
-  gridptr->lcc_originLon = grid->lcc_originLon;
-  gridptr->lcc_originLat = grid->lcc_originLat;
-  gridptr->lcc_lonParY = grid->lcc_lonParY;
-  gridptr->lcc_lat1 = grid->lcc_lat1;
-  gridptr->lcc_lat2 = grid->lcc_lat2;
-  gridptr->lcc_xinc = grid->lcc_xinc;
-  gridptr->lcc_yinc = grid->lcc_yinc;
-  gridptr->lcc_projflag = grid->lcc_projflag;
-  gridptr->lcc_scanflag = grid->lcc_scanflag;
-  gridptr->number = grid->number;
-  gridptr->position = grid->position;
-  memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE);
-  if ( gridtype == GRID_UNSTRUCTURED && grid->reference )
-    gridDefReference(gridID, grid->reference);
-  if ( gridtype == GRID_PROJECTION )
-    gridptr->name = strdup(grid->name);
-  if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    gridDefRowlon(gridID, grid->ysize, grid->rowlon);
-  gridptr->trunc = grid->trunc;
-  gridptr->lcomplex = grid->lcomplex;
-  gridptr->nd = grid->nd;
-  gridptr->ni = grid->ni;
-  gridptr->ni2 = grid->ni2;
-  gridptr->ni3 = grid->ni3;
-  const char *grid_str_tab[] = GRID_STR_SERIALIZE(grid);
-  char *gridptr_str_tab[] = GRID_STR_SERIALIZE(gridptr);
-  for (size_t i = 0; i < sizeof (grid_str_tab) / sizeof (grid_str_tab[0]); ++i)
-    if ( grid_str_tab[i][0] )
-      memcpy(gridptr_str_tab[i], grid_str_tab[i], CDI_MAX_NAME);
-  gridComplete(gridptr);
-  return gridID;
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
-static void
-grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+/*
+ at Function  gridInqXname
+ at Title     Get the name of a X-axis
+
+ at Prototype void gridInqXname(int gridID, char *name)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  name     Name of the X-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+
+ at Description
+The function @func{gridInqXname} returns the name of a X-axis.
+
+ at Result
+ at func{gridInqXname} returns the name of the X-axis to the parameter name.
+
+ at EndFunction
+*/
+void gridInqXname(int gridID, char *xname)
 {
-  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
-  size_t gridsize = (size_t)gridptrOrig->size;
-  int gridtype = gridptrOrig->type;
-  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
-  if ( nrowlon )
-    {
-      gridptrDup->rowlon = (int*) Malloc(nrowlon * sizeof(int));
-      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
-    }
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
+}
 
-  if ( gridptrOrig->xvals != NULL )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+/*
+ at Function  gridInqXlongname
+ at Title     Get the longname of a X-axis
 
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
-    }
+ at Prototype void gridInqXlongname(int gridID, char *longname)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  longname Longname of the X-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
 
-  if ( gridptrOrig->yvals != NULL )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
+ at Description
+The function @func{gridInqXlongname} returns the longname of a X-axis.
 
-      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
-    }
+ at Result
+ at func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
 
-  if ( gridptrOrig->xbounds != NULL )
-    {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
-        * (size_t)gridptrOrig->nvertex;
+ at EndFunction
+*/
+void gridInqXlongname(int gridID, char *xlongname)
+{
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
+}
 
-      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
-    }
+/*
+ at Function  gridInqXunits
+ at Title     Get the units of a X-axis
 
-  if ( gridptrOrig->ybounds != NULL )
-    {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
-        * (size_t)gridptrOrig->nvertex;
+ at Prototype void gridInqXunits(int gridID, char *units)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  units    Units of the X-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
 
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
-    }
+ at Description
+The function @func{gridInqXunits} returns the units of a X-axis.
 
-  {
-    const double *gridptrOrig_area
-      = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
-    if ( gridptrOrig_area != NULL )
-      {
-        size_t size = gridsize;
+ at Result
+ at func{gridInqXunits} returns the units of the X-axis to the parameter units.
 
-        gridptrDup->area = (double *)Malloc(size * sizeof (double));
-        memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
-      }
-  }
+ at EndFunction
+*/
+void gridInqXunits(int gridID, char *xunits)
+{
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+}
 
-  if ( gridptrOrig->mask != NULL )
-    {
-      size_t size = gridsize;
 
-      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
-      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
+void gridInqXstdname(int gridID, char *xstdname)
+{
+  if ( xstdname )
+    {
+      xstdname[0] = 0;
+      grid_t *gridptr = grid_to_pointer(gridID);
+      if ( gridptr->x.stdname ) strcpy(xstdname, gridptr->x.stdname);
     }
+}
 
-  if ( gridptrOrig->mask_gme != NULL )
-    {
-      size_t size = gridsize;
+/*
+ at Function  gridInqYname
+ at Title     Get the name of a Y-axis
 
-      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
-      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
-    }
+ at Prototype void gridInqYname(int gridID, char *name)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  name     Name of the Y-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+
+ at Description
+The function @func{gridInqYname} returns the name of a Y-axis.
+
+ at Result
+ at func{gridInqYname} returns the name of the Y-axis to the parameter name.
+
+ at EndFunction
+*/
+void gridInqYname(int gridID, char *yname)
+{
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
+}
+
+/*
+ at Function  gridInqYlongname
+ at Title     Get the longname of a Y-axis
+
+ at Prototype void gridInqYlongname(int gridID, char *longname)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  longname Longname of the Y-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
+
+ at Description
+The function @func{gridInqYlongname} returns the longname of a Y-axis.
+
+ at Result
+ at func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
+
+ at EndFunction
+*/
+void gridInqYlongname(int gridID, char *ylongname)
+{
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
 }
 
-
 /*
- at Function  gridDuplicate
- at Title     Duplicate a horizontal Grid
+ at Function  gridInqYunits
+ at Title     Get the units of a Y-axis
 
- at Prototype int gridDuplicate(int gridID)
+ at Prototype void gridInqYunits(int gridID, char *units)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  units    Units of the Y-axis. The caller must allocate space for the
+                    returned string. The maximum possible length, in characters, of
+                    the string is given by the predefined constant @func{CDI_MAX_NAME}.
 
 @Description
-The function @func{gridDuplicate} duplicates a horizontal Grid.
+The function @func{gridInqYunits} returns the units of a Y-axis.
 
 @Result
- at func{gridDuplicate} returns an identifier to the duplicated Grid.
+ at func{gridInqYunits} returns the units of the Y-axis to the parameter units.
 
 @EndFunction
 */
-int gridDuplicate(int gridID)
+void gridInqYunits(int gridID, char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
-  int gridIDnew = reshPut(gridptrnew, &gridOps);
-  gridptrnew->self = gridIDnew;
-  return gridIDnew;
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
 
-void gridCompress(int gridID)
+void gridInqYstdname(int gridID, char *ystdname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  int gridtype = gridInqType(gridID);
-  if ( gridtype == GRID_UNSTRUCTURED )
+  if ( ystdname )
     {
-      if ( gridptr->mask_gme != NULL )
-	{
-          size_t gridsize = (size_t)gridInqSize(gridID);
-	  size_t nv = (size_t)gridptr->nvertex;
-          double *restrict area
-            = (double *)gridptr->vtable->inqAreaPtr(gridptr),
-            *restrict xvals = (double *)gridptr->vtable->inqXValsPtr((grid_t *)gridptr),
-            *restrict yvals = (double *)gridptr->vtable->inqYValsPtr((grid_t *)gridptr),
-            *restrict xbounds = (double *)gridptr->vtable->inqXBoundsPtr(gridptr),
-            *restrict ybounds = (double *)gridptr->vtable->inqYBoundsPtr(gridptr);
-          mask_t *restrict mask_gme = gridptr->mask_gme;
-          size_t *restrict selection = (size_t *)Malloc(gridsize * sizeof (selection[0]));
-          size_t nselect;
-          {
-            size_t j = 0;
-            for (size_t i = 0; i < gridsize; i++ )
-              selection[j] = i, j += (mask_gme[i] != 0);
-            nselect = j;
-          }
-          selection = (size_t *)Realloc(selection, nselect * sizeof (selection[0]));
-          if (xvals)
-            for (size_t i = 0; i < nselect; i++ )
-	      xvals[i] = xvals[selection[i]];
-          if (yvals)
-            for (size_t i = 0; i < nselect; i++ )
-              yvals[i] = yvals[selection[i]];
-          if (area)
-            for (size_t i = 0; i < nselect; i++ )
-              area[i] = area[selection[i]];
-          if (xbounds)
-            for (size_t i = 0; i < nselect; i++ )
-              for (size_t iv = 0; iv < nv; iv++)
-                xbounds[i * nv + iv] = xbounds[selection[i] * nv + iv];
-          if (ybounds)
-            for (size_t i = 0; i < nselect; i++ )
-              for (size_t iv = 0; iv < nv; iv++)
-                ybounds[i * nv + iv] = ybounds[selection[i] * nv + iv];
-          Free(selection);
+      ystdname[0] = 0;
+      grid_t *gridptr = grid_to_pointer(gridID);
+      if ( gridptr->y.stdname ) strcpy(ystdname, gridptr->y.stdname);
+    }
+}
 
-	  /* fprintf(stderr, "grid compress %d %d %d\n", i, j, gridsize); */
-	  gridsize = nselect;
-	  gridptr->size  = (int)gridsize;
-	  gridptr->xsize = (int)gridsize;
-	  gridptr->ysize = (int)gridsize;
 
-          double **resizeP[] = { &gridptr->xvals, &gridptr->yvals,
-                                 &gridptr->area,
-                                 &gridptr->xbounds, &gridptr->ybounds };
-          size_t newSize[] = { gridsize, gridsize, gridsize, nv*gridsize,
-                               nv*gridsize };
-          for ( size_t i = 0; i < sizeof (resizeP) / sizeof (resizeP[0]); ++i)
-            if ( *(resizeP[i]) )
-              *(resizeP[i]) = (double *)Realloc(*(resizeP[i]), newSize[i]*sizeof(double));
+void gridDefProj(int gridID, int projID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->proj = projID;
 
-	  Free(gridptr->mask_gme);
-	  gridptr->mask_gme = NULL;
-          gridMark4Update(gridID);
-	}
+  if ( gridptr->type == GRID_CURVILINEAR )
+    {
+      grid_t *projptr = grid_to_pointer(projID);
+      if ( projptr->x.name[0] ) strcpy(gridptr->x.dimname, projptr->x.name);
+      if ( projptr->y.name[0] ) strcpy(gridptr->y.dimname, projptr->y.name);
     }
-  else
-    Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
 }
 
-static void
-gridDefAreaSerial(grid_t *gridptr, const double *area)
+
+int gridInqProj(int gridID)
 {
-  size_t size = (size_t)gridptr->size;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->proj;
+}
 
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridptr->self);
 
-  if ( gridptr->area == NULL )
-    gridptr->area = (double *) Malloc(size*sizeof(double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+int gridInqProjType(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  memcpy(gridptr->area, area, size * sizeof(double));
-}
+  int projtype = gridptr->projtype;
 
+  if ( projtype == -1 )
+    {
+      char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+      if ( mapping[0] )
+        {
+          if      ( strcmp(mapping, "rotated_latitude_longitude") == 0 )   projtype = CDI_PROJ_RLL;
+          else if ( strcmp(mapping, "lambert_azimuthal_equal_area") == 0 ) projtype = CDI_PROJ_LAEA;
+          else if ( strcmp(mapping, "lambert_conformal_conic") == 0 )      projtype = CDI_PROJ_LCC;
+          else if ( strcmp(mapping, "sinusoidal") == 0 )                   projtype = CDI_PROJ_SINU;
 
-void gridDefArea(int gridID, const double *area)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defArea(gridptr, area);
-  gridMark4Update(gridID);
-}
+          gridptr->projtype = projtype;
+        }
+    }
 
-static void
-gridInqAreaSerial(grid_t *gridptr, double *area)
-{
-  if (gridptr->area)
-    memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
+  return projtype;
 }
 
 
-void gridInqArea(int gridID, double *area)
+void gridVerifyProj(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->inqArea(gridptr, area);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-static int
-gridHasAreaBase(grid_t *gridptr)
-{
-  return gridptr->area != NULL;
-}
+  int projtype = gridInqProjType(gridID);
 
-int gridHasArea(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->hasArea(gridptr);
+  if ( projtype == CDI_PROJ_RLL )
+    {
+      gridptr->x.stdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+      gridptr->y.stdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+      gridSetName(gridptr->x.units, "degrees");
+      gridSetName(gridptr->y.units, "degrees");
+    }
+  else if ( projtype == CDI_PROJ_LCC )
+    {
+      gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
+      gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
+      if ( !gridptr->x.units[0] ) gridSetName(gridptr->x.units, "m");
+      if ( !gridptr->y.units[0] ) gridSetName(gridptr->y.units, "m");
+    }
 }
 
+/*
+ at Function  gridInqType
+ at Title     Get the type of a Grid
 
-static const double *gridInqAreaPtrBase(grid_t *gridptr)
-{
-  return gridptr->area;
-}
+ at Prototype int gridInqType(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-const double *gridInqAreaPtr(int gridID)
+ at Description
+The function @func{gridInqType} returns the type of a Grid.
+
+ at Result
+ at func{gridInqType} returns the type of the grid,
+one of the set of predefined CDI grid types.
+The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
+ at func{GRID_LONLAT}, @func{GRID_PROJECTION}, @func{GRID_SPECTRAL}, @func{GRID_GME},
+ at func{GRID_CURVILINEAR} and @func{GRID_UNSTRUCTURED}.
+
+ at EndFunction
+*/
+int gridInqType(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqAreaPtr(gridptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  return gridptr->type;
 }
 
 
-void gridDefNvertex(int gridID, int nvertex)
+/*
+ at Function  gridInqSize
+ at Title     Get the size of a Grid
+
+ at Prototype size_t gridInqSize(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridInqSize} returns the size of a Grid.
+
+ at Result
+ at func{gridInqSize} returns the number of grid points of a Grid.
+
+ at EndFunction
+*/
+size_t gridInqSize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if (gridptr->nvertex != nvertex)
+  size_t size = gridptr->size;
+
+  if ( size == 0 )
     {
-      gridptr->nvertex = nvertex;
-      gridMark4Update(gridID);
+      size_t xsize = gridptr->x.size;
+      size_t ysize = gridptr->y.size;
+
+      size = ysize ? xsize * ysize : xsize;
+
+      gridptr->size = size;
     }
-}
 
+  return size;
+}
 
-int gridInqNvertex(int gridID)
+static
+int nsp2trunc(int nsp)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->nvertex;
+  /*  nsp = (trunc+1)*(trunc+1)              */
+  /*      => trunc^2 + 3*trunc - (x-2) = 0   */
+  /*                                         */
+  /*  with:  y^2 + p*y + q = 0               */
+  /*         y = -p/2 +- sqrt((p/2)^2 - q)   */
+  /*         p = 3 and q = - (x-2)           */
+  int trunc = (int) (sqrt(nsp*4 + 1.) - 3) / 2;
+  return trunc;
 }
 
-static void
-gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
-                     double **field)
+
+int gridInqTrunc(int gridID)
 {
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t nvertex = (size_t)gridptr->nvertex;
-  if ( nvertex == 0 )
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->trunc == 0 )
     {
-      Warning("nvertex undefined for gridID = %d. Cannot define bounds!",
-              gridptr->self);
-      return;
+      if ( gridptr->type == GRID_SPECTRAL )
+        gridptr->trunc = nsp2trunc(gridptr->size);
+      /*
+      else if      ( gridptr->type == GRID_GAUSSIAN )
+        gridptr->trunc = nlat2trunc(gridptr->y.size);
+      */
     }
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : regularSize);
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridptr->self);
 
-  if (*field == NULL)
-    *field = (double *)Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
-
-  memcpy(*field, bounds, size * sizeof (double));
+  return gridptr->trunc;
 }
 
 
-static void
-gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
+void gridDefTrunc(int gridID, int trunc)
 {
-  gridDefBoundsGeneric(gridptr, xbounds, gridptr->xsize, &gridptr->xbounds);
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->trunc != trunc )
+    {
+      gridMark4Update(gridID);
+      gridptr->trunc = trunc;
+    }
 }
 
 /*
- at Function  gridDefXbounds
- at Title     Define the bounds of a X-axis
+ at Function  gridDefXsize
+ at Title     Define the number of values of a X-axis
 
- at Prototype void gridDefXbounds(int gridID, const double *xbounds)
+ at Prototype void gridDefXsize(int gridID, size_t xsize)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  xbounds  X-bounds of the grid.
+    @Item  xsize    Number of values of a X-axis.
 
 @Description
-The function @func{gridDefXbounds} defines all bounds of the X-axis.
+The function @func{gridDefXsize} defines the number of values of a X-axis.
 
 @EndFunction
 */
-void gridDefXbounds(int gridID, const double *xbounds)
+void gridDefXsize(int gridID, size_t xsize)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defXBounds(gridptr, xbounds);
-  gridMark4Update(gridID);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-static int
-gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
-{
-  size_t nvertex = (size_t)gridptr->nvertex;
+  size_t gridSize = gridInqSize(gridID);
+  if ( xsize > gridSize )
+    Error("xsize %zu is greater then gridsize %zu", xsize, gridSize);
 
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
+    Error("xsize %zu must be equal to gridsize %zu for gridtype: UNSTRUCTURED", xsize, gridSize);
 
-  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
-  if ( gridptr_xbounds )
+  if ( gridptr->x.size != xsize )
     {
-      if ( size && xbounds )
-        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
+      gridMark4Update(gridID);
+      gridptr->x.size = xsize;
     }
-  else
-    size = 0;
 
-  return (int)size;
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
+    {
+      size_t axisproduct = gridptr->x.size*gridptr->y.size;
+      if ( axisproduct > 0 && axisproduct != gridSize )
+        Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
+              gridptr->x.size, gridptr->y.size, gridSize);
+    }
 }
 
 /*
- at Function  gridInqXbounds
- at Title     Get the bounds of a X-axis
+ at Function
+ at Title
 
- at Prototype int gridInqXbounds(int gridID, double *xbounds)
+ at Prototype
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  xbounds  Pointer to the location into which the X-bounds are read.
-                    The caller must allocate space for the returned values.
-
- at Description
-The function @func{gridInqXbounds} returns the bounds of the X-axis.
-
- at Result
-Upon successful completion @func{gridInqXbounds} returns the number of bounds and
-the bounds are stored in @func{xbounds}.
-Otherwise, 0 is returned and @func{xbounds} is empty.
+    @Item  Grid identifier
 
 @EndFunction
 */
-int gridInqXbounds(int gridID, double *xbounds)
+void gridDefDatatype(int gridID, int datatype)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXBounds(gridptr, xbounds);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-static const double *
-gridInqXBoundsPtrSerial(grid_t *gridptr)
-{
-  return gridptr->xbounds;
+  if ( gridptr->datatype != datatype )
+    {
+      gridMark4Update(gridID);
+      gridptr->datatype = datatype;
+    }
 }
 
+/*
+ at Function
+ at Title
 
-const double *gridInqXboundsPtr(int gridID)
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
+
+ at EndFunction
+*/
+int gridInqDatatype(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXBoundsPtr(gridptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->datatype;
 }
 
-static void
-gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
+/*
+ at Function  gridInqXsize
+ at Title     Get the number of values of a X-axis
+
+ at Prototype size_t gridInqXsize(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridInqXsize} returns the number of values of a X-axis.
+
+ at Result
+ at func{gridInqXsize} returns the number of values of a X-axis.
+
+ at EndFunction
+*/
+size_t gridInqXsize(int gridID)
 {
-  gridDefBoundsGeneric(gridptr, ybounds, gridptr->ysize, &gridptr->ybounds);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->x.size;
 }
 
 /*
- at Function  gridDefYbounds
- at Title     Define the bounds of a Y-axis
+ at Function  gridDefYsize
+ at Title     Define the number of values of a Y-axis
 
- at Prototype void gridDefYbounds(int gridID, const double *ybounds)
+ at Prototype void gridDefYsize(int gridID, size_t ysize)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  ybounds  Y-bounds of the grid.
+    @Item  ysize    Number of values of a Y-axis.
 
 @Description
-The function @func{gridDefYbounds} defines all bounds of the Y-axis.
+The function @func{gridDefYsize} defines the number of values of a Y-axis.
 
 @EndFunction
 */
-void gridDefYbounds(int gridID, const double *ybounds)
+void gridDefYsize(int gridID, size_t ysize)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defYBounds(gridptr, ybounds);
-  gridMark4Update(gridID);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-static int
-gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
-{
-  size_t nvertex = (size_t)gridptr->nvertex;
+  size_t gridSize = gridInqSize(gridID);
 
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
+  if ( ysize > gridSize )
+    Error("ysize %zu is greater then gridsize %zu", ysize, gridSize);
 
-  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
-  if ( gridptr_ybounds )
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && ysize != gridSize )
+    Error("ysize %zu must be equal gridsize %zu for gridtype: UNSTRUCTURED", ysize, gridSize);
+
+  if ( gridptr->y.size != ysize )
     {
-      if ( size && ybounds )
-        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
+      gridMark4Update(gridID);
+      gridptr->y.size = ysize;
     }
-  else
-    size = 0;
 
-  return (int)size;
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
+    {
+      size_t axisproduct = gridptr->x.size*gridptr->y.size;
+      if ( axisproduct > 0 && axisproduct != gridSize )
+        Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
+              gridptr->x.size, gridptr->y.size, gridSize);
+    }
 }
 
-
 /*
- at Function  gridInqYbounds
- at Title     Get the bounds of a Y-axis
+ at Function  gridInqYsize
+ at Title     Get the number of values of a Y-axis
 
- at Prototype int gridInqYbounds(int gridID, double *ybounds)
+ at Prototype size_t gridInqYsize(int gridID)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  ybounds  Pointer to the location into which the Y-bounds are read.
-                    The caller must allocate space for the returned values.
 
 @Description
-The function @func{gridInqYbounds} returns the bounds of the Y-axis.
+The function @func{gridInqYsize} returns the number of values of a Y-axis.
 
 @Result
-Upon successful completion @func{gridInqYbounds} returns the number of bounds and
-the bounds are stored in @func{ybounds}.
-Otherwise, 0 is returned and @func{ybounds} is empty.
+ at func{gridInqYsize} returns the number of values of a Y-axis.
 
 @EndFunction
 */
-int gridInqYbounds(int gridID, double *ybounds)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYBounds(gridptr, ybounds);
-}
-
-static const double *
-gridInqYBoundsPtrSerial(grid_t *gridptr)
+size_t gridInqYsize(int gridID)
 {
-  return gridptr->ybounds;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->y.size;
 }
 
+/*
+ at Function  gridDefNP
+ at Title     Define the number of parallels between a pole and the equator
 
-const double *gridInqYboundsPtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYBoundsPtr(gridptr);
-}
-
-static void
-printDblsPrefixAutoBrk(FILE *fp, int dig, const char prefix[], size_t nbyte0,
-                       size_t n, const double vals[])
-{
-  fputs(prefix, fp);
-  size_t nbyte = nbyte0;
-  for ( size_t i = 0; i < n; i++ )
-    {
-      if ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%.*g ", dig, vals[i]);
-    }
-  fputs("\n", fp);
-}
+ at Prototype void gridDefNP(int gridID, int np)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  np       Number of parallels between a pole and the equator.
 
-static void
-printIntsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
-                       size_t n, const int vals[])
-{
-  fputs(prefix, fp);
-  size_t nbyte = nbyte0;
-  for ( size_t i = 0; i < n; i++ )
-    {
-      if ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
-    }
-  fputs("\n", fp);
-}
+ at Description
+The function @func{gridDefNP} defines the number of parallels between a pole and the equator
+of a Gaussian grid.
 
-static void
-printBounds(FILE *fp, int dig, const char prefix[], size_t nbyte0,
-            size_t n, size_t nvertex, const double bounds[])
+ at EndFunction
+*/
+void gridDefNP(int gridID, int np)
 {
-  fputs(prefix, fp);
-  if ( n > 0 )
-    {
-      for ( size_t iv = 0; iv < nvertex; iv++ )
-        fprintf(fp, "%.*g ", dig, bounds[iv]);
-      for ( size_t i = 1; i < (size_t)n; i++ )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          for ( size_t iv = 0; iv < nvertex; iv++ )
-            fprintf(fp, "%.*g ", dig, bounds[i*nvertex+iv]);
-        }
-      fputs("\n", fp);
-    }
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-static void
-printMask(FILE *fp, const char prefix[], size_t nbyte0,
-          size_t n, const mask_t mask[])
-{
-  fputs(prefix, fp);
-  size_t nbyte = nbyte0;
-  for ( size_t i = 0; i < n; i++ )
+  if ( gridptr->np != np )
     {
-      if ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
+      gridMark4Update(gridID);
+      gridptr->np = np;
     }
-  fputs("\n", fp);
 }
 
-static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
-{
-  int xdim, ydim;
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-  int gridID = gridptr->self;
-  const double *area    = gridInqAreaPtr(gridID);
-  const double *xvals   = gridInqXvalsPtr(gridID);
-  const double *yvals   = gridInqYvalsPtr(gridID);
-  const double *xbounds = gridInqXboundsPtr(gridID);
-  const double *ybounds = gridInqYboundsPtr(gridID);
-
-  int type     = gridInqType(gridID);
-  int trunc    = gridInqTrunc(gridID);
-  int gridsize = gridInqSize(gridID);
-  int xsize    = gridInqXsize(gridID);
-  int ysize    = gridInqYsize(gridID);
-  int nvertex  = gridInqNvertex(gridID);
-  int prec     = gridInqPrec(gridID);
-
-  int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
-
-  fprintf(fp, "#\n"
-          "# gridID %d\n"
-          "#\n"
-          "gridtype  = %s\n"
-          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
-
-  if ( type != GRID_GME )
-    {
-      if ( xvals )
-        {
-          if ( gridptr->xname[0]     )     fprintf(fp, "xname     = %s\n", gridptr->xname);
-          if ( gridptr->xlongname[0] )     fprintf(fp, "xlongname = %s\n", gridptr->xlongname);
-          if ( gridptr->xunits[0]    )     fprintf(fp, "xunits    = %s\n", gridptr->xunits);
-        }
-      if ( yvals )
-        {
-          if ( gridptr->yname[0]     )     fprintf(fp, "yname     = %s\n", gridptr->yname);
-          if ( gridptr->ylongname[0] )     fprintf(fp, "ylongname = %s\n", gridptr->ylongname);
-          if ( gridptr->yunits[0]    )     fprintf(fp, "yunits    = %s\n", gridptr->yunits);
-        }
-      if ( type == GRID_UNSTRUCTURED && nvertex > 0 ) fprintf(fp, "nvertex   = %d\n", nvertex);
-    }
-
-  switch (type)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-    case GRID_GAUSSIAN_REDUCED:
-    case GRID_GENERIC:
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
-    case GRID_CURVILINEAR:
-    case GRID_UNSTRUCTURED:
-      {
-        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridptr->np);
-
-	if ( type == GRID_CURVILINEAR || type == GRID_UNSTRUCTURED )
-	  {
-	    xdim = gridsize;
-	    ydim = gridsize;
-	  }
-        else if ( type == GRID_GAUSSIAN_REDUCED )
-          {
-	    xdim = 2;
-	    ydim = ysize;
-          }
-	else
-	  {
-	    xdim = xsize;
-	    ydim = ysize;
-	  }
-
-	if ( type != GRID_UNSTRUCTURED )
-	  {
-	    if ( xsize > 0 ) fprintf(fp, "xsize     = %d\n", xsize);
-	    if ( ysize > 0 ) fprintf(fp, "ysize     = %d\n", ysize);
-	  }
-
-	if ( type == GRID_UNSTRUCTURED )
-          {
-            int number = gridInqNumber(gridID);
-            int position = gridInqPosition(gridID);
-            // const unsigned char *d;
-            if ( number > 0 )
-              {
-                fprintf(fp, "number    = %d\n", number);
-                if ( position >= 0 ) fprintf(fp, "position  = %d\n", position);
-              }
-            /*
-              gridInqUUID(gridID, uuidOfHGrid);
-              d = (unsigned char *) &uuidOfHGrid;
-              fprintf(fp, "uuid      = %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
-              d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
-              d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
-            */
-            if ( gridInqReference(gridID, NULL) )
-              {
-                char reference_link[8192];
-                gridInqReference(gridID, reference_link);
-                fprintf(fp, "uri       = %s\n", reference_link);
-              }
-          }
+/*
+ at Function  gridInqNP
+ at Title     Get the number of parallels between a pole and the equator
 
-	if ( type == GRID_LAEA )
-	  {
-	    double a = 0, lon_0 = 0, lat_0 = 0;
-	    gridInqLaea(gridID, &a, &lon_0, &lat_0);
-	    fprintf(fp, "a         = %.*g\n"
-                    "lon_0     = %.*g\n"
-                    "lat_0     = %.*g\n", dig, a, dig, lon_0, dig, lat_0);
-	  }
+ at Prototype int gridInqNP(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-	if ( type == GRID_LCC2 )
-	  {
-	    double a = 0, lon_0 = 0, lat_0 = 0, lat_1 = 0, lat_2 = 0;
-	    gridInqLcc2(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2);
-	    fprintf(fp, "a         = %.*g\n"
-                    "lon_0     = %.*g\n"
-                    "lat_0     = %.*g\n"
-                    "lat_1     = %.*g\n"
-                    "lat_2     = %.*g\n",
-                    dig, a, dig, lon_0, dig, lat_0, dig, lat_1, dig, lat_2);
-	  }
+ at Description
+The function @func{gridInqNP} returns the number of parallels between a pole and the equator
+of a Gaussian grid.
 
-	if ( gridptr->isRotated )
-	  {
-	    if ( xsize > 0 ) fprintf(fp, "xnpole    = %.*g\n", dig, gridptr->xpole);
-	    if ( ysize > 0 ) fprintf(fp, "ynpole    = %.*g\n", dig, gridptr->ypole);
-	    if ( IS_NOT_EQUAL(gridptr->angle, 0) ) fprintf(fp, "angle     = %.*g\n", dig, gridptr->angle);
- 	  }
+ at Result
+ at func{gridInqNP} returns the number of parallels between a pole and the equator.
 
-	if ( xvals )
-	  {
-	    double xfirst = 0.0, xinc = 0.0;
+ at EndFunction
+*/
+int gridInqNP(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->np;
+}
 
-	    if ( type == GRID_LONLAT     || type == GRID_GAUSSIAN ||
-		 type == GRID_GENERIC    || type == GRID_LCC2     ||
-                 type == GRID_SINUSOIDAL || type == GRID_LAEA )
-	      {
-		xfirst = gridInqXval(gridID, 0);
-		xinc   = gridInqXinc(gridID);
-	      }
+/*
+ at Function
+ at Title
 
-	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
-	      {
-                fprintf(fp, "xfirst    = %.*g\n"
-                        "xinc      = %.*g\n", dig, xfirst, dig, xinc);
-	      }
-	    else
-	      {
-                static const char prefix[] = "xvals     = ";
-                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
-                                       (size_t)(xdim > 0 ? xdim : 0), xvals);
-	      }
-	  }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-	if ( xbounds )
-	  {
-            static const char prefix[] = "xbounds   = ";
-            printBounds(fp, dig, prefix, sizeof(prefix)-1,
-                        (size_t)(xdim > 0 ? xdim : 0),
-                        (size_t)(nvertex > 0 ? nvertex : 0), xbounds);
-	  }
+ at EndFunction
+*/
+void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-	if ( yvals )
-	  {
-	    double yfirst = 0.0, yinc = 0.0;
+  gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
+  gridptr->nrowlon = nrowlon;
+  memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
+  gridMark4Update(gridID);
+}
 
-	    if ( type == GRID_LONLAT || type == GRID_GENERIC || type == GRID_LCC2 ||
-		 type == GRID_SINUSOIDAL || type == GRID_LAEA )
-	      {
-		yfirst = gridInqYval(gridID, 0);
-		yinc   = gridInqYinc(gridID);
-	      }
+/*
+ at Function
+ at Title
 
-	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
-	      {
-	  	fprintf(fp, "yfirst    = %.*g\n"
-                        "yinc      = %.*g\n", dig, yfirst, dig, yinc);
-	      }
-	    else
-	      {
-                static const char prefix[] = "yvals     = ";
-                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
-                                       (size_t)(ydim > 0 ? ydim : 0), yvals);
-	      }
-	  }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-	if ( ybounds )
-	  {
-            static const char prefix[] = "ybounds   = ";
-            printBounds(fp, dig, prefix, sizeof(prefix)-1,
-                        (size_t)(ydim > 0 ? ydim : 0),
-                        (size_t)(nvertex > 0 ? nvertex : 0), ybounds);
-	  }
+ at EndFunction
+*/
+void gridInqRowlon(int gridID, int *rowlon)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-	if ( area )
-	  {
-            static const char prefix[] = "area      = ";
-            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
-                                   (size_t)(gridsize > 0 ? gridsize : 0), area);
-	  }
+  if ( gridptr->rowlon == 0 )  Error("undefined pointer!");
 
-        if ( type == GRID_GAUSSIAN_REDUCED )
-          {
-            static const char prefix[] = "rowlon    = ";
-            int *rowlon = (int *)Malloc((size_t)ysize*sizeof(int));
-            gridInqRowlon(gridID, rowlon);
-            printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
-                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
-            Free(rowlon);
-          }
+  memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
+}
 
-	break;
-      }
-    case GRID_LCC:
-      {
-	double originLon = 0, originLat = 0, lonParY = 0, lat1 = 0, lat2 = 0, xincm = 0, yincm = 0;
-	int projflag = 0, scanflag = 0;
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
-
-	fprintf(fp,
-                "xsize     = %d\n"
-                "ysize     = %d\n"
-                "originLon = %.*g\n"
-                "originLat = %.*g\n"
-                "lonParY   = %.*g\n"
-                "lat1      = %.*g\n"
-                "lat2      = %.*g\n"
-                "xinc      = %.*g\n"
-                "yinc      = %.*g\n"
-                "projection = %s\n",
-                xsize, ysize, dig, originLon, dig, originLat, dig, lonParY,
-                dig, lat1, dig, lat2, dig, xincm, dig, yincm,
-                (projflag & 128) == 0 ? "northpole" : "southpole");
-	break;
-      }
-    case GRID_SPECTRAL:
-      {
-        fprintf(fp, "truncation = %d\n"
-                "complexpacking = %d\n", trunc, gridptr->lcomplex );
-        break;
-      }
-    case GRID_FOURIER:
-      {
-	fprintf(fp, "truncation = %d\n", trunc);
-	break;
-      }
-    case GRID_GME:
-      {
-        fprintf(fp, "ni        = %d\n", gridptr->ni );
-        break;
-      }
-   default:
-      {
-	fprintf(stderr, "Unsupported grid type: %s\n", gridNamePtr(type));
-        break;
-      }
-    }
+static size_t
+gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
+                        int *restrict mask)
+{
+  size_t size = gridptr->size;
 
-  gridInqUUID(gridID, uuidOfHGrid);
-  if ( !cdiUUIDIsNull(uuidOfHGrid) )
-    {
-      char uuidOfHGridStr[37];
-      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
-      if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
-        fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
-    }
+  if ( CDI_Debug && size == 0 )
+    Warning("Size undefined for gridID = %d", gridptr->self);
 
-  if ( gridptr->mask )
+  const mask_t *restrict mask_src = *internalMask;
+  if ( mask_src )
     {
-      static const char prefix[] = "mask      = ";
-      printMask(fp, prefix, sizeof(prefix)-1,
-                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
+      if (mask && size > 0)
+        for (size_t i = 0; i < size; ++i)
+          mask[i] = (int)mask_src[i];
     }
+  else
+    size = 0;
+
+  return size;
 }
 
-void gridPrint ( int gridID, int index, int opt )
+static size_t
+gridInqMaskSerial(grid_t *gridptr, int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  gridPrintKernel ( gridptr, index, opt, stdout );
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
 }
 
 
-
-void gridPrintP ( void * voidptr, FILE * fp )
+int gridInqMask(int gridID, int *mask)
 {
-  grid_t * gridptr = ( grid_t * ) voidptr;
-
-  xassert ( gridptr );
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqMask(gridptr, mask);
+}
 
-  gridPrintKernel ( gridptr , gridptr->self, 0, fp );
+static void
+gridDefMaskSerial(grid_t *gridptr, const int *mask)
+{
+  size_t size = gridptr->size;
 
-  fprintf(fp,
-          "precision = %d\n"
-          "nd        = %d\n"
-          "ni        = %d\n"
-          "ni2       = %d\n"
-          "ni3       = %d\n"
-          "number    = %d\n"
-          "position  = %d\n"
-          "trunc     = %d\n"
-          "lcomplex  = %d\n"
-          "nrowlon   = %d\n",
-          gridptr->prec, gridptr->nd, gridptr->ni, gridptr->ni2,
-          gridptr->ni3, gridptr->number, gridptr->position, gridptr->trunc,
-          gridptr->lcomplex, gridptr->nrowlon );
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
 
-  if ( gridptr->rowlon )
+  if ( mask == NULL )
     {
-      static const char prefix[] = "rowlon    = ";
-      printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
-                             (size_t)(gridptr->nrowlon > 0
-                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
+      if ( gridptr->mask )
+	{
+	  Free(gridptr->mask);
+	  gridptr->mask = NULL;
+	}
     }
-
-  if ( gridptr->mask_gme )
+  else
     {
-      static const char prefix[] = "mask_gme  = ";
-      printMask(fp, prefix, sizeof(prefix)-1,
-                (size_t)(gridptr->size > 0 ? gridptr->size : 0),
-                gridptr->mask_gme);
+      if ( gridptr->mask == NULL )
+	gridptr->mask = (mask_t *) Malloc(size*sizeof(mask_t));
+      else if ( CDI_Debug )
+	Warning("grid mask already defined!");
+
+      for (size_t i = 0; i < size; ++i )
+	gridptr->mask[i] = (mask_t)(mask[i] != 0);
     }
 }
 
-static const double *gridInqXValsPtrSerial(grid_t *gridptr)
+void gridDefMask(int gridID, const int *mask)
 {
-  return gridptr->xvals;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defMask(gridptr, mask);
+  gridMark4Update(gridID);
 }
 
-const double *gridInqXvalsPtr(int gridID)
+static int
+gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXValsPtr(gridptr);
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
 }
 
+int gridInqMaskGME(int gridID, int *mask)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqMaskGME(gridptr, mask);
+}
 
-static const double *gridInqYValsPtrSerial(grid_t *gridptr)
+static void
+gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
 {
-  return gridptr->yvals;
+  size_t size = gridptr->size;
+
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
+
+  if ( gridptr->mask_gme == NULL )
+    gridptr->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
+  else if ( CDI_Debug )
+    Warning("mask already defined!");
+
+  for (size_t i = 0; i < size; ++i)
+    gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
 }
 
-const double *gridInqYvalsPtr(int gridID)
+void gridDefMaskGME(int gridID, const int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYValsPtr(gridptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defMaskGME(gridptr, mask);
+  gridMark4Update(gridID);
 }
 
-/*
- at Function  gridDefLCC
- at Title     Define the parameter of a Lambert Conformal Conic grid
+static
+size_t gridInqXValsSerial(grid_t *gridptr, double *xvals)
+{
+  size_t size;
+  if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
+    size = gridptr->size;
+  else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
+    size = 2;
+  else
+    size = gridptr->x.size;
 
- at Prototype void gridDefLCC(int gridID, double originLon, double originLat, double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag)
- at Parameter
-    @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  originLon Longitude of the first grid point.
-    @Item  originLat Latitude of the first grid point.
-    @Item  lonParY   The East longitude of the meridian which is parallel to the Y-axis.
-    @Item  lat1      First latitude from the pole at which the secant cone cuts the sphere.
-    @Item  lat2      Second latitude at which the secant cone cuts the sphere.
-    @Item  xinc      X-direction grid lenght in meter.
-    @Item  yinc      Y-direction grid lenght in meter.
-    @Item  projflag  Projection centre flag.
-    @Item  scanflag  Scanning mode flag.
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d", gridptr->self);
 
- at Description
-The function @func{gridDefLCC} defines the parameter of a Lambert Conformal Conic grid.
+  if ( gridptr->x.vals )
+    {
+      if ( size && xvals )
+        {
+          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
+          memcpy(xvals, gridptr_xvals, size * sizeof (double));
+        }
+    }
+  else
+    size = 0;
 
- at EndFunction
-*/
-void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
-                double lat1, double lat2, double xinc, double yinc,
-                int projflag, int scanflag)
+  return size;
+}
+
+static
+size_t gridInqXCvalsSerial(grid_t *gridptr, char **xcvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( gridptr->type != GRID_CHARXY )
+    Error("Function only valid for grid type 'GRID_CHARXY'.");
 
-  if ( gridptr->type != GRID_LCC )
-    Warning("Definition of LCC grid for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  else
+  size_t size = gridptr->x.size;
+  size_t maxclength = 0;
+
+  const char **gridptr_xcvals = gridptr->vtable->inqXCvalsPtr(gridptr);
+  if ( gridptr_xcvals && size && xcvals )
     {
-      gridptr->lcc_originLon = originLon;
-      gridptr->lcc_originLat = originLat;
-      gridptr->lcc_lonParY   = lonParY;
-      gridptr->lcc_lat1      = lat1;
-      gridptr->lcc_lat2      = lat2;
-      gridptr->lcc_xinc      = xinc;
-      gridptr->lcc_yinc      = yinc;
-      gridptr->lcc_projflag  = projflag;
-      gridptr->lcc_scanflag  = scanflag;
-      gridptr->lcc_defined   = TRUE;
-      gridMark4Update(gridID);
+      maxclength = gridptr->x.clength;
+      for ( size_t i = 0; i < size; i++ )
+        memcpy(xcvals[i], gridptr_xcvals[i], maxclength*sizeof(char));
     }
+
+  return maxclength;
+}
+
+static
+int gridInqXIscSerial(grid_t *gridptr)
+{
+  int clen = gridptr->x.clength;
+  /*
+  if ( gridptr->type != GRID_CHARXY )
+    Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'.");
+  */
+  return clen;
 }
 
 /*
- at Function  gridInqLCC
- at Title     Get the parameter of a Lambert Conformal Conic grid
+ at Function  gridInqXvals
+ at Title     Get all values of a X-axis
 
- at Prototype void gridInqLCC(int gridID, double *originLon, double *originLat, double *lonParY, double *lat1, double *lat2, double *xinc, double *yinc, int *projflag, int *scanflag)
+ at Prototype size_t gridInqXvals(int gridID, double *xvals)
 @Parameter
-    @Item  gridID    Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-    @Item  originLon Longitude of the first grid point.
-    @Item  originLat Latitude of the first grid point.
-    @Item  lonParY   The East longitude of the meridian which is parallel to the Y-axis.
-    @Item  lat1      First latitude from the pole at which the secant cone cuts the sphere.
-    @Item  lat2      Second latitude at which the secant cone cuts the sphere.
-    @Item  xinc      X-direction grid lenght in meter.
-    @Item  yinc      Y-direction grid lenght in meter.
-    @Item  projflag  Projection centre flag.
-    @Item  scanflag  Scanning mode flag.
- 
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  xvals    Pointer to the location into which the X-values are read.
+                    The caller must allocate space for the returned values.
+
 @Description
-The function @func{gridInqLCC} returns the parameter of a Lambert Conformal Conic grid.
+The function @func{gridInqXvals} returns all values of the X-axis.
+
+ at Result
+Upon successful completion @func{gridInqXvals} returns the number of values and
+the values are stored in @func{xvals}.
+Otherwise, 0 is returned and @func{xvals} is empty.
 
 @EndFunction
 */
-void gridInqLCC(int gridID, double *originLon, double *originLat, double *lonParY,
-                double *lat1, double *lat2, double *xinc, double *yinc,
-                int *projflag, int *scanflag)
+size_t gridInqXvals(int gridID, double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->type != GRID_LCC )
-    Warning("Inquire of LCC grid definition for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  else
-    {
-      if ( gridptr->lcc_defined )
-        {
-          *originLon = gridptr->lcc_originLon;
-          *originLat = gridptr->lcc_originLat;
-          *lonParY   = gridptr->lcc_lonParY;
-          *lat1      = gridptr->lcc_lat1;
-          *lat2      = gridptr->lcc_lat2;
-          *xinc      = gridptr->lcc_xinc;
-          *yinc      = gridptr->lcc_yinc;
-          *projflag  = gridptr->lcc_projflag;
-          *scanflag  = gridptr->lcc_scanflag;
-        }
-      else
-	Warning("Lambert Conformal grid undefined (gridID = %d)", gridID);
-    }
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXVals(gridptr, xvals);
 }
 
-void gridDefLcc2(int gridID, double earth_radius, double lon_0, double lat_0, double lat_1, double lat_2)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
 
-  if ( gridptr->type != GRID_LCC2 )
-    Warning("Definition of LCC2 grid for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  else
-    {
-      gridptr->lcc2_a       = earth_radius;
-      gridptr->lcc2_lon_0   = lon_0;
-      gridptr->lcc2_lat_0   = lat_0;
-      gridptr->lcc2_lat_1   = lat_1;
-      gridptr->lcc2_lat_2   = lat_2;
-      gridptr->lcc2_defined = TRUE;
-      gridMark4Update(gridID);
-    }
+size_t gridInqXCvals(int gridID, char **xcvals)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXCvals(gridptr, xcvals);
 }
 
 
-void gridInqLcc2(int gridID, double *earth_radius, double *lon_0, double *lat_0, double *lat_1, double *lat_2)
+int gridInqXIsc(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXIsc(gridptr);
+}
+
+static
+void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int gridtype = gridptr->type;
 
-  if ( gridptr->type != GRID_LCC2 )
-    Warning("Inquire of LCC2 grid definition for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
+  size_t size;
+  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
+    size = gridptr->size;
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    size = 2;
   else
-    {
-      if ( gridptr->lcc2_defined )
-        {
-          *earth_radius = gridptr->lcc2_a;
-          *lon_0        = gridptr->lcc2_lon_0;
-          *lat_0        = gridptr->lcc2_lat_0;
-          *lat_1        = gridptr->lcc2_lat_1;
-          *lat_2        = gridptr->lcc2_lat_2;
-        }
-      else
-        Warning("LCC2 grid undefined (gridID = %d)", gridID);
-    }
+    size = gridptr->x.size;
+
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
+
+  if (gridptr->x.vals && CDI_Debug)
+    Warning("values already defined!");
+  gridptr->x.vals = (double *)Realloc(gridptr->x.vals,
+                                      size * sizeof(double));
+  memcpy(gridptr->x.vals, xvals, size * sizeof (double));
 }
 
-void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0)
+static
+size_t gridInqYCvalsSerial(grid_t *gridptr, char **ycvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( gridptr->type != GRID_CHARXY )
+    Error("Function only valid for grid type 'GRID_CHARXY'.");
 
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Definition of LAEA grid for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
+  size_t size = gridptr->y.size;
+  size_t maxclength = 0;
+
+  const char **gridptr_ycvals = gridptr->vtable->inqYCvalsPtr(gridptr);
+  if ( gridptr_ycvals && size && ycvals )
     {
-      gridptr->laea_a       = earth_radius;
-      gridptr->laea_lon_0   = lon_0;
-      gridptr->laea_lat_0   = lat_0;
-      gridptr->laea_defined = TRUE;
-      gridMark4Update(gridID);
+      maxclength = gridptr->y.clength;
+      for ( size_t i = 0; i < size; i++ )
+        memcpy(ycvals[i], gridptr_ycvals[i], maxclength*sizeof(char));
     }
+
+  return maxclength;
+}
+
+static
+int gridInqYIscSerial(grid_t *gridptr)
+{
+  int clen = gridptr->y.clength;
+  /*
+  if ( gridptr->type != GRID_CHARXY )
+    Error("Axis type is 'char' but grid is not type 'GRID_CHARXY'.");
+  */
+  return clen;
 }
 
+/*
+ at Function  gridDefXvals
+ at Title     Define the values of a X-axis
+
+ at Prototype void gridDefXvals(int gridID, const double *xvals)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  xvals    X-values of the grid.
+
+ at Description
+The function @func{gridDefXvals} defines all values of the X-axis.
+
+ at EndFunction
+*/
+void gridDefXvals(int gridID, const double *xvals)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defXVals(gridptr, xvals);
+  gridMark4Update(gridID);
+}
 
-void gridInqLaea(int gridID, double *earth_radius, double *lon_0, double *lat_0)
+static
+size_t gridInqYValsSerial(grid_t *gridptr, double *yvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  int gridtype = gridptr->type;
+  size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+            ? gridptr->size : gridptr->y.size;
 
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Inquire of LAEA grid definition for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d!", gridptr->self);
+
+  if ( gridptr->y.vals )
     {
-      if ( gridptr->laea_defined )
+      if ( size && yvals )
         {
-          *earth_radius = gridptr->laea_a;
-          *lon_0        = gridptr->laea_lon_0;
-          *lat_0        = gridptr->laea_lat_0;
+          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
+          memcpy(yvals, gridptr_yvals, size * sizeof (double));
         }
-      else
-        Warning("LAEA grid undefined (gridID = %d)", gridID);
     }
+  else
+    size = 0;
+
+  return size;
 }
 
+/*
+ at Function  gridInqYvals
+ at Title     Get all values of a Y-axis
 
-void gridDefComplexPacking(int gridID, int lcomplex)
+ at Prototype size_t gridInqYvals(int gridID, double *yvals)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  yvals    Pointer to the location into which the Y-values are read.
+                    The caller must allocate space for the returned values.
+
+ at Description
+The function @func{gridInqYvals} returns all values of the Y-axis.
+
+ at Result
+Upon successful completion @func{gridInqYvals} returns the number of values and
+the values are stored in @func{yvals}.
+Otherwise, 0 is returned and @func{yvals} is empty.
+
+ at EndFunction
+*/
+size_t gridInqYvals(int gridID, double *yvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYVals(gridptr, yvals);
+}
 
-  if (gridptr->lcomplex != lcomplex)
-    {
-      gridptr->lcomplex = (short)(lcomplex != 0);
-      gridMark4Update(gridID);
-    }
+
+size_t gridInqYCvals(int gridID, char **ycvals)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYCvals(gridptr, ycvals);
 }
 
 
-int gridInqComplexPacking(int gridID)
+int gridInqYIsc(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYIsc(gridptr);
+}
+
+static
+void gridDefYValsSerial(grid_t *gridptr, const double *yvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  int gridtype = gridptr->type;
+  size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+            ? gridptr->size : gridptr->y.size;
+
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d!", gridptr->self);
+
+  if ( gridptr->y.vals && CDI_Debug )
+    Warning("Values already defined!");
 
-  return gridptr->lcomplex;
+  gridptr->y.vals = (double *)Realloc(gridptr->y.vals, size * sizeof (double));
+  memcpy(gridptr->y.vals, yvals, size * sizeof (double));
 }
 
 
-void gridDefHasDims(int gridID, int hasdims)
+/*
+ at Function  gridDefYvals
+ at Title     Define the values of a Y-axis
+
+ at Prototype void gridDefYvals(int gridID, const double *yvals)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  yvals    Y-values of the grid.
+
+ at Description
+The function @func{gridDefYvals} defines all values of the Y-axis.
+
+ at EndFunction
+*/
+void gridDefYvals(int gridID, const double *yvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defYVals(gridptr, yvals);
+  gridMark4Update(gridID);
+}
 
-  if ( gridptr->hasdims != (hasdims != 0) )
-    {
-      gridptr->hasdims = hasdims != 0;
-      gridMark4Update(gridID);
-    }
+static double
+gridInqXValSerial(grid_t *gridptr, size_t index)
+{
+  double xval = gridptr->x.vals ? gridptr->x.vals[index] : 0;
+  return xval;
 }
 
 
-int gridInqHasDims(int gridID)
+double gridInqXval(int gridID, size_t index)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXVal(gridptr, index);
+}
 
-  return gridptr->hasdims;
+static double
+gridInqYValSerial(grid_t *gridptr, size_t index)
+{
+  double yval = gridptr->y.vals ? gridptr->y.vals[index] : 0;
+  return yval;
 }
 
 /*
- at Function  gridDefNumber
- at Title     Define the reference number for an unstructured grid
+ at Function
+ at Title
 
- at Prototype void gridDefNumber(int gridID, const int number)
+ at Prototype
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  number   Reference number for an unstructured grid.
+    @Item  Grid identifier
 
- at Description
-The function @func{gridDefNumber} defines the reference number for an unstructured grid.
+ at EndFunction
+*/
+double gridInqYval(int gridID, size_t index)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYVal(gridptr, index);
+}
+
+/*
+ at Function
+ at Title
+
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
 @EndFunction
 */
-void gridDefNumber(int gridID, const int number)
+double gridInqXinc(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  double xinc = gridptr->x.inc;
+  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
-  if ( gridptr->number != number )
+  if ( (! (fabs(xinc) > 0)) && xvals )
     {
-      gridptr->number = number;
-      gridMark4Update(gridID);
+      size_t xsize = gridptr->x.size;
+      if ( xsize > 1 )
+        {
+          xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
+          for ( size_t i = 2; i < xsize; i++ )
+            if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
+              {
+                xinc = 0;
+                break;
+              }
+
+          gridptr->x.inc = xinc;
+        }
     }
+
+  return xinc;
 }
 
 /*
- at Function  gridInqNumber
- at Title     Get the reference number to an unstructured grid
+ at Function
+ at Title
 
- at Prototype int gridInqNumber(int gridID)
+ at Prototype
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  Grid identifier
 
- at Description
-The function @func{gridInqNumber} returns the reference number to an unstructured grid.
+ at EndFunction
+*/
+double gridInqYinc(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  double yinc = gridptr->y.inc;
+  const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
+
+  if ( (! (fabs(yinc) > 0)) && yvals )
+    {
+      size_t ysize = gridptr->y.size;
+      if ( ysize > 1 )
+        {
+          yinc = yvals[1] - yvals[0];
+          double abs_yinc = fabs(yinc);
+          for ( size_t i = 2; i < ysize; i++ )
+            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
+              {
+                yinc = 0;
+                break;
+              }
+
+          gridptr->y.inc = yinc;
+        }
+    }
+
+  return yinc;
+}
+
+/*
+ at Function
+ at Title
+
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
- at Result
- at func{gridInqNumber} returns the reference number to an unstructured grid.
 @EndFunction
 */
-int gridInqNumber(int gridID)
+void gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
-  return gridptr->number;
+  *xpole = 0; *ypole = 0; *angle = 0;
+
+  const char *projection = "rotated_latitude_longitude";
+  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+  if ( mapping[0] && strcmp(mapping, projection) == 0 )
+    {
+      int atttype, attlen;
+      char attname[CDI_MAX_NAME+1];
+
+      int natts;
+      cdiInqNatts(gridID, CDI_GLOBAL, &natts);
+
+      for ( int iatt = 0; iatt < natts; ++iatt )
+        {
+          cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
+          if ( attlen != 1 ) continue;
+
+          double attflt;
+          if ( cdiInqAttConvertedToFloat(gridID, atttype, attname, attlen, &attflt) )
+            {
+              if      ( strcmp(attname, "grid_north_pole_longitude") == 0 ) *xpole = attflt;
+              else if ( strcmp(attname, "grid_north_pole_latitude")  == 0 ) *ypole = attflt;
+              else if ( strcmp(attname, "north_pole_grid_longitude") == 0 ) *angle = attflt;
+            }
+        }
+    }
+  else
+    Warning("%s mapping parameter missing!", projection);
 }
 
 /*
- at Function  gridDefPosition
- at Title     Define the position of grid in the reference file
+ at Function
+ at Title
 
- at Prototype void gridDefPosition(int gridID, const int position)
+ at Prototype
 @Parameter
-    @Item  gridID     Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  position   Position of grid in the reference file.
-
- at Description
-The function @func{gridDefPosition} defines the position of grid in the reference file.
+    @Item  Grid identifier
 
 @EndFunction
 */
-void gridDefPosition(int gridID, int position)
+void gridDefParamRLL(int gridID, double xpole, double ypole, double angle)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, "rotated_pole");
 
-  if ( gridptr->position != position )
-    {
-      gridptr->position = position;
-      gridMark4Update(gridID);
-    }
+  const char *mapping = "rotated_latitude_longitude";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(mapping)), mapping);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_longitude", CDI_DATATYPE_FLT64, 1, &xpole);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_latitude", CDI_DATATYPE_FLT64, 1, &ypole);
+  if ( IS_NOT_EQUAL(angle, 0) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "north_pole_grid_longitude", CDI_DATATYPE_FLT64, 1, &angle);
+
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->projtype = CDI_PROJ_RLL;
+
+  gridVerifyProj(gridID);
 }
 
 /*
- at Function  gridInqPosition
- at Title     Get the position of grid in the reference file
+ at Function
+ at Title
 
- at Prototype int gridInqPosition(int gridID)
+ at Prototype
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqPosition} returns the position of grid in the reference file.
+    @Item  Grid identifier
 
- at Result
- at func{gridInqPosition} returns the position of grid in the reference file.
 @EndFunction
 */
-int gridInqPosition(int gridID)
+void gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  return gridptr->position;
+  *nd  = gridptr->gme.nd;
+  *ni  = gridptr->gme.ni;
+  *ni2 = gridptr->gme.ni2;
+  *ni3 = gridptr->gme.ni3;
 }
 
 /*
- at Function  gridDefReference
- at Title     Define the reference URI for an unstructured grid
+ at Function
+ at Title
 
- at Prototype void gridDefReference(int gridID, const char *reference)
+ at Prototype
 @Parameter
-    @Item  gridID      Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  reference   Reference URI for an unstructured grid.
-
- at Description
-The function @func{gridDefReference} defines the reference URI for an unstructured grid.
+    @Item  Grid identifier
 
 @EndFunction
 */
-void gridDefReference(int gridID, const char *reference)
+void gridDefParamGME(int gridID, int nd, int ni, int ni2, int ni3)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( reference )
+  if ( gridptr->gme.nd != nd )
     {
-      if ( gridptr->reference )
-        {
-          Free(gridptr->reference);
-          gridptr->reference = NULL;
-        }
-
-      gridptr->reference = strdupx(reference);
+      gridptr->gme.nd  = nd;
+      gridptr->gme.ni  = ni;
+      gridptr->gme.ni2 = ni2;
+      gridptr->gme.ni3 = ni3;
       gridMark4Update(gridID);
     }
 }
 
 /*
- at Function  gridInqReference
- at Title     Get the reference URI to an unstructured grid
+ at Function
+ at Title
 
- at Prototype char *gridInqReference(int gridID, char *reference)
+ at Prototype
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqReference} returns the reference URI to an unstructured grid.
+    @Item  Grid identifier
 
- at Result
- at func{gridInqReference} returns the reference URI to an unstructured grid.
 @EndFunction
 */
-int gridInqReference(int gridID, char *reference)
+void gridChangeType(int gridID, int gridtype)
 {
-  size_t len = 0;
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->reference )
+  if ( CDI_Debug )
+    Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
+
+  if (gridptr->type != gridtype)
     {
-      len = strlen(gridptr->reference);
-      if ( reference )
-        strcpy(reference, gridptr->reference);
+      gridptr->type = gridtype;
+      gridMark4Update(gridID);
     }
-
-  return (int)len;
 }
 
-const char *gridInqReferencePtr(int gridID)
+static
+void grid_check_cyclic(grid_t *gridptr)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->reference;
-}
+  gridptr->isCyclic = 0;
+  enum { numVertices = 4 };
+  size_t xsize = gridptr->x.size,
+         ysize = gridptr->y.size;
+  const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
+               *yvals = gridptr->vtable->inqYValsPtr(gridptr),
+    (*xbounds)[numVertices]
+    = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
 
-/*
- at Function  gridDefUUID
- at Title     Define the UUID for an unstructured grid
+  if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
+    {
+      if ( xvals && xsize > 1 )
+        {
+          double xval1 = xvals[0];
+          double xval2 = xvals[1];
+          double xvaln = xvals[xsize-1];
+          if ( xval2 < xval1 ) xval2 += 360;
+          if ( xvaln < xval1 ) xvaln += 360;
 
- at Prototype void gridDefUUID(int gridID, const char *uuid)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  uuid     UUID for an unstructured grid.
+          if ( IS_NOT_EQUAL(xval1, xvaln) )
+            {
+              double xinc = xval2 - xval1;
+              if ( IS_EQUAL(xinc, 0) ) xinc = (xvaln - xval1)/(xsize-1);
 
- at Description
-The function @func{gridDefUUID} defines the UUID for an unstructured grid.
+              double x0 = xvaln + xinc - 360;
 
- at EndFunction
-*/
-void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
-{
-  grid_t* gridptr = gridID2Ptr(gridID);
+              if ( fabs(x0 - xval1) < 0.01*xinc ) gridptr->isCyclic = 1;
+            }
+        }
+    }
+  else if ( gridptr->type == GRID_CURVILINEAR )
+    {
+      bool lcheck = true;
+      if ( yvals && xvals )
+        {
+          if ( (fabs(yvals[0] - yvals[xsize-1]) > fabs(yvals[0] - yvals[xsize*ysize-xsize])) &&
+               (fabs(yvals[xsize*ysize-xsize] - yvals[xsize*ysize-1]) > fabs(yvals[xsize-1] - yvals[xsize*ysize-1])) )
+            lcheck = false;
+        }
+      else lcheck = false;
 
-  memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
-  gridMark4Update(gridID);
-}
+      if ( lcheck && xvals && xsize > 1 )
+        {
+          size_t nc = 0;
+          for ( size_t j = 0; j < ysize; ++j )
+            {
+              size_t i1 = j*xsize,
+                     i2 = j*xsize+1,
+                     in = j*xsize+(xsize-1);
+              double val1 = xvals[i1],
+                     val2 = xvals[i2],
+                     valn = xvals[in];
+              double xinc = fabs(val2-val1);
 
-/*
- at Function  gridInqUUID
- at Title     Get the UUID to an unstructured grid
+	      if ( val1 <    1 && valn > 300 ) val1 += 360;
+	      if ( valn <    1 && val1 > 300 ) valn += 360;
+	      if ( val1 < -179 && valn > 120 ) val1 += 360;
+	      if ( valn < -179 && val1 > 120 ) valn += 360;
+              if ( fabs(valn-val1) > 180 ) val1 += 360;
 
- at Prototype void gridInqUUID(int gridID, char *uuid)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+              double x0 = valn + copysign(xinc, val1 - valn);
 
- at Description
-The function @func{gridInqUUID} returns the UUID to an unstructured grid.
+              nc += fabs(x0-val1) < 0.5*xinc;
+            }
+          gridptr->isCyclic = nc > ysize/2;
+        }
 
- at Result
- at func{gridInqUUID} returns the UUID to an unstructured grid to the parameter uuid.
- at EndFunction
-*/
-void gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE])
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      if ( lcheck && xbounds && xsize > 1 )
+	{
+          bool isCyclic = true;
+	  for ( size_t j = 0; j < ysize; ++j )
+	    {
+	      size_t i1 = j*xsize,
+                     i2 = j*xsize+(xsize-1);
+	      for (size_t k1 = 0; k1 < numVertices; ++k1 )
+		{
+		  double val1 = xbounds[i1][k1];
+		  for (size_t k2 = 0; k2 < numVertices; ++k2 )
+		    {
+		      double val2 = xbounds[i2][k2];
 
-  memcpy(uuid, gridptr->uuid, CDI_UUID_SIZE);
+		      if ( val1 <    1 && val2 > 300 ) val1 += 360;
+		      if ( val2 <    1 && val1 > 300 ) val2 += 360;
+		      if ( val1 < -179 && val2 > 120 ) val1 += 360;
+		      if ( val2 < -179 && val1 > 120 ) val2 += 360;
+                      if ( fabs(val2-val1) > 180 ) val1 += 360;
+
+		      if ( fabs(val1-val2) < 0.001 )
+                        goto foundCloseVertices;
+		    }
+		}
+              /* all vertices more than 0.001 degrees apart */
+              isCyclic = false;
+              break;
+              foundCloseVertices:
+              ;
+	    }
+          gridptr->isCyclic = isCyclic;
+	}
+    }
 }
 
 
-void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
+int gridIsCircular(int gridID)
 {
-  reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
 
+  if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
 
-static int
-gridTxCode ()
-{
-  return GRID;
+  return gridptr->isCyclic;
 }
 
-enum { gridNint    = 28,
-       gridNdouble = 24,
-       gridHasMaskFlag = 1 << 0,
-       gridHasGMEMaskFlag = 1 << 1,
-       gridHasXValsFlag = 1 << 2,
-       gridHasYValsFlag = 1 << 3,
-       gridHasAreaFlag = 1 << 4,
-       gridHasXBoundsFlag = 1 << 5,
-       gridHasYBoundsFlag = 1 << 6,
-       gridHasReferenceFlag = 1 << 7,
-       gridHasRowLonFlag = 1 << 8,
-       gridHasUUIDFlag = 1 << 9,
-};
+static
+bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
+{
+  bool differ = false;
 
+  size_t xsizeTest = gridTest->x.size, ysizeTest = gridTest->y.size;
+  if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
+    {
+      const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
+        *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
 
-static int gridGetComponentFlags(const grid_t * gridP)
-{
-  int flags = (gridHasMaskFlag & (int)((unsigned)(gridP->mask == NULL) - 1U))
-    | (gridHasGMEMaskFlag & (int)((unsigned)(gridP->mask_gme == NULL) - 1U))
-    | (gridHasXValsFlag
-       & (int)((unsigned)(gridP->vtable->inqXValsPtr((grid_t *)gridP) == NULL) - 1U))
-    | (gridHasYValsFlag
-       & (int)((unsigned)(gridP->vtable->inqYValsPtr((grid_t *)gridP) == NULL) - 1U))
-    | (gridHasAreaFlag
-       & (int)((unsigned)(gridP->vtable->inqAreaPtr((grid_t *)gridP) == NULL)
-               - 1U))
-    | (gridHasXBoundsFlag & (int)((unsigned)(gridP->xbounds == NULL) - 1U))
-    | (gridHasYBoundsFlag & (int)((unsigned)(gridP->ybounds == NULL) - 1U))
-    | (gridHasReferenceFlag & (int)((unsigned)(gridP->reference == NULL) - 1U))
-    | (gridHasRowLonFlag & (int)((unsigned)(gridP->rowlon == NULL) - 1U))
-    | (gridHasUUIDFlag & (int)((unsigned)cdiUUIDIsNull(gridP->uuid) - 1U));
-  return flags;
+      for ( size_t i = 0; i < xsizeTest; ++i )
+	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
+	  {
+	    differ = true;
+	    break;
+	  }
+    }
+
+  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
+    {
+      const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
+        *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
+      for ( size_t i = 0; i < ysizeTest; ++i )
+	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
+	  {
+	    differ = true;
+	    break;
+	  }
+    }
+
+  return differ;
 }
 
-static int
-gridGetPackSize(void * voidP, void *context)
+static
+bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
 {
-  grid_t * gridP = ( grid_t * ) voidP;
-  int packBuffSize = 0, count;
+  size_t gridsize = gridTest->size;
+  bool differ = ((gridTest->x.vals == NULL) ^ (gridRef->x.vals == NULL))
+             || ((gridTest->y.vals == NULL) ^ (gridRef->y.vals == NULL));
 
-  packBuffSize += serializeGetSize(gridNint, DATATYPE_INT, context)
-    + serializeGetSize(1, DATATYPE_UINT32, context);
+  typedef double (*inqVal)(grid_t *grid, size_t index);
+  inqVal inqXValRef = gridRef->vtable->inqXVal,
+         inqYValRef = gridRef->vtable->inqYVal,
+         inqXValTest = gridTest->vtable->inqXVal,
+         inqYValTest = gridTest->vtable->inqYVal;
 
-  if (gridP->rowlon)
-    {
-      xassert(gridP->nrowlon);
-      packBuffSize += serializeGetSize(gridP->nrowlon, DATATYPE_INT, context)
-        + serializeGetSize( 1, DATATYPE_UINT32, context);
-    }
+  if ( !differ && gridTest->x.vals )
+    differ = fabs(inqXValTest(gridTest, 0) - inqXValRef(gridRef, 0)) > 1.e-9
+          || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
 
-  packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
+  if ( !differ && gridTest->y.vals )
+    differ = fabs(inqYValTest(gridTest, 0) - inqYValRef(gridRef, 0)) > 1.e-9
+          || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
 
-  if (gridP->vtable->inqXValsPtr(gridP))
-    {
-      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
-	count = gridP->size;
-      else
-	count = gridP->xsize;
-      xassert(count);
-      packBuffSize += serializeGetSize(count, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+  return differ;
+}
 
-  if (gridP->vtable->inqYValsPtr(gridP))
-    {
-      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
-	count = gridP->size;
-      else
-	count = gridP->ysize;
-      xassert(count);
-      packBuffSize += serializeGetSize(count, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+static
+bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
+{
+  bool differ = true;
+  const grid_t *gridRef = grid_to_pointer(gridID);
 
-  if (gridP->vtable->inqAreaPtr(gridP))
+  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
     {
-      xassert(gridP->size);
-      packBuffSize +=
-        serializeGetSize(gridP->size, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      if ( grid->size == gridRef->size )
+	{
+	  differ = false;
+	  if ( grid->type == GRID_LONLAT || grid->type == GRID_PROJECTION )
+	    {
+	      /*
+	      printf("gridID      %d\n", gridID);
+	      printf("grid.xdef   %d\n", grid->x.flag);
+	      printf("grid.ydef   %d\n", grid->y.flag);
+	      printf("grid.xsize  %zu\n", grid->x.size);
+	      printf("grid.ysize  %zu\n", grid->y.size);
+	      printf("grid.xfirst %f\n", grid->x.first);
+	      printf("grid.yfirst %f\n", grid->y.first);
+	      printf("grid.xfirst %f\n", gridInqXval(gridID, 0));
+	      printf("grid.yfirst %f\n", gridInqYval(gridID, 0));
+	      printf("grid.xinc   %f\n", grid->x.inc);
+	      printf("grid.yinc   %f\n", grid->y.inc);
+	      printf("grid.xinc   %f\n", gridInqXinc(gridID));
+	      printf("grid.yinc   %f\n", gridInqYinc(gridID));
+	      */
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
+		{
+		  if ( grid->x.flag == 2 && grid->y.flag == 2 )
+		    {
+		      if ( ! (IS_EQUAL(grid->x.first, 0) && IS_EQUAL(grid->x.last, 0) && IS_EQUAL(grid->x.inc, 0)) &&
+			   ! (IS_EQUAL(grid->y.first, 0) && IS_EQUAL(grid->y.last, 0) && IS_EQUAL(grid->y.inc, 0)) &&
+			   IS_NOT_EQUAL(grid->x.first, grid->x.last) && IS_NOT_EQUAL(grid->y.first, grid->y.last) )
+			{
+			  if ( IS_NOT_EQUAL(grid->x.first, gridInqXval(gridID, 0)) ||
+			       IS_NOT_EQUAL(grid->y.first, gridInqYval(gridID, 0)))
+			    {
+			      differ = true;
+			    }
+			  if ( !differ && fabs(grid->x.inc) > 0 &&
+			       fabs(fabs(grid->x.inc) - fabs(gridRef->x.inc)) > fabs(grid->x.inc/1000))
+			    {
+			      differ = true;
+			    }
+			  if ( !differ && fabs(grid->y.inc) > 0 &&
+			       fabs(fabs(grid->y.inc) - fabs(gridRef->y.inc)) > fabs(grid->y.inc/1000))
+			    {
+			      differ = true;
+			    }
+			}
+		    }
+		  else if ( grid->x.vals && grid->y.vals )
+                    differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
+		}
+	      else
+		differ = true;
+	    }
+	  else if ( grid->type == GRID_GENERIC )
+	    {
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
+		{
+		  if ( grid->x.flag == 1 && grid->y.flag == 1
+                       && grid->x.vals && grid->y.vals )
+                    differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
+		}
+	      else if ( (grid->y.size == 0 || grid->y.size == 1) &&
+			grid->x.size == gridRef->x.size*gridRef->y.size )
+		{
+		}
+	      else
+		differ = true;
+	    }
+	  else if ( grid->type == GRID_GAUSSIAN )
+	    {
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
+		{
+		  if ( grid->x.flag == 2 && grid->y.flag == 2 )
+		    {
+		      if ( ! (IS_EQUAL(grid->x.first, 0) && IS_EQUAL(grid->x.last, 0) && IS_EQUAL(grid->x.inc, 0)) &&
+			   ! (IS_EQUAL(grid->y.first, 0) && IS_EQUAL(grid->y.last, 0)) )
+			if ( fabs(grid->x.first - gridInqXval(gridID, 0)) > 0.0015 ||
+			     fabs(grid->y.first - gridInqYval(gridID, 0)) > 0.0015 ||
+			     (fabs(grid->x.inc)>0 && fabs(fabs(grid->x.inc) - fabs(gridRef->x.inc)) > fabs(grid->x.inc/1000)) )
+			  {
+			    differ = true;
+			  }
+		    }
+		  else if ( grid->x.vals && grid->y.vals )
+                    differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
+		}
+	      else
+		differ = true;
+	    }
+	  else if ( grid->type == GRID_CURVILINEAR )
+	    {
+	      /*
+	      printf("gridID      %d\n", gridID);
+	      printf("grid.xsize  %d\n", grid->x.size);
+	      printf("grid.ysize  %d\n", grid->y.size);
+	      printf("grid.xfirst %f\n", grid->x.vals[0]);
+	      printf("grid.yfirst %f\n", grid->y.vals[0]);
+	      printf("grid xfirst %f\n", gridInqXval(gridID, 0));
+	      printf("grid yfirst %f\n", gridInqYval(gridID, 0));
+	      printf("grid.xlast  %f\n", grid->x.vals[grid->size-1]);
+	      printf("grid.ylast  %f\n", grid->y.vals[grid->size-1]);
+	      printf("grid xlast  %f\n", gridInqXval(gridID, grid->size-1));
+	      printf("grid ylast  %f\n", gridInqYval(gridID, grid->size-1));
+	      printf("grid.nv     %d\n", grid->nvertex);
+	      printf("grid nv     %d\n", gridInqNvertex(gridID));
+	      */
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
+                differ = gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
+	    }
+	  else if ( grid->type == GRID_UNSTRUCTURED )
+	    {
+              if ( coord_compare )
+                {
+                  differ = grid->nvertex != gridRef->nvertex
+                    || gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
+                }
+              else
+                {
+                  /* FIXME: not octet 0 but octet 7 is guaranteed  non-zero for any non-NULL UUID */
+                  differ = differ || (gridRef->uuid[0] && grid->uuid[0] && memcmp(gridRef->uuid, grid->uuid, CDI_UUID_SIZE) != 0);
+
+                  if ( !differ &&
+                       ((grid->x.vals == NULL) ^ (gridRef->x.vals == NULL)) &&
+                       ((grid->y.vals == NULL) ^ (gridRef->y.vals == NULL)) )
+                    {
+                      int nvertexA, nvertexB, numberA, numberB;
+                      differ = ( (nvertexA = grid->nvertex)
+                                 && (nvertexB = gridRef->nvertex)
+                                 && (nvertexA != nvertexB) )
+                        || (numberA = grid->number, numberB = gridRef->number,
+                            ( (numberA)
+                              && numberB
+                              && (numberA != numberB) )
+                            || ( (numberA && numberB)
+                                 && (grid->position) != (gridRef->position) ) );
+                    }
+                  else if ( !differ )
+                    {
+                      differ = grid->nvertex != gridRef->nvertex
+                        || grid->number != gridRef->number
+                        || (grid->number > 0 && grid->position != gridRef->position)
+                        || gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
+                    }
+                }
+            }
+	}
     }
 
-  if (gridP->xbounds)
+  if ( (grid->scanningMode != gridInqScanningMode(gridID)) || (grid->uvRelativeToGrid != gridInqUvRelativeToGrid(gridID)) )
     {
-      xassert(gridP->nvertex);
-      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
-	count = gridP->size;
-      else
-	count = gridP->xsize;
-      xassert(count);
-      packBuffSize
-        += (serializeGetSize(gridP->nvertex * count, DATATYPE_FLT64, context)
-            + serializeGetSize(1, DATATYPE_UINT32, context));
+      // often grid definition may differ in UV-relativeToGrid
+      differ = 1;
+#ifdef HIRLAM_EXTENSIONS
+      if ( cdiDebugExt>=200 )
+        printf("gridCompare(gridID=%d): Differs: grid.scanningMode [%d] != gridInqScanningMode(gridID) [%d] or  grid.uvRelativeToGrid [%ld] != gridInqUvRelativeToGrid(gridID) [%d]\n",
+               gridID, grid->scanningMode, gridInqScanningMode(gridID), grid->uvRelativeToGrid, gridInqUvRelativeToGrid(gridID) );
+#endif // HIRLAM_EXTENSIONS
     }
+  return differ;
+}
+
+/*
+int gridIsEqual(int gridID1, int gridID2)
+{
+  const grid_t *grid2 = grid_to_pointer(gridID2);
+
+  int grid_is_equal = gridCompare(gridID1, grid2, true) == false;
+
+  return grid_is_equal;
+}
+*/
+
+int gridCompareP(void *gridptr1, void *gridptr2)
+{
+  grid_t *g1 = ( grid_t * ) gridptr1;
+  grid_t *g2 = ( grid_t * ) gridptr2;
+  enum { equal = 0,
+         differ = -1 };
+  size_t i, size;
+
+  xassert ( g1 );
+  xassert ( g2 );
+
+  if ( g1->type          != g2->type         ) return differ;
+  if ( g1->datatype      != g2->datatype     ) return differ;
+  if ( g1->isCyclic      != g2->isCyclic     ) return differ;
+  if ( g1->x.flag        != g2->x.flag       ) return differ;
+  if ( g1->y.flag        != g2->y.flag       ) return differ;
+  if ( g1->gme.nd        != g2->gme.nd       ) return differ;
+  if ( g1->gme.ni        != g2->gme.ni       ) return differ;
+  if ( g1->gme.ni2       != g2->gme.ni2      ) return differ;
+  if ( g1->gme.ni3       != g2->gme.ni3      ) return differ;
+  if ( g1->number        != g2->number       ) return differ;
+  if ( g1->position      != g2->position     ) return differ;
+  if ( g1->trunc         != g2->trunc        ) return differ;
+  if ( g1->nvertex       != g2->nvertex      ) return differ;
+  if ( g1->nrowlon       != g2->nrowlon      ) return differ;
+  if ( g1->size          != g2->size         ) return differ;
+  if ( g1->x.size        != g2->x.size       ) return differ;
+  if ( g1->y.size        != g2->y.size       ) return differ;
+  if ( g1->lcomplex      != g2->lcomplex     ) return differ;
 
-  if (gridP->ybounds)
+  if ( IS_NOT_EQUAL(g1->x.first       , g2->x.first)       ) return differ;
+  if ( IS_NOT_EQUAL(g1->y.first	      , g2->y.first)       ) return differ;
+  if ( IS_NOT_EQUAL(g1->x.last        , g2->x.last)        ) return differ;
+  if ( IS_NOT_EQUAL(g1->y.last        , g2->y.last)        ) return differ;
+  if ( IS_NOT_EQUAL(g1->x.inc	      , g2->x.inc)         ) return differ;
+  if ( IS_NOT_EQUAL(g1->y.inc	      , g2->y.inc)         ) return differ;
+  if ( IS_NOT_EQUAL(g1->uvRelativeToGrid     , g2->uvRelativeToGrid)     ) return differ;
+  if ( IS_NOT_EQUAL(g1->scanningMode         , g2->scanningMode)         ) return differ;
+
+  const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
+               *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_xvals )
     {
-      xassert(gridP->nvertex);
-      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
-	count = gridP->size;
+      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
+        size = g1->size;
       else
-	count = gridP->ysize;
-      xassert(count);
-      packBuffSize
-        += (serializeGetSize(gridP->nvertex * count, DATATYPE_FLT64, context)
-            + serializeGetSize(1, DATATYPE_UINT32, context));
-    }
+        size = g1->x.size;
+      xassert ( size );
 
-  {
-    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = (int)(sizeof (strTab) / sizeof (strTab[0]));
-    packBuffSize
-      += serializeStrTabGetPackSize(strTab, numStr, context);
-  }
+      if ( !g2_xvals ) return differ;
 
-  if (gridP->reference)
-    {
-      size_t len = strlen(gridP->reference);
-      packBuffSize += serializeGetSize(1, DATATYPE_INT, context)
-        + serializeGetSize((int)len + 1, DATATYPE_TXT, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      for ( i = 0; i < size; i++ )
+        if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
     }
+  else if ( g2_xvals )
+    return differ;
 
-  if (gridP->mask)
+  const double *restrict g1_yvals = g1->vtable->inqYValsPtr(g1),
+               *restrict g2_yvals = g2->vtable->inqYValsPtr(g2);
+  if ( g1_yvals )
     {
-      xassert(gridP->size);
-      packBuffSize
-        += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
+	size = g1->size;
+      else
+	size = g1->y.size;
+      xassert ( size );
 
-  if (gridP->mask_gme)
-    {
-      xassert(gridP->size);
-      packBuffSize += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+      if ( !g2_yvals ) return differ;
 
-  if (!cdiUUIDIsNull(gridP->uuid))
-    packBuffSize += serializeGetSize(CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+      for ( i = 0; i < size; i++ )
+        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
+    }
+  else if ( g2_yvals )
+    return differ;
 
-  return packBuffSize;
-}
+  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
+               *restrict g2_area = g2->vtable->inqAreaPtr(g2);
+  if ( g1_area )
+    {
+      xassert ( g1->size );
 
-void
-gridUnpack(char * unpackBuffer, int unpackBufferSize,
-           int * unpackBufferPos, int originNamespace, void *context,
-           int force_id)
-{
-  grid_t * gridP;
-  uint32_t d;
-  int memberMask, size;
+      if ( !g2_area ) return differ;
 
-  gridInit();
+      for ( i = 0; i < g1->size; i++ )
+	if ( IS_NOT_EQUAL(g1_area[i], g2_area[i]) ) return differ;
+    }
+  else if ( g2_area )
+    return differ;
 
   {
-    int intBuffer[gridNint];
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    intBuffer, gridNint, DATATYPE_INT, context);
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    &d, 1, DATATYPE_UINT32, context);
-
-    xassert(cdiCheckSum(DATATYPE_INT, gridNint, intBuffer) == d);
-    int targetID = namespaceAdaptKey(intBuffer[0], originNamespace);
-    gridP = gridNewEntry(force_id?targetID:CDI_UNDEFID);
+    const double *restrict g1_xbounds, *restrict g2_xbounds;
+    if ( (g1_xbounds = g1->vtable->inqXBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->x.size;
+        xassert ( size );
 
-    xassert(!force_id || targetID == gridP->self);
+        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
 
-    gridP->type          =   intBuffer[1];
-    gridP->prec          =   intBuffer[2];
-    gridP->lcc_projflag  =   intBuffer[3];
-    gridP->lcc_scanflag  =   intBuffer[4];
-    gridP->lcc_defined   =   (short)intBuffer[5];
-    gridP->lcc2_defined  =   (short)intBuffer[6];
-    gridP->laea_defined  =   intBuffer[7];
-    gridP->isCyclic      =   (short)intBuffer[8];
-    gridP->isRotated     =   (short)intBuffer[9];
-    gridP->xdef          =   (short)intBuffer[10];
-    gridP->ydef          =   (short)intBuffer[11];
-    gridP->nd            =   intBuffer[12];
-    gridP->ni            =   intBuffer[13];
-    gridP->ni2           =   intBuffer[14];
-    gridP->ni3           =   intBuffer[15];
-    gridP->number        =   intBuffer[16];
-    gridP->position      =   intBuffer[17];
-    gridP->trunc         =   intBuffer[18];
-    gridP->nvertex       =   intBuffer[19];
-    gridP->nrowlon       =   intBuffer[20];
-    gridP->size          =   intBuffer[21];
-    gridP->xsize         =   intBuffer[22];
-    gridP->ysize         =   intBuffer[23];
-    gridP->lcomplex      =   (short)intBuffer[24];
-    memberMask           =   intBuffer[25];
-    gridP->xstdname      =   xystdname_tab[intBuffer[26]][0];
-    gridP->ystdname      =   xystdname_tab[intBuffer[27]][1];
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1_xbounds[i], g2_xbounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqXBoundsPtr(g2) )
+      return differ;
   }
 
-  if (memberMask & gridHasRowLonFlag)
-    {
-      xassert(gridP->nrowlon);
-      gridP->rowlon = (int *) Malloc((size_t)gridP->nrowlon * sizeof (int));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->rowlon, gridP->nrowlon , DATATYPE_INT, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_INT, gridP->nrowlon, gridP->rowlon) == d);
-    }
-
   {
-    double doubleBuffer[gridNdouble];
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    doubleBuffer, gridNdouble, DATATYPE_FLT64, context);
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    &d, 1, DATATYPE_UINT32, context);
-    xassert(d == cdiCheckSum(DATATYPE_FLT, gridNdouble, doubleBuffer));
-
-    gridP->xfirst = doubleBuffer[0];
-    gridP->yfirst = doubleBuffer[1];
-    gridP->xlast = doubleBuffer[2];
-    gridP->ylast = doubleBuffer[3];
-    gridP->xinc = doubleBuffer[4];
-    gridP->yinc = doubleBuffer[5];
-    gridP->lcc_originLon = doubleBuffer[6];
-    gridP->lcc_originLat = doubleBuffer[7];
-    gridP->lcc_lonParY = doubleBuffer[8];
-    gridP->lcc_lat1 = doubleBuffer[9];
-    gridP->lcc_lat2 = doubleBuffer[10];
-    gridP->lcc_xinc = doubleBuffer[11];
-    gridP->lcc_yinc = doubleBuffer[12];
-    gridP->lcc2_lon_0 = doubleBuffer[13];
-    gridP->lcc2_lat_0 = doubleBuffer[14];
-    gridP->lcc2_lat_1 = doubleBuffer[15];
-    gridP->lcc2_lat_2 = doubleBuffer[16];
-    gridP->lcc2_a = doubleBuffer[17];
-    gridP->laea_lon_0 = doubleBuffer[18];
-    gridP->laea_lat_0 = doubleBuffer[19];
-    gridP->laea_a = doubleBuffer[20];
-    gridP->xpole = doubleBuffer[21];
-    gridP->ypole = doubleBuffer[22];
-    gridP->angle = doubleBuffer[23];
+    const double *restrict g1_ybounds, *restrict g2_ybounds;
+    if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
+      {
+        xassert ( g1->nvertex );
+        if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
+          size = g1->nvertex * g1->size;
+        else
+          size = g1->nvertex * g1->y.size;
+        xassert ( size );
+
+        if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
+
+        for ( i = 0; i < size; i++ )
+          if ( IS_NOT_EQUAL(g1->y.bounds[i], g2->y.bounds[i]) ) return differ;
+      }
+    else if ( g2->vtable->inqYBoundsPtr(g2) )
+      return differ;
   }
 
-  int irregular = gridP->type == GRID_UNSTRUCTURED
-    || gridP->type == GRID_CURVILINEAR;
-  if (memberMask & gridHasXValsFlag)
-    {
-      size = irregular ? gridP->size : gridP->xsize;
+  if (strcmp(g1->x.name, g2->x.name)) return differ;
+  if (strcmp(g1->y.name, g2->y.name)) return differ;
+  if (strcmp(g1->x.longname, g2->x.longname)) return differ;
+  if (strcmp(g1->y.longname, g2->y.longname)) return differ;
+  if (g1->x.stdname != g2->x.stdname) return differ;
+  if (g1->y.stdname != g2->y.stdname) return differ;
+  if (strcmp(g1->x.units, g2->x.units)) return differ;
+  if (strcmp(g1->y.units, g2->y.units)) return differ;
 
-      gridP->xvals = (double *) Malloc((size_t)size * sizeof (double));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->xvals, size, DATATYPE_FLT64, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->xvals) == d );
-    }
+  if (strcmp(g1->mapping, g2->mapping)) return differ;
 
-  if (memberMask & gridHasYValsFlag)
+  if ( g1->reference )
     {
-      size = irregular ? gridP->size : gridP->ysize;
-
-      gridP->yvals = (double *) Malloc((size_t)size * sizeof (double));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->yvals, size, DATATYPE_FLT64, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->yvals) == d);
+      if ( !g2->reference ) return differ;
+      if ( strcmp(g1->reference, g2->reference) ) return differ;
     }
+  else if ( g2->reference )
+    return differ;
 
-  if (memberMask & gridHasAreaFlag)
+  if ( g1->mask )
     {
-      size = gridP->size;
-      xassert(size);
-      gridP->area = (double *) Malloc((size_t)size * sizeof (double));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->area, size, DATATYPE_FLT64, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->area) == d);
+      xassert ( g1->size );
+      if ( !g2->mask ) return differ;
+      if ( memcmp ( g1->mask, g2->mask, g1->size * sizeof(mask_t)) ) return differ;
     }
+  else if ( g2->mask )
+    return differ;
 
-  if (memberMask & gridHasXBoundsFlag)
+  if ( g1->mask_gme )
     {
-      size = gridP->nvertex * (irregular ? gridP->size : gridP->xsize);
-      xassert(size);
-
-      gridP->xbounds = (double *) Malloc((size_t)size * sizeof (double));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->xbounds, size, DATATYPE_FLT64, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->xbounds) == d);
+      xassert ( g1->size );
+      if ( !g2->mask_gme ) return differ;
+      if ( memcmp ( g1->mask_gme, g2->mask_gme, g1->size * sizeof(mask_t)) ) return differ;
     }
+  else if ( g2->mask_gme )
+    return differ;
 
-  if (memberMask & gridHasYBoundsFlag)
-    {
-      size = gridP->nvertex * (irregular ? gridP->size : gridP->ysize);
-      xassert(size);
+  if ( memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE) )
+    return differ;
 
-      gridP->ybounds = (double *) Malloc((size_t)size * sizeof (double));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-			  gridP->ybounds, size, DATATYPE_FLT64, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->ybounds) == d);
-    }
+  return equal;
+}
 
-  {
-    char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = sizeof (strTab) / sizeof (strTab[0]);
-    serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                          strTab, numStr, context);
-  }
+static
+void gridComplete(grid_t *grid)
+{
+  int gridID = grid->self;
+  gridDefDatatype(gridID, grid->datatype);
 
-  if (memberMask & gridHasReferenceFlag)
+  int gridtype = grid->type;
+  switch (gridtype)
     {
-      int referenceSize;
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &referenceSize, 1, DATATYPE_INT, context);
-      gridP->reference = (char *) Malloc((size_t)referenceSize);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->reference, referenceSize, DATATYPE_TXT, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_TXT, referenceSize, gridP->reference) == d);
-    }
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_UNSTRUCTURED:
+    case GRID_CURVILINEAR:
+    case GRID_GENERIC:
+    case GRID_PROJECTION:
+    case GRID_CHARXY:
+      {
+	if ( grid->x.size > 0 ) gridDefXsize(gridID, grid->x.size);
+	if ( grid->y.size > 0 ) gridDefYsize(gridID, grid->y.size);
 
-  if (memberMask & gridHasMaskFlag)
-    {
-      xassert((size = gridP->size));
-      gridP->mask = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->mask, gridP->size, DATATYPE_UCHAR, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_UCHAR, gridP->size, gridP->mask) == d);
-    }
+        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
 
-  if (memberMask & gridHasGMEMaskFlag)
-    {
-      xassert((size = gridP->size));
-      gridP->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->mask_gme, gridP->size, DATATYPE_UCHAR, context);
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_UCHAR, gridP->size, gridP->mask_gme) == d);
-    }
-  if (memberMask & gridHasUUIDFlag)
-    {
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR, context);
-    }
+	if ( grid->nvertex > 0 )
+	  gridDefNvertex(gridID, grid->nvertex);
 
-  reshSetStatus(gridP->self, &gridOps,
-                reshGetStatus(gridP->self, &gridOps) & ~RESH_SYNC_BIT);
-}
+	if ( grid->x.flag == 2 )
+	  {
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *xvals = (double *) Malloc(grid->x.size * sizeof (double));
+	    gridGenXvals(grid->x.size, grid->x.first, grid->x.last, grid->x.inc, xvals);
+	    grid->x.vals = xvals;
+	    // gridDefXinc(gridID, grid->x.inc);
+	  }
 
+	if ( grid->y.flag == 2 )
+	  {
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
+	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
+	    grid->y.vals = yvals;
+	    // gridDefYinc(gridID, grid->y.inc);
+	  }
 
-static void
-gridPack(void * voidP, void * packBuffer, int packBufferSize,
-         int * packBufferPos, void *context)
-{
-  grid_t   * gridP = ( grid_t * )   voidP;
-  int size;
-  uint32_t d;
-  int memberMask;
+	if ( grid->projtype == CDI_PROJ_RLL )
+	  {
+	    if ( grid->x.name[0] == 0 || grid->x.name[0] == 'x' ) strcpy(grid->x.name, "rlon");
+	    if ( grid->y.name[0] == 0 || grid->y.name[0] == 'y' ) strcpy(grid->y.name, "rlat");
+	    if ( grid->x.longname[0] == 0 ) strcpy(grid->x.longname, "longitude in rotated pole grid");
+	    if ( grid->y.longname[0] == 0 ) strcpy(grid->y.longname, "latitude in rotated pole grid");
+            grid->x.stdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+            grid->y.stdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+	    if ( grid->x.units[0] == 0 ) strcpy(grid->x.units, "degrees");
+	    if ( grid->y.units[0] == 0 ) strcpy(grid->y.units, "degrees");
+	  }
 
-  {
-    int intBuffer[gridNint];
+        if ( gridtype == GRID_UNSTRUCTURED )
+          {
+            int number = grid->number;
+            int position = grid->position >= 0 ? grid->position : 0;
+            if ( number > 0 ) gridDefNumber(gridID, number);
+            gridDefPosition(gridID, position);
+          }
 
-    intBuffer[0]  = gridP->self;
-    intBuffer[1]  = gridP->type;
-    intBuffer[2]  = gridP->prec;
-    intBuffer[3]  = gridP->lcc_projflag;
-    intBuffer[4]  = gridP->lcc_scanflag;
-    intBuffer[5]  = gridP->lcc_defined;
-    intBuffer[6]  = gridP->lcc2_defined;
-    intBuffer[7]  = gridP->laea_defined;
-    intBuffer[8]  = gridP->isCyclic;
-    intBuffer[9]  = gridP->isRotated;
-    intBuffer[10] = gridP->xdef;
-    intBuffer[11] = gridP->ydef;
-    intBuffer[12] = gridP->nd;
-    intBuffer[13] = gridP->ni;
-    intBuffer[14] = gridP->ni2;
-    intBuffer[15] = gridP->ni3;
-    intBuffer[16] = gridP->number;
-    intBuffer[17] = gridP->position;
-    intBuffer[18] = gridP->trunc;
-    intBuffer[19] = gridP->nvertex;
-    intBuffer[20] = gridP->nrowlon;
-    intBuffer[21] = gridP->size;
-    intBuffer[22] = gridP->xsize;
-    intBuffer[23] = gridP->ysize;
-    intBuffer[24] = gridP->lcomplex;
-    intBuffer[25] = memberMask = gridGetComponentFlags(gridP);
-    intBuffer[26] = (int)((const char (*)[2][24])gridP->xstdname
-                          - xystdname_tab);
-    intBuffer[27] = (int)((const char (*)[2][24])gridP->ystdname
-                          - (const char (*)[2][24])xystdname_tab[0][1]);
-
-    serializePack(intBuffer, gridNint, DATATYPE_INT,
-                  packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_INT, gridNint, intBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
-                  packBuffer, packBufferSize, packBufferPos, context);
-  }
+	break;
+      }
+    case GRID_GAUSSIAN_REDUCED:
+      {
+	gridDefNP(gridID, grid->np);
+	gridDefYsize(gridID, grid->y.size);
+        if ( grid->x.flag == 2 )
+          {
+            double xvals[2] = { grid->x.first, grid->x.last };
+            gridDefXvals(gridID, xvals);
+          }
 
-  if (memberMask & gridHasRowLonFlag)
-    {
-      size = gridP->nrowlon;
-      xassert(size > 0);
-      serializePack(gridP->rowlon, size, DATATYPE_INT,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_INT , size, gridP->rowlon);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+        if ( grid->y.flag == 2 )
+	  {
+	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
+	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
+            grid->y.vals = yvals;
+	    /*
+	    gridDefYinc(gridID, grid->y.inc);
+	    */
+	  }
+	break;
+      }
+    case GRID_SPECTRAL:
+      {
+        gridDefTrunc(gridID, grid->trunc);
+        if ( grid->lcomplex ) gridDefComplexPacking(gridID, 1);
+        break;
+      }
+    case GRID_FOURIER:
+      {
+	gridDefTrunc(gridID, grid->trunc);
+	break;
+      }
+    case GRID_GME:
+      {
+        gridDefParamGME(gridID, grid->gme.nd, grid->gme.ni, grid->gme.ni2, grid->gme.ni3);
+        break;
+      }
+      /*
+    case GRID_GENERIC:
+      {
+        if ( grid->x.size > 0 && grid->y.size > 0 )
+          {
+            gridDefXsize(gridID, grid->x.size);
+            gridDefYsize(gridID, grid->y.size);
+            if ( grid->x.vals ) gridDefXvals(gridID, grid->x.vals);
+            if ( grid->y.vals ) gridDefYvals(gridID, grid->y.vals);
+          }
+        break;
+      }
+      */
+    case GRID_TRAJECTORY:
+      {
+        gridDefXsize(gridID, 1);
+        gridDefYsize(gridID, 1);
+        break;
+      }
+    default:
+      {
+	Error("Gridtype %s unsupported!", gridNamePtr(gridtype));
+	break;
+      }
     }
 
-  {
-    double doubleBuffer[gridNdouble];
+  grid->x.name[CDI_MAX_NAME - 1] = 0;
+  grid->x.longname[CDI_MAX_NAME - 1] = 0;
+  grid->x.units[CDI_MAX_NAME - 1] = 0;
+  grid->y.name[CDI_MAX_NAME - 1] = 0;
+  grid->y.longname[CDI_MAX_NAME - 1] = 0;
+  grid->y.units[CDI_MAX_NAME - 1] = 0;
+}
 
-    doubleBuffer[0]  = gridP->xfirst;
-    doubleBuffer[1]  = gridP->yfirst;
-    doubleBuffer[2]  = gridP->xlast;
-    doubleBuffer[3]  = gridP->ylast;
-    doubleBuffer[4]  = gridP->xinc;
-    doubleBuffer[5]  = gridP->yinc;
-    doubleBuffer[6]  = gridP->lcc_originLon;
-    doubleBuffer[7]  = gridP->lcc_originLat;
-    doubleBuffer[8]  = gridP->lcc_lonParY;
-    doubleBuffer[9]  = gridP->lcc_lat1;
-    doubleBuffer[10] = gridP->lcc_lat2;
-    doubleBuffer[11] = gridP->lcc_xinc;
-    doubleBuffer[12] = gridP->lcc_yinc;
-    doubleBuffer[13] = gridP->lcc2_lon_0;
-    doubleBuffer[14] = gridP->lcc2_lat_0;
-    doubleBuffer[15] = gridP->lcc2_lat_1;
-    doubleBuffer[16] = gridP->lcc2_lat_2;
-    doubleBuffer[17] = gridP->lcc2_a;
-    doubleBuffer[18] = gridP->laea_lon_0;
-    doubleBuffer[19] = gridP->laea_lat_0;
-    doubleBuffer[20] = gridP->laea_a;
-    doubleBuffer[21] = gridP->xpole;
-    doubleBuffer[22] = gridP->ypole;
-    doubleBuffer[23] = gridP->angle;
-
-    serializePack(doubleBuffer, gridNdouble, DATATYPE_FLT64,
-                  packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_FLT, gridNdouble, doubleBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
-                  packBuffer, packBufferSize, packBufferPos, context);
-  }
+#define GRID_STR_SERIALIZE(gridP) { gridP->x.dimname, gridP->y.dimname,  \
+    gridP->vdimname, gridP->x.name, gridP->y.name,  \
+    gridP->x.longname, gridP->y.longname, \
+    gridP->x.units, gridP->y.units }
 
-  if (memberMask & gridHasXValsFlag)
+int gridGenerate(const grid_t *grid)
+{
+  int gridtype = grid->type;
+  int gridID = gridCreate(gridtype, grid->size);
+  grid_t *restrict gridptr = grid_to_pointer(gridID);
+  gridptr->datatype = grid->datatype;
+  gridptr->x.size = grid->x.size;
+  gridptr->y.size = grid->y.size;
+  gridptr->np = grid->np;
+  gridptr->nvertex = grid->nvertex;
+  gridptr->x.flag = grid->x.flag;
+  int valdef_group1 = 0;
+  static const int valdef_group1_tab[] = {
+    GRID_LONLAT, GRID_GAUSSIAN, GRID_UNSTRUCTURED, GRID_CURVILINEAR,
+    GRID_GENERIC, GRID_PROJECTION
+  };
+  for ( size_t i = 0; i < sizeof (valdef_group1_tab) / sizeof (valdef_group1_tab[0]); ++i)
+    valdef_group1 |= (gridtype == valdef_group1_tab[i]);
+  if ( valdef_group1 && grid->x.flag == 1 )
     {
-      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
-	size = gridP->size;
-      else
-	size = gridP->xsize;
-      xassert(size);
+      gridDefXvals(gridID, grid->x.vals);
+      if ( grid->x.bounds )
+        gridDefXbounds(gridID, grid->x.bounds);
+    }
+  gridptr->x.first = grid->x.first;
+  gridptr->x.last = grid->x.last;
+  gridptr->x.inc = grid->x.inc;
+  gridptr->y.flag = grid->y.flag;
+  if ( (valdef_group1 || gridtype == GRID_GAUSSIAN_REDUCED) && grid->y.flag == 1)
+    {
+      gridDefYvals(gridID, grid->y.vals);
+      if ( grid->y.bounds )
+        gridDefYbounds(gridID, grid->y.bounds);
+    }
+  gridptr->y.first = grid->y.first;
+  gridptr->y.last = grid->y.last;
+  gridptr->y.inc = grid->y.inc;
+  if ( valdef_group1 && grid->area)
+    gridDefArea(gridID, grid->area);
+  gridptr->number = grid->number;
+  gridptr->position = grid->position;
+  gridptr->uvRelativeToGrid       = grid->uvRelativeToGrid;
+  gridptr->scanningMode           = grid->scanningMode;
+  gridptr->iScansNegatively       = grid->iScansNegatively;
+  gridptr->jScansPositively       = grid->jScansPositively;
+  gridptr->jPointsAreConsecutive  = grid->jPointsAreConsecutive;
+  memcpy(gridptr->uuid, grid->uuid, CDI_UUID_SIZE);
+  if ( gridtype == GRID_UNSTRUCTURED && grid->reference )
+    gridDefReference(gridID, grid->reference);
+  if ( gridtype == GRID_PROJECTION )
+    gridptr->name = strdup(grid->name);
+  if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    gridDefRowlon(gridID, grid->y.size, grid->rowlon);
+  gridptr->trunc = grid->trunc;
+  gridptr->lcomplex = grid->lcomplex;
+  gridptr->gme.nd = grid->gme.nd;
+  gridptr->gme.ni = grid->gme.ni;
+  gridptr->gme.ni2 = grid->gme.ni2;
+  gridptr->gme.ni3 = grid->gme.ni3;
+  const char *grid_str_tab[] = GRID_STR_SERIALIZE(grid);
+  char *gridptr_str_tab[] = GRID_STR_SERIALIZE(gridptr);
+  for (size_t i = 0; i < sizeof (grid_str_tab) / sizeof (grid_str_tab[0]); ++i)
+    if ( grid_str_tab[i][0] )
+      memcpy(gridptr_str_tab[i], grid_str_tab[i], CDI_MAX_NAME);
+  gridComplete(gridptr);
 
-      const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
-      serializePack(gridP_xvals, size, DATATYPE_FLT64,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP_xvals);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+  return gridID;
+}
+
+static void
+grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
+  size_t gridsize = gridptrOrig->size;
+  int gridtype = gridptrOrig->type;
+  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
+  if ( nrowlon )
+    {
+      gridptrDup->rowlon = (int*) Malloc(nrowlon * sizeof(int));
+      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
     }
 
-  if (memberMask & gridHasYValsFlag)
+  if ( gridptrOrig->x.vals != NULL )
     {
-      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR )
-	size = gridP->size;
-      else
-	size = gridP->ysize;
-      xassert(size);
-      const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
-      serializePack(gridP_yvals, size, DATATYPE_FLT64,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP_yvals);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      size_t size = irregular ? gridsize : gridptrOrig->x.size;
+
+      gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
     }
 
-  if (memberMask & gridHasAreaFlag)
+  if ( gridptrOrig->y.vals != NULL )
     {
-      xassert(gridP->size);
+      size_t size  = irregular ? gridsize : gridptrOrig->y.size;
 
-      serializePack(gridP->area, gridP->size, DATATYPE_FLT64,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, gridP->size, gridP->area);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
     }
 
-  if (memberMask & gridHasXBoundsFlag)
+  if ( gridptrOrig->x.bounds != NULL )
     {
-      xassert ( gridP->nvertex );
-      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
-	size = gridP->nvertex * gridP->size;
-      else
-	size = gridP->nvertex * gridP->xsize;
-      xassert ( size );
+      size_t size  = (irregular ? gridsize : gridptrOrig->x.size)
+        * gridptrOrig->nvertex;
 
-      serializePack(gridP->xbounds, size, DATATYPE_FLT64,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->xbounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
     }
 
-  if (memberMask & gridHasYBoundsFlag)
+  if ( gridptrOrig->y.bounds != NULL )
     {
-      xassert(gridP->nvertex);
-      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
-	size = gridP->nvertex * gridP->size;
-      else
-	size = gridP->nvertex * gridP->ysize;
-      xassert ( size );
+      size_t size = (irregular ? gridsize : gridptrOrig->y.size)
+        * gridptrOrig->nvertex;
 
-      serializePack(gridP->ybounds, size, DATATYPE_FLT64,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->ybounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
     }
 
   {
-    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = sizeof (strTab) / sizeof (strTab[0]);
-    serializeStrTabPack(strTab, numStr,
-                        packBuffer, packBufferSize, packBufferPos, context);
+    const double *gridptrOrig_area
+      = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
+    if ( gridptrOrig_area != NULL )
+      {
+        size_t size = gridsize;
+
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
+      }
   }
 
-  if (memberMask & gridHasReferenceFlag)
+  if ( gridptrOrig->mask != NULL )
     {
-      size = (int)strlen(gridP->reference) + 1;
-      serializePack(&size, 1, DATATYPE_INT,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      serializePack(gridP->reference, size, DATATYPE_TXT,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_TXT, size, gridP->reference);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
-    }
+      size_t size = gridsize;
 
-  if (memberMask & gridHasMaskFlag)
-    {
-      xassert((size = gridP->size));
-      serializePack(gridP->mask, size, DATATYPE_UCHAR,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_UCHAR, size, gridP->mask);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
 
-  if (memberMask & gridHasGMEMaskFlag)
+  if ( gridptrOrig->mask_gme != NULL )
     {
-      xassert((size = gridP->size));
+      size_t size = gridsize;
 
-      serializePack(gridP->mask_gme, size, DATATYPE_UCHAR,
-                    packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_UCHAR, size, gridP->mask_gme);
-      serializePack(&d, 1, DATATYPE_UINT32,
-                    packBuffer, packBufferSize, packBufferPos, context);
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
     }
-
-  if (memberMask & gridHasUUIDFlag)
-    serializePack(gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR,
-                  packBuffer, packBufferSize, packBufferPos, context);
 }
 
-#undef GRID_STR_SERIALIZE
 
+/*
+ at Function  gridDuplicate
+ at Title     Duplicate a horizontal Grid
 
-struct gridCompareSearchState
+ at Prototype int gridDuplicate(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridDuplicate} duplicates a horizontal Grid.
+
+ at Result
+ at func{gridDuplicate} returns an identifier to the duplicated Grid.
+
+ at EndFunction
+*/
+int gridDuplicate(int gridID)
 {
-  int resIDValue;
-  const grid_t *queryKey;
-};
+  grid_t *gridptr = grid_to_pointer(gridID);
+  grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
+  int gridIDnew = reshPut(gridptrnew, &gridOps);
+  gridptrnew->self = gridIDnew;
+  return gridIDnew;
+}
 
-static enum cdiApplyRet
-gridCompareSearch(int id, void *res, void *data)
+
+void gridCompress(int gridID)
 {
-  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
-  (void)res;
-  if ( gridCompare(id, state->queryKey) == false )
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_UNSTRUCTURED )
     {
-      state->resIDValue = id;
-      return CDI_APPLY_STOP;
+      if ( gridptr->mask_gme != NULL )
+	{
+          size_t gridsize = gridInqSize(gridID);
+	  size_t nv = (size_t)gridptr->nvertex;
+          double *restrict area
+            = (double *)gridptr->vtable->inqAreaPtr(gridptr),
+            *restrict xvals = (double *)gridptr->vtable->inqXValsPtr((grid_t *)gridptr),
+            *restrict yvals = (double *)gridptr->vtable->inqYValsPtr((grid_t *)gridptr),
+            *restrict xbounds = (double *)gridptr->vtable->inqXBoundsPtr(gridptr),
+            *restrict ybounds = (double *)gridptr->vtable->inqYBoundsPtr(gridptr);
+          mask_t *restrict mask_gme = gridptr->mask_gme;
+          size_t *restrict selection = (size_t *)Malloc(gridsize * sizeof (selection[0]));
+          size_t nselect;
+          {
+            size_t j = 0;
+            for (size_t i = 0; i < gridsize; i++ )
+              selection[j] = i, j += (mask_gme[i] != 0);
+            nselect = j;
+          }
+          selection = (size_t *)Realloc(selection, nselect * sizeof (selection[0]));
+          if (xvals)
+            for (size_t i = 0; i < nselect; i++ )
+	      xvals[i] = xvals[selection[i]];
+          if (yvals)
+            for (size_t i = 0; i < nselect; i++ )
+              yvals[i] = yvals[selection[i]];
+          if (area)
+            for (size_t i = 0; i < nselect; i++ )
+              area[i] = area[selection[i]];
+          if (xbounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                xbounds[i * nv + iv] = xbounds[selection[i] * nv + iv];
+          if (ybounds)
+            for (size_t i = 0; i < nselect; i++ )
+              for (size_t iv = 0; iv < nv; iv++)
+                ybounds[i * nv + iv] = ybounds[selection[i] * nv + iv];
+          Free(selection);
+
+	  /* fprintf(stderr, "grid compress %d %d %d\n", i, j, gridsize); */
+	  gridsize = nselect;
+	  gridptr->size  = (int)gridsize;
+	  gridptr->x.size = (int)gridsize;
+	  gridptr->y.size = (int)gridsize;
+
+          double **resizeP[] = { &gridptr->x.vals, &gridptr->y.vals,
+                                 &gridptr->area,
+                                 &gridptr->x.bounds, &gridptr->y.bounds };
+          size_t newSize[] = { gridsize, gridsize, gridsize, nv*gridsize,
+                               nv*gridsize };
+          for ( size_t i = 0; i < sizeof (resizeP) / sizeof (resizeP[0]); ++i)
+            if ( *(resizeP[i]) )
+              *(resizeP[i]) = (double *)Realloc(*(resizeP[i]), newSize[i]*sizeof(double));
+
+	  Free(gridptr->mask_gme);
+	  gridptr->mask_gme = NULL;
+          gridMark4Update(gridID);
+	}
     }
   else
-    return CDI_APPLY_GO_ON;
+    Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
 }
 
-/* Add grid (which must be Malloc'ed to vlist if not already found */
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
+static void
+gridDefAreaSerial(grid_t *gridptr, const double *area)
 {
-  /*
-    mode: 0 search in vlist and grid table
-          1 search in grid table only
-   */
-  bool gridglobdefined = false;
-  bool griddefined = false;
-  int gridID = CDI_UNDEFID;
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  size_t size = gridptr->size;
 
-  unsigned ngrids = (unsigned)vlistptr->ngrids;
+  if ( size == 0 )
+    Error("size undefined for gridID = %d", gridptr->self);
 
-  if ( mode == 0 )
-    for ( unsigned index = 0; index < ngrids; index++ )
-      {
-	if ( (gridID = vlistptr->gridIDs[index]) != UNDEFID )
-          {
-            if ( gridCompare(gridID, grid) == false )
-              {
-                griddefined = true;
-                break;
-              }
-          }
-        else
-          Error("Internal problem: undefined gridID in vlist "
-                "%d, position %u!", vlistID, index);
+  if ( gridptr->area == NULL )
+    gridptr->area = (double *) Malloc(size*sizeof(double));
+  else if ( CDI_Debug )
+    Warning("values already defined!");
 
-      }
+  memcpy(gridptr->area, area, size * sizeof(double));
+}
 
-  if ( ! griddefined )
-    {
-      struct gridCompareSearchState query;
-      query.queryKey = grid;// = { .queryKey = grid };
-      if ((gridglobdefined
-           = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
-              == CDI_APPLY_STOP)))
-        gridID = query.resIDValue;
 
-      if ( mode == 1 && gridglobdefined )
-	for (unsigned index = 0; index < ngrids; index++ )
-	  if ( vlistptr->gridIDs[index] == gridID )
-	    {
-	      gridglobdefined = false;
-	      break;
-	    }
-    }
+void gridDefArea(int gridID, const double *area)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defArea(gridptr, area);
+  gridMark4Update(gridID);
+}
 
-  if ( ! griddefined )
-    {
-      if ( ! gridglobdefined )
-        {
-          grid->self = gridID = reshPut(grid, &gridOps);
-          gridComplete(grid);
-        }
-      vlistptr->gridIDs[ngrids] = gridID;
-      vlistptr->ngrids++;
-    }
+static void
+gridInqAreaSerial(grid_t *gridptr, double *area)
+{
+  if (gridptr->area)
+    memcpy(area, gridptr->area, gridptr->size * sizeof (double));
+}
 
-  return (struct addIffNewRes){ .Id = gridID,
-      .isNew = !griddefined && !gridglobdefined };
+
+void gridInqArea(int gridID, double *area)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->inqArea(gridptr, area);
 }
 
-const struct gridVirtTable cdiGridVtable
-  = {
-  .destroy = gridDestroyKernel,
-  .copy = grid_copy_base,
-  .copyScalarFields = grid_copy_base_scalar_fields,
-  .copyArrayFields = grid_copy_base_array_fields,
-  .defXVals = gridDefXValsSerial,
-  .defYVals = gridDefYValsSerial,
-  .defMask = gridDefMaskSerial,
-  .defMaskGME = gridDefMaskGMESerial,
-  .defXBounds = gridDefXBoundsSerial,
-  .defYBounds = gridDefYBoundsSerial,
-  .defArea = gridDefAreaSerial,
-  .inqXVal = gridInqXValSerial,
-  .inqYVal = gridInqYValSerial,
-  .inqXVals = gridInqXValsSerial,
-  .inqYVals = gridInqYValsSerial,
-  .inqXValsPtr = gridInqXValsPtrSerial,
-  .inqYValsPtr = gridInqYValsPtrSerial,
-  .compareXYFull = compareXYvals,
-  .compareXYAO = compareXYvals2,
-  .inqArea = gridInqAreaSerial,
-  .inqAreaPtr = gridInqAreaPtrBase,
-  .hasArea = gridHasAreaBase,
-  .inqMask = gridInqMaskSerial,
-  .inqMaskGME = gridInqMaskGMESerial,
-  .inqXBounds = gridInqXBoundsSerial,
-  .inqYBounds = gridInqYBoundsSerial,
-  .inqXBoundsPtr = gridInqXBoundsPtrSerial,
-  .inqYBoundsPtr = gridInqYBoundsPtrSerial,
-};
+static int
+gridHasAreaBase(grid_t *gridptr)
+{
+  return gridptr->area != NULL;
+}
+
+int gridHasArea(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->hasArea(gridptr);
+}
+
+
+static const double *gridInqAreaPtrBase(grid_t *gridptr)
+{
+  return gridptr->area;
+}
+
+const double *gridInqAreaPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqAreaPtr(gridptr);
+}
+
+
+void gridDefNvertex(int gridID, int nvertex)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  if (gridptr->nvertex != nvertex)
+    {
+      gridptr->nvertex = nvertex;
+      gridMark4Update(gridID);
+    }
+}
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
 
+int gridInqNvertex(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->nvertex;
+}
 
+static void
+gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, size_t regularSize,
+                     double **field)
+{
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t nvertex = (size_t)gridptr->nvertex;
+  if ( nvertex == 0 )
+    {
+      Warning("nvertex undefined for gridID = %d. Cannot define bounds!",
+              gridptr->self);
+      return;
+    }
+  size_t size = nvertex * (irregular ? gridptr->size : regularSize);
+  if ( size == 0 )
+    Error("size undefined for gridID = %d", gridptr->self);
 
-static int initIegLib      = 0;
-static int iegDefaultDprec = 0;
+  if (*field == NULL)
+    *field = (double *)Malloc(size * sizeof (double));
+  else if ( CDI_Debug )
+    Warning("values already defined!");
 
+  memcpy(*field, bounds, size * sizeof (double));
+}
 
-/*
- * A version string.
- */
-#undef  LIBVERSION
-#define LIBVERSION      1.4.0
-#define XSTRING(x)	#x
-#define STRING(x)	XSTRING(x)
-static const char ieg_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__;
 
-const char *iegLibraryVersion(void)
+static void
+gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
 {
-  return ieg_libvers;
+  gridDefBoundsGeneric(gridptr, xbounds, gridptr->x.size, &gridptr->x.bounds);
 }
 
+/*
+ at Function  gridDefXbounds
+ at Title     Define the bounds of a X-axis
 
-static int IEG_Debug = 0;    /* If set to 1, debugging */
+ at Prototype void gridDefXbounds(int gridID, const double *xbounds)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  xbounds  X-bounds of the grid.
 
-static
-void iegLibInit(void)
+ at Description
+The function @func{gridDefXbounds} defines all bounds of the X-axis.
+
+ at EndFunction
+*/
+void gridDefXbounds(int gridID, const double *xbounds)
 {
-  const char *envName = "IEG_PRECISION";
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defXBounds(gridptr, xbounds);
+  gridMark4Update(gridID);
+}
 
-  char *envString = getenv(envName);
-  if ( envString )
-    {
-      int pos;
-      int nrun;
-      if ( strlen(envString) == 2 ) nrun = 1;
-      else                          nrun = 2;
+static size_t
+gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
+{
+  size_t nvertex = (size_t)gridptr->nvertex;
 
-      pos = 0;
-      while ( nrun-- )
-	{
-	  switch ( tolower((int) envString[pos]) )
-	    {
-	    case 'r':
-	      {
-		switch ( (int) envString[pos+1] )
-		  {
-		  case '4': iegDefaultDprec = EXSE_SINGLE_PRECISION; break;
-		  case '8': iegDefaultDprec = EXSE_DOUBLE_PRECISION; break;
-		  default:
-		    Message("Invalid digit in %s: %s", envName, envString);
-		  }
-		break;
-	      }
-	    default:
-              {
-                Message("Invalid character in %s: %s", envName, envString);
-                break;
-              }
-            }
-	  pos += 2;
-	}
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t size = nvertex * (irregular ? gridptr->size : gridptr->x.size);
+
+  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
+  if ( gridptr_xbounds )
+    {
+      if ( size && xbounds )
+        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
     }
+  else
+    size = 0;
 
-  initIegLib = 1;
+  return size;
 }
 
+/*
+ at Function  gridInqXbounds
+ at Title     Get the bounds of a X-axis
+
+ at Prototype size_t gridInqXbounds(int gridID, double *xbounds)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  xbounds  Pointer to the location into which the X-bounds are read.
+                    The caller must allocate space for the returned values.
 
-void iegDebug(int debug)
-{
-  IEG_Debug = debug;
+ at Description
+The function @func{gridInqXbounds} returns the bounds of the X-axis.
 
-  if ( IEG_Debug )
-    Message("debug level %d", debug);
+ at Result
+Upon successful completion @func{gridInqXbounds} returns the number of bounds and
+the bounds are stored in @func{xbounds}.
+Otherwise, 0 is returned and @func{xbounds} is empty.
+
+ at EndFunction
+*/
+size_t gridInqXbounds(int gridID, double *xbounds)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXBounds(gridptr, xbounds);
 }
 
-static
-void iegInit(iegrec_t *iegp)
+static const double *
+gridInqXBoundsPtrSerial(grid_t *gridptr)
 {
-  iegp->checked    = 0;
-  iegp->byteswap   = 0;
-  iegp->dprec      = 0;
-  iegp->refval     = 0;
-  iegp->datasize   = 0;
-  iegp->buffersize = 0;
-  iegp->buffer     = NULL;
+  return gridptr->x.bounds;
 }
 
 
-void iegInitMem(void *ieg)
+const double *gridInqXboundsPtr(int gridID)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-
-  memset(iegp->ipdb, 0, sizeof(iegp->ipdb));
-  memset(iegp->igdb, 0, sizeof(iegp->igdb));
-  memset(iegp->vct,  0, sizeof(iegp->vct));
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXBoundsPtr(gridptr);
 }
 
-
-void *iegNew(void)
+static void
+gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
 {
-  if ( ! initIegLib ) iegLibInit();
+  gridDefBoundsGeneric(gridptr, ybounds, gridptr->y.size, &gridptr->y.bounds);
+}
 
-  iegrec_t *iegp = (iegrec_t *) Malloc(sizeof(iegrec_t));
+/*
+ at Function  gridDefYbounds
+ at Title     Define the bounds of a Y-axis
 
-  iegInit(iegp);
-  iegInitMem(iegp);
+ at Prototype void gridDefYbounds(int gridID, const double *ybounds)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  ybounds  Y-bounds of the grid.
 
-  return (void*)iegp;
-}
+ at Description
+The function @func{gridDefYbounds} defines all bounds of the Y-axis.
 
+ at EndFunction
+*/
+void gridDefYbounds(int gridID, const double *ybounds)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defYBounds(gridptr, ybounds);
+  gridMark4Update(gridID);
+}
 
-void iegDelete(void *ieg)
+static size_t
+gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
+  size_t nvertex = (size_t)gridptr->nvertex;
 
-  if ( iegp )
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t size = nvertex * (irregular ? gridptr->size : gridptr->y.size);
+
+  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
+  if ( gridptr_ybounds )
     {
-      if ( iegp->buffer ) Free(iegp->buffer);
-      Free(iegp);
+      if ( size && ybounds )
+        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
     }
+  else
+    size = 0;
+
+  return size;
 }
 
 
-int iegCheckFiletype(int fileID, int *swap)
+/*
+ at Function  gridInqYbounds
+ at Title     Get the bounds of a Y-axis
+
+ at Prototype size_t gridInqYbounds(int gridID, double *ybounds)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  ybounds  Pointer to the location into which the Y-bounds are read.
+                    The caller must allocate space for the returned values.
+
+ at Description
+The function @func{gridInqYbounds} returns the bounds of the Y-axis.
+
+ at Result
+Upon successful completion @func{gridInqYbounds} returns the number of bounds and
+the bounds are stored in @func{ybounds}.
+Otherwise, 0 is returned and @func{ybounds} is empty.
+
+ at EndFunction
+*/
+size_t gridInqYbounds(int gridID, double *ybounds)
 {
-  size_t data = 0;
-  size_t dimx = 0, dimy = 0;
-  size_t fact = 0;
-  unsigned char buffer[1048], *pbuf;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYBounds(gridptr, ybounds);
+}
 
-  if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
+static const double *
+gridInqYBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->y.bounds;
+}
 
-  size_t blocklen  = get_UINT32(buffer);
-  size_t sblocklen = get_SUINT32(buffer);
 
-  if ( IEG_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+const double *gridInqYboundsPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYBoundsPtr(gridptr);
+}
 
-  if ( blocklen == 636 || blocklen == 640 )
+static void
+printDblsPrefixAutoBrk(FILE *fp, int dig, const char prefix[], size_t nbyte0,
+                       size_t n, const double vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
     {
-     *swap = 0;
-      fact = 4;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
-      pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%.*g ", dig, vals[i]);
     }
-  else if ( blocklen == 1040 || blocklen == 1036 )
+  fputs("\n", fp);
+}
+
+static void
+printIntsPrefixAutoBrk(FILE *fp, const char prefix[], size_t nbyte0,
+                       size_t n, const int vals[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
     {
-     *swap = 0;
-      fact = 8;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
-      pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
     }
-  else if ( sblocklen == 636 || sblocklen == 640 )
+  fputs("\n", fp);
+}
+
+static void
+printBounds(FILE *fp, int dig, const char prefix[], size_t nbyte0,
+            size_t n, size_t nvertex, const double bounds[])
+{
+  fputs(prefix, fp);
+  if ( n > 0 )
     {
-     *swap = 1;
-      fact = 4;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
-      pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
+      for ( size_t iv = 0; iv < nvertex; iv++ )
+        fprintf(fp, "%.*g ", dig, bounds[iv]);
+      for ( size_t i = 1; i < n; i++ )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          for ( size_t iv = 0; iv < nvertex; iv++ )
+            fprintf(fp, "%.*g ", dig, bounds[i*nvertex+iv]);
+        }
+      fputs("\n", fp);
     }
-  else if ( sblocklen == 1040 || sblocklen == 1036 )
+}
+
+static void
+printMask(FILE *fp, const char prefix[], size_t nbyte0,
+          size_t n, const int mask[])
+{
+  fputs(prefix, fp);
+  size_t nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
     {
-     *swap = 1;
-      fact = 8;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
-      pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", mask[i]);
     }
+  fputs("\n", fp);
+}
 
-  fileRewind(fileID);
-
-  int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
-
-  if ( IEG_Debug )
+static inline
+void *resizeBuffer(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
     {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
     }
-
-  return found;
+  return *buf;
 }
 
-
-void iegCopyMeta(void *dieg, void *sieg)
+static
+void gridPrintAttributes(FILE *fp, int gridID)
 {
-  iegrec_t *diegp = (iegrec_t *) dieg;
-  iegrec_t *siegp = (iegrec_t *) sieg;
+  int cdiID = gridID;
+  int varID = CDI_GLOBAL;
+  int atttype, attlen;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 0;
 
-  /*  diegp->byteswap = siegp->byteswap; */
-  diegp->dprec    = siegp->dprec;
-  diegp->refval   = siegp->refval;
+  int natts;
+  cdiInqNatts(cdiID, varID, &natts);
 
-  memcpy(diegp->ipdb, siegp->ipdb, sizeof(siegp->ipdb));
-  memcpy(diegp->igdb, siegp->igdb, sizeof(siegp->igdb));
-  memcpy(diegp->vct,  siegp->vct,  sizeof(siegp->vct));
+  for ( int iatt = 0; iatt < natts; ++iatt )
+    {
+      cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
+
+      if ( attlen == 0 ) continue;
+
+      if ( atttype == CDI_DATATYPE_TXT )
+        {
+          size_t attSize = (size_t)(attlen+1)*sizeof(char);
+          char *atttxt = (char *)resizeBuffer(&attBuf, &attBufSize, attSize);
+          cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
+          atttxt[attlen] = 0;
+          fprintf(fp, "ATTR_TXT: %s = \"%s\"\n", attname, atttxt);
+        }
+      else if ( atttype == CDI_DATATYPE_INT8  || atttype == CDI_DATATYPE_UINT8  ||
+                atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
+                atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
+        {
+          size_t attSize = (size_t)attlen*sizeof(int);
+          int *attint = (int *)resizeBuffer(&attBuf, &attBufSize, attSize);
+          cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
+          if ( attlen == 1 )
+            fprintf(fp, "ATTR_INT: %s =", attname);
+          else
+            fprintf(fp, "ATTR_INT_%d: %s =", attlen, attname);
+          for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %d", attint[i]);
+          fprintf(fp, "\n");
+        }
+      else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+        {
+          size_t attSize = (size_t)attlen * sizeof(double);
+          double *attflt = (double *)resizeBuffer(&attBuf, &attBufSize, attSize);
+          int dig = (atttype == CDI_DATATYPE_FLT64) ? 15 : 7;
+          cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
+          if ( attlen == 1 )
+            fprintf(fp, "ATTR_FLT: %s =", attname);
+          else
+            fprintf(fp, "ATTR_FLT_%d: %s =", attlen, attname);
+          for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %.*g", dig, attflt[i]);
+          fprintf(fp, "\n");
+        }
+    }
+
+  Free(attBuf);
 }
 
 static
-int iegInqData(void *ieg, int prec, void *data)
+void gridPrintKernel(int gridID, int opt, FILE *fp)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-  int ierr = 0;
-  int byteswap = iegp->byteswap;
-  size_t datasize = iegp->datasize;
-  void *buffer = iegp->buffer;
-  int dprec = iegp->dprec;
+  size_t xdimLen, ydimLen;
+  char attstr[CDI_MAX_NAME];
+  char attstr2[CDI_MAX_NAME];
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  const char  **xcvals  = gridInqXCvalsPtr(gridID);
+  const char  **ycvals  = gridInqYCvalsPtr(gridID);
+  size_t nxvals = gridInqXvals(gridID, NULL);
+  size_t nyvals = gridInqYvals(gridID, NULL);
+  size_t nxbounds = gridInqXbounds(gridID, NULL);
+  size_t nybounds = gridInqYbounds(gridID, NULL);
 
-  switch ( dprec )
+  int type     = gridInqType(gridID);
+  size_t gridsize = gridInqSize(gridID);
+  size_t xsize    = gridInqXsize(gridID);
+  size_t ysize    = gridInqYsize(gridID);
+  int xstrlen  = gridInqXIsc(gridID);
+  int ystrlen  = gridInqYIsc(gridID);
+  int nvertex  = gridInqNvertex(gridID);
+  int datatype = gridInqDatatype(gridID);
+
+  int dig = (datatype == CDI_DATATYPE_FLT64) ? 15 : 7;
+
+  fprintf(fp, "gridtype  = %s\n" "gridsize  = %zu\n", gridNamePtr(type), gridsize);
+
+  if ( type != GRID_GME )
     {
-    case EXSE_SINGLE_PRECISION:
+      if ( type != GRID_UNSTRUCTURED && type != GRID_SPECTRAL && type != GRID_FOURIER )
+        {
+          if ( xsize > 0 ) fprintf(fp, "xsize     = %zu\n", xsize);
+          if ( ysize > 0 ) fprintf(fp, "ysize     = %zu\n", ysize);
+        }
+
+      if ( nxvals > 0 || xcvals )
+        {
+          if ( xstrlen )  fprintf(fp, "xstringlen= %d\n", xstrlen);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "xname     = %s\n", attstr);
+          attstr2[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, attstr2);
+          if ( attstr2[0] && strcmp(attstr, attstr2) )  fprintf(fp, "xdimname  = %s\n", attstr2);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "xlongname = %s\n", attstr);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "xunits    = %s\n", attstr);
+        }
+
+      if ( nyvals > 0 || ycvals )
+        {
+          if ( ystrlen )  fprintf(fp, "ystringlen= %d\n", ystrlen);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "yname     = %s\n", attstr);
+          attstr2[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, attstr2);
+          if ( attstr2[0] && strcmp(attstr, attstr2) )  fprintf(fp, "ydimname  = %s\n", attstr2);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "ylongname = %s\n", attstr);
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, attstr);
+          if ( attstr[0] )  fprintf(fp, "yunits    = %s\n", attstr);
+        }
+
+      if ( type == GRID_UNSTRUCTURED || type == GRID_CURVILINEAR )
+        {
+          attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, attstr);
+          if ( attstr[0] ) fprintf(fp, "vdimname  = %s\n", attstr);
+        }
+      if ( type == GRID_UNSTRUCTURED && nvertex > 0 ) fprintf(fp, "nvertex   = %d\n", nvertex);
+    }
+
+  switch (type)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_GENERIC:
+    case GRID_PROJECTION:
+    case GRID_CURVILINEAR:
+    case GRID_UNSTRUCTURED:
+    case GRID_CHARXY:
       {
-	if ( sizeof(FLT32) == 4 )
+        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridInqNP(gridID));
+
+	if ( type == GRID_CURVILINEAR || type == GRID_UNSTRUCTURED )
 	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
+	    xdimLen = gridsize;
+	    ydimLen = gridsize;
+	  }
+        else if ( type == GRID_GAUSSIAN_REDUCED )
+          {
+	    xdimLen = 2;
+	    ydimLen = ysize;
+          }
+	else
+	  {
+	    xdimLen = xsize;
+	    ydimLen = ysize;
+	  }
 
-	    if ( dprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT32));
-	    else
+	if ( type == GRID_UNSTRUCTURED )
+          {
+            int number = gridInqNumber(gridID);
+            int position = gridInqPosition(gridID);
+            // const unsigned char *d;
+            if ( number > 0 )
               {
-                const float *restrict p = (float *)buffer;
-                double *restrict q = (double *)data;
-                for ( size_t i = 0; i < datasize; i++)
-                  q[i] = p[i];
+                fprintf(fp, "number    = %d\n", number);
+                if ( position >= 0 ) fprintf(fp, "position  = %d\n", position);
+              }
+            /*
+              gridInqUUID(gridID, uuidOfHGrid);
+              d = (unsigned char *) &uuidOfHGrid;
+              fprintf(fp, "uuid      = %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
+              d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
+              d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+            */
+            if ( gridInqReference(gridID, NULL) )
+              {
+                char reference_link[8192];
+                gridInqReference(gridID, reference_link);
+                fprintf(fp, "uri       = %s\n", reference_link);
               }
+          }
+
+	if ( nxvals > 0 )
+	  {
+	    double xfirst = 0.0, xinc = 0.0;
+
+	    if ( type == GRID_LONLAT     || type == GRID_GAUSSIAN ||
+		 type == GRID_PROJECTION || type == GRID_GENERIC )
+	      {
+		xfirst = gridInqXval(gridID, 0);
+		xinc   = gridInqXinc(gridID);
+	      }
+
+	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
+	      {
+                fprintf(fp, "xfirst    = %.*g\n"
+                        "xinc      = %.*g\n", dig, xfirst, dig, xinc);
+	      }
+	    else
+	      {
+                double *xvals = (double*) Malloc(nxvals*sizeof(double));
+                gridInqXvals(gridID, xvals);
+                static const char prefix[] = "xvals     = ";
+                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nxvals, xvals);
+                Free(xvals);
+	      }
+	  }
+
+        if ( xcvals )
+          {
+            attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, attstr);
+            if ( attstr[0] )
+              fprintf(fp, "x%ss = %.*s\n", attstr, xstrlen, xcvals[0]);
+            else
+              fprintf(fp, "xstrings  = %.*s\n", xstrlen, xcvals[0]);
+            for ( size_t i = 1; i < xsize; i++ )
+              fprintf(fp, "          = %.*s\n", xstrlen, xcvals[i]);
+          }
+
+	if ( nxbounds )
+	  {
+            double *xbounds = (double*) Malloc(nxbounds*sizeof(double));
+            gridInqXbounds(gridID, xbounds);
+            static const char prefix[] = "xbounds   = ";
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, xdimLen, (size_t)nvertex, xbounds);
+            Free(xbounds);
+	  }
+
+	if ( nyvals > 0 )
+	  {
+	    double yfirst = 0.0, yinc = 0.0;
+
+	    if ( type == GRID_LONLAT || type == GRID_GENERIC ||
+                 type == GRID_PROJECTION || type == GRID_GENERIC )
+	      {
+		yfirst = gridInqYval(gridID, 0);
+		yinc   = gridInqYinc(gridID);
+	      }
+
+	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
+	      {
+	  	fprintf(fp, "yfirst    = %.*g\n"
+                        "yinc      = %.*g\n", dig, yfirst, dig, yinc);
+	      }
+	    else
+	      {
+                double *yvals = (double*) Malloc(nyvals*sizeof(double));
+                gridInqYvals(gridID, yvals);
+                static const char prefix[] = "yvals     = ";
+                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nyvals, yvals);
+                Free(yvals);
+	      }
 	  }
-	else
+
+        if ( ycvals )
+          {
+            attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, attstr);
+            if ( attstr[0] )
+              fprintf(fp, "x%ss = %.*s\n", attstr, ystrlen, ycvals[0]);
+            else
+              fprintf(fp, "ystrings  = %.*s\n", ystrlen, ycvals[0]);
+            for ( size_t i = 1; i < ysize; i++ )
+              fprintf(fp, "          = %.*s\n", ystrlen, ycvals[i]);
+          }
+
+	if ( nybounds )
 	  {
-	    Error("not implemented for %d byte float", sizeof(FLT32));
+            double *ybounds = (double*) Malloc(nybounds*sizeof(double));
+            gridInqYbounds(gridID, ybounds);
+            static const char prefix[] = "ybounds   = ";
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, ydimLen, (size_t)nvertex, ybounds);
+            Free(ybounds);
 	  }
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-	if ( sizeof(FLT64) == 8 )
-	  {
-	    if ( byteswap ) swap8byte(buffer, datasize);
 
-	    if ( dprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT64));
-	    else
-              {
-                const double *restrict p = (double *)buffer;
-                float *restrict q = (float *)data;
-                for ( size_t i = 0; i < datasize; i++)
-                  q[i] = (float)p[i];
-              }
-	  }
-	else
+	if ( gridHasArea(gridID) )
 	  {
-	    Error("not implemented for %d byte float", sizeof(FLT64));
+            double *area = (double*) Malloc(gridsize*sizeof(double));
+            gridInqArea(gridID, area);
+            static const char prefix[] = "area      = ";
+            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, gridsize, area);
+            Free(area);
 	  }
+
+        if ( type == GRID_GAUSSIAN_REDUCED )
+          {
+            static const char prefix[] = "rowlon    = ";
+            int *rowlon = (int *)Malloc(ysize*sizeof(int));
+            gridInqRowlon(gridID, rowlon);
+            printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
+                                   (ysize > 0 ? ysize : 0), rowlon);
+            Free(rowlon);
+          }
+
+        if ( type == GRID_PROJECTION ) gridPrintAttributes(fp, gridID);
+
 	break;
-    default:
+      }
+    case GRID_SPECTRAL:
       {
-	Error("unexpected data precision %d", dprec);
+        fprintf(fp, "truncation = %d\n"
+                "complexpacking = %d\n", gridInqTrunc(gridID), gridInqComplexPacking(gridID) );
+        break;
+      }
+    case GRID_FOURIER:
+      {
+	fprintf(fp, "truncation = %d\n", gridInqTrunc(gridID));
+	break;
+      }
+    case GRID_GME:
+      {
+        int nd, ni, ni2, ni3;
+        gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+        fprintf(fp, "ni        = %d\n", ni );
+        break;
+      }
+   default:
+      {
+	fprintf(stderr, "Unsupported grid type: %s\n", gridNamePtr(type));
         break;
       }
     }
 
-  return ierr;
-}
-
+  gridInqUUID(gridID, uuidOfHGrid);
+  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+    {
+      char uuidOfHGridStr[37];
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
+      if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
+        fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
+    }
 
-int iegInqDataSP(void *ieg, float *data)
-{
-  return iegInqData(ieg, EXSE_SINGLE_PRECISION, (void *) data);
+  if ( gridInqMask(gridID, NULL) )
+    {
+      int *mask = (gridsize>0) ? (int*) Malloc(gridsize*sizeof(int)) : NULL;
+      gridInqMask(gridID, mask);
+      static const char prefix[] = "mask      = ";
+      printMask(fp, prefix, sizeof(prefix)-1,
+                (gridsize > 0 ? gridsize : 0), mask);
+      if ( mask ) Free(mask);
+    }
 }
 
 
-int iegInqDataDP(void *ieg, double *data)
+void gridPrint(int gridID, int opt)
 {
-  return iegInqData(ieg, EXSE_DOUBLE_PRECISION, (void *) data);
+  gridPrintKernel(gridID, opt, stdout);
 }
 
 
-static int
-iegDefData(iegrec_t *iegp, int prec, const void *data)
+void gridPrintP(void *voidptr, FILE *fp)
 {
-  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
-
-  iegp->dprec = dprec = dprec ? dprec : prec;
+  grid_t *gridptr = (grid_t *) voidptr;
+  int gridID = gridptr->self;
 
-  size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
-  size_t blocklen = datasize * (size_t)dprec;
+  xassert( gridptr );
 
-  iegp->datasize = datasize;
+  gridPrintKernel(gridID, 0, fp);
 
-  size_t buffersize = iegp->buffersize;
+  fprintf(fp,
+          "datatype  = %d\n"
+          "nd        = %d\n"
+          "ni        = %d\n"
+          "ni2       = %d\n"
+          "ni3       = %d\n"
+          "number    = %d\n"
+          "position  = %d\n"
+          "trunc     = %d\n"
+          "lcomplex  = %d\n"
+          "nrowlon   = %d\n",
+          gridptr->datatype, gridptr->gme.nd, gridptr->gme.ni, gridptr->gme.ni2,
+          gridptr->gme.ni3, gridptr->number, gridptr->position, gridptr->trunc,
+          gridptr->lcomplex, gridptr->nrowlon );
 
-  void *buffer = iegp->buffer;
-  if ( buffersize != blocklen )
+  if ( gridptr->rowlon )
     {
-      buffersize = blocklen;
-      buffer = Realloc(buffer, buffersize);
-      iegp->buffer = buffer;
-      iegp->buffersize = buffersize;
+      static const char prefix[] = "rowlon    = ";
+      printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
+                             (size_t)(gridptr->nrowlon > 0
+                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
     }
 
-  switch ( dprec )
+  if ( gridInqMaskGME(gridID, NULL) )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( dprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT32));
-	else
-          {
-            const double *restrict p = (const double *)data;
-            float *restrict q = (float *)buffer;
-            for (size_t i = 0; i < datasize; i++)
-              q[i] = (float)p[i];
-          }
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	if ( dprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT64));
-	else
-          {
-            const float *restrict p = (const float *)data;
-            double *restrict q = (double *)buffer;
-            for ( size_t i = 0; i < datasize; i++)
-              q[i] = p[i];
-          }
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
+      size_t gridsize = gridptr->size;
+      int *mask = (gridsize>0) ? (int*) Malloc(gridsize*sizeof(int)) : NULL;
+      gridInqMaskGME(gridID, mask);
+      static const char prefix[] = "mask_gme  = ";
+      printMask(fp, prefix, sizeof(prefix)-1,
+                (gridptr->size > 0 ? gridptr->size : 0), mask);
+      if ( mask ) Free(mask);
     }
+}
 
-  return 0;
+static const double *gridInqXValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->x.vals;
+}
+
+static const char **gridInqXCvalsPtrSerial(grid_t *gridptr)
+{
+  return (const char **) gridptr->x.cvals;
 }
 
 
-int iegDefDataSP(void *ieg, const float *data)
+const double *gridInqXvalsPtr(int gridID)
 {
-  return iegDefData((iegrec_t *)ieg, EXSE_SINGLE_PRECISION, (void *) data);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXValsPtr(gridptr);
 }
 
 
-int iegDefDataDP(void *ieg, const double *data)
+const char **gridInqXCvalsPtr(int gridID)
 {
-  return iegDefData((iegrec_t *)ieg, EXSE_DOUBLE_PRECISION, (void *) data);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXCvalsPtr(gridptr);
 }
 
+static const double *gridInqYValsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->y.vals;
+}
 
-int iegRead(int fileID, void *ieg)
+static const char **gridInqYCvalsPtrSerial(grid_t *gridptr)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-  union { double d[200]; float f[200]; int32_t i32[200]; } buf;
+  return (const char **) gridptr->y.cvals;
+}
 
-  if ( ! iegp->checked )
-    {
-      int status = iegCheckFiletype(fileID, &iegp->byteswap);
-      if ( status == 0 ) Error("Not a IEG file!");
-      iegp->checked = 1;
-    }
+const double *gridInqYvalsPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYValsPtr(gridptr);
+}
 
-  int byteswap = iegp->byteswap;
+const char **gridInqYCvalsPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYCvalsPtr(gridptr);
+}
 
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
+/*
+ at Function  gridDefParamLCC
+ at Title     Define the parameter of a Lambert Conformal Conic grid
 
-  if ( fileEOF(fileID) ) return -1;
+ at Prototype void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2, double a, double rf, double xval_0, double yval_0, double x_0, double y_0)
+ at Parameter
+    @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  missval   Missing value
+    @Item  lon_0     The East longitude of the meridian which is parallel to the Y-axis.
+    @Item  lat_0     Latitude of the projection origin
+    @Item  lat_1     First latitude from the pole at which the secant cone cuts the sphere.
+    @Item  lat_2     Second latitude at which the secant cone cuts the sphere.
+    @Item  a         Earth radius in metres (optional).
+    @Item  rf        Inverse flattening (1/f) (optional).
+    @Item  xval_0    Longitude of the first grid point in degree (optional).
+    @Item  yval_0    Latitude of the first grid point in degree (optional).
+    @Item  x_0       False easting (optional).
+    @Item  y_0       False northing (optional).
 
-  if ( IEG_Debug )
-    Message("blocklen = %lu", blocklen);
+ at Description
+The function @func{gridDefParamLCC} defines the parameter of a Lambert Conformal Conic grid.
 
-  int dprec = 0;
-  if ( blocklen == 636 || blocklen == 640 )
-    dprec = 4;
-  else if ( blocklen == 1040 || blocklen == 1036 )
-    dprec = 8;
-  else
-    {
-      Warning("unexpecteted header size %d!", (int) blocklen);
-      return -1;
-    }
+ at EndFunction
+*/
+void gridDefParamLCC(int gridID, double missval, double lon_0, double lat_0, double lat_1, double lat_2,
+                     double a, double rf, double xval_0, double yval_0, double x_0, double y_0)
+{
+  (void)lat_0;
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, "Lambert_Conformal");
+
+  const char *mapname = "lambert_conformal_conic";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapname);
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)(strlen(mapname)), mapname);
+  int nlats = 0;
+  double lats[2];
+  lats[nlats++] = lat_1;
+  if ( IS_NOT_EQUAL(lat_1, lat_2) ) lats[nlats++] = lat_2;
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "standard_parallel", CDI_DATATYPE_FLT64, nlats, lats);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "longitude_of_central_meridian", CDI_DATATYPE_FLT64, 1, &lon_0);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "latitude_of_projection_origin", CDI_DATATYPE_FLT64, 1, &lat_2);
+  if ( a > 0 ) cdiDefAttFlt(gridID, CDI_GLOBAL, "earth_radius", CDI_DATATYPE_FLT64, 1, &a);
+  if ( rf > 0 ) cdiDefAttFlt(gridID, CDI_GLOBAL, "inverse_flattening", CDI_DATATYPE_FLT64, 1, &rf);
+  if ( IS_NOT_EQUAL(x_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_easting", CDI_DATATYPE_FLT64, 1, &x_0);
+  if ( IS_NOT_EQUAL(y_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "false_northing", CDI_DATATYPE_FLT64, 1, &y_0);
+  if ( IS_NOT_EQUAL(xval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "longitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &xval_0);
+  if ( IS_NOT_EQUAL(yval_0, missval) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "latitudeOfFirstGridPointInDegrees", CDI_DATATYPE_FLT64, 1, &yval_0);
+
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->projtype = CDI_PROJ_LCC;
+
+  gridVerifyProj(gridID);
+}
 
-  iegp->dprec = dprec;
+/*
+ at Function  gridInqParamLCC
+ at Title     Get the parameter of a Lambert Conformal Conic grid
 
-  binReadInt32(fileID, byteswap, 37, buf.i32);
-  for ( size_t i = 0; i < 37; i++ ) iegp->ipdb[i] = (int)buf.i32[i];
+ at Prototype void gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
+ at Parameter
+    @Item  gridID    Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  missval   Missing value
+    @Item  lon_0     The East longitude of the meridian which is parallel to the Y-axis.
+    @Item  lat_0     Latitude of the projection origin
+    @Item  lat_1     First latitude from the pole at which the secant cone cuts the sphere.
+    @Item  lat_2     Second latitude at which the secant cone cuts the sphere.
+    @Item  a         Earth radius in metres (optional).
+    @Item  rf        Inverse flattening (1/f) (optional).
+    @Item  xval_0    Longitude of the first grid point in degree (optional).
+    @Item  yval_0    Latitude of the first grid point in degree (optional).
+    @Item  x_0       False easting (optional).
+    @Item  y_0       False northing (optional).
 
-  binReadInt32(fileID, byteswap, 18, buf.i32);
-  for ( size_t i = 0; i < 18; i++ ) iegp->igdb[i] = (int)buf.i32[i];
+ at Description
+The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid.
 
-  if ( blocklen == 636 || blocklen == 1036 )
-    {
-      fileRead(fileID, buf.f, 4);
-      if ( byteswap ) swap4byte(buf.f, 1);
-      iegp->refval = (double)buf.f[0];
-    }
-  else
-    {
-      fileRead(fileID, buf.d, 8);
-      if ( byteswap ) swap8byte(buf.d, 1);
-      iegp->refval = (double)buf.d[0];
-    }
+ at EndFunction
+*/
+int gridInqParamLCC(int gridID, double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
+                    double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
+{
+  *a = 0; *rf = 0;
+  *lon_0 = missval; *lat_0 = missval, *lat_1 = missval, *lat_2 = missval;
+  *xval_0 = missval; *yval_0 = missval; *x_0 = missval, *y_0 = missval;
 
-  binReadInt32(fileID, byteswap, 3, buf.i32);
-  for ( size_t i = 0; i < 3; i++ ) iegp->igdb[18+i] = (int)buf.i32[i];
+  int status = -1;
+  if ( gridInqType(gridID) != GRID_PROJECTION ) return status;
 
-  if ( dprec == EXSE_SINGLE_PRECISION )
-    {
-      fileRead(fileID, buf.f, 400);
-      if ( byteswap ) swap4byte(buf.f, 100);
-      for ( size_t i = 0; i < 100; i++ )
-	iegp->vct[i] = (double)buf.f[i];
-    }
-  else
+  status = -2;
+  const char *projection = "lambert_conformal_conic";
+  char mapname[CDI_MAX_NAME]; mapname[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapname);
+  if ( mapname[0] && strcmp(mapname, projection) == 0 )
     {
-      fileRead(fileID, buf.d, 800);
-      if ( byteswap ) swap8byte(buf.d, 100);
-      for ( size_t i = 0; i < 100; i++ )
-	iegp->vct[i] = buf.d[i];
-    }
+      int atttype, attlen;
+      char attname[CDI_MAX_NAME+1];
 
-  /*
-  fprintf(stderr, "refval %g\n", iegp->refval);
+      int natts;
+      cdiInqNatts(gridID, CDI_GLOBAL, &natts);
 
-  for ( size_t i = 0; i < 100; i++ )
-    fprintf(stderr, "%3d %g\n", i, iegp->vct[i]);
+      if ( natts ) status = 0;
 
-  {
-    int i;
-    for ( size_t i = 0; i < 37; i++ )
-      fprintf(stderr, "pdb: %d %d\n", i, iegp->ipdb[i]);
-    for ( size_t i = 0; i < 22; i++ )
-      fprintf(stderr, "gdb: %d %d\n", i, iegp->igdb[i]);
-  }
-  */
-  size_t blocklen2 = binReadF77Block(fileID, byteswap);
+      for ( int iatt = 0; iatt < natts; ++iatt )
+        {
+          cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
+          if ( attlen > 2 ) continue;
 
-  if ( blocklen2 != blocklen )
-    {
-      Warning("header blocklen differ!");
-      return -1;
+          double attflt[2];
+          if ( cdiInqAttConvertedToFloat(gridID, atttype, attname, attlen, attflt) )
+            {
+              if      ( strcmp(attname, "earth_radius") == 0 )                       *a      = attflt[0];
+              else if ( strcmp(attname, "inverse_flattening") == 0 )                 *rf     = attflt[0];
+              else if ( strcmp(attname, "longitude_of_central_meridian") == 0 )      *lon_0  = attflt[0];
+              else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )      *lat_0  = attflt[0];
+              else if ( strcmp(attname, "false_easting")  == 0 )                     *x_0    = attflt[0];
+              else if ( strcmp(attname, "false_northing") == 0 )                     *y_0    = attflt[0];
+              else if ( strcmp(attname, "longitudeOfFirstGridPointInDegrees") == 0 ) *xval_0 = attflt[0];
+              else if ( strcmp(attname, "latitudeOfFirstGridPointInDegrees")  == 0 ) *yval_0 = attflt[0];
+              else if ( strcmp(attname, "standard_parallel") == 0 )
+                {
+                  *lat_1 = attflt[0];
+                  *lat_2 = (attlen == 2) ? attflt[1] : attflt[0];
+                }
+            }
+        }
     }
 
-  size_t datasize = iegp->datasize
-    = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
-
-  if ( IEG_Debug )
-    Message("datasize = %lu", iegp->datasize);
+  return status;
+}
 
-  blocklen = binReadF77Block(fileID, byteswap);
 
+int gridVerifyGribParamLCC(double missval, double *lon_0, double *lat_0, double *lat_1, double *lat_2,
+                           double *a, double *rf, double *xval_0, double *yval_0, double *x_0, double *y_0)
+{
+  static bool lwarn = true;
 
-  void *buffer = iegp->buffer;
-  if ( iegp->buffersize < blocklen )
+  if ( lwarn )
     {
-      iegp->buffer = buffer = Realloc(buffer, blocklen);
-      iegp->buffersize = blocklen;
+      // lwarn = false;
+      const char *projection = "lambert_conformal_conic";
+      if ( IS_EQUAL(*lon_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "longitude_of_central_meridian"); }
+      if ( IS_EQUAL(*lat_0, missval) ) { Warning("%s mapping parameter %s missing!", projection, "latitude_of_central_meridian"); }
+      if ( IS_EQUAL(*lat_1, missval) ) { Warning("%s mapping parameter %s missing!", projection, "standard_parallel"); }
+      if ( IS_NOT_EQUAL(*x_0, missval) && IS_NOT_EQUAL(*y_0, grid_missval) && (IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval)) )
+        {
+          if ( proj_lcc_to_lonlat_func )
+            {
+              *xval_0 = -(*x_0); *yval_0 = -(*y_0);
+              proj_lcc_to_lonlat_func(missval, *lon_0, *lat_0, *lat_1, *lat_2, *a, *rf, 0.0, 0.0, (size_t)1, xval_0, yval_0);
+            }
+          if ( IS_EQUAL(*xval_0, missval) || IS_EQUAL(*yval_0, missval) )
+            Warning("%s mapping parameter %s missing!", projection, "longitudeOfFirstGridPointInDegrees and latitudeOfFirstGridPointInDegrees");
+        }
     }
 
-  if ( dprec != (int) (blocklen/datasize) )
-    {
-      Warning("data precision differ! (h = %d; d = %d)",
-	      (int) dprec, (int) (blocklen/datasize));
-      return -1;
-    }
+  return 0;
+}
 
-  fileRead(fileID, buffer, blocklen);
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+void gridDefComplexPacking(int gridID, int lcomplex)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( blocklen2 != blocklen )
+  if (gridptr->lcomplex != lcomplex)
     {
-      Warning("data blocklen differ!");
-      return -1;
+      gridptr->lcomplex = lcomplex != 0;
+      gridMark4Update(gridID);
     }
+}
 
-  return 0;
+
+int gridInqComplexPacking(int gridID)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
+
+  return (int)gridptr->lcomplex;
 }
 
 
-int iegWrite(int fileID, void *ieg)
+void gridDefHasDims(int gridID, int hasdims)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-  union { INT32 i32[200]; float fvct[100]; } buf;
-  int dprec  = iegp->dprec;
-  int byteswap = iegp->byteswap;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  /* write header record */
-  size_t blocklen = ( dprec == EXSE_SINGLE_PRECISION ) ? 636 : 1040;
+  if ( gridptr->hasdims != (hasdims != 0) )
+    {
+      gridptr->hasdims = hasdims != 0;
+      gridMark4Update(gridID);
+    }
+}
 
-  binWriteF77Block(fileID, byteswap, blocklen);
 
-  for ( size_t i = 0; i < 37; i++ ) buf.i32[i] = (INT32) iegp->ipdb[i];
-  binWriteInt32(fileID, byteswap, 37, buf.i32);
+int gridInqHasDims(int gridID)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  for ( size_t i = 0; i < 18; i++ ) buf.i32[i] = (INT32) iegp->igdb[i];
-  binWriteInt32(fileID, byteswap, 18, buf.i32);
+  return (int)gridptr->hasdims;
+}
 
-  FLT64 refval = (FLT64)iegp->refval;
-  FLT32 refvalf = (FLT32)iegp->refval;
-  if ( dprec == EXSE_SINGLE_PRECISION )
-    binWriteFlt32(fileID, byteswap, 1, &refvalf);
-  else
-    binWriteFlt64(fileID, byteswap, 1, &refval);
+/*
+ at Function  gridDefNumber
+ at Title     Define the reference number for an unstructured grid
 
-  for ( size_t i = 0; i < 3; i++ ) buf.i32[i] = (INT32) iegp->igdb[18+i];
-  binWriteInt32(fileID, byteswap, 3, buf.i32);
+ at Prototype void gridDefNumber(int gridID, const int number)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  number   Reference number for an unstructured grid.
 
-  if ( dprec == EXSE_SINGLE_PRECISION )
-    {
-      for ( size_t i = 0; i < 100; i++ ) buf.fvct[i] = (float) iegp->vct[i];
-      binWriteFlt32(fileID, byteswap, 100, buf.fvct);
-    }
-  else
+ at Description
+The function @func{gridDefNumber} defines the reference number for an unstructured grid.
+
+ at EndFunction
+*/
+void gridDefNumber(int gridID, const int number)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->number != number )
     {
-      binWriteFlt64(fileID, byteswap, 100, iegp->vct);
+      gridptr->number = number;
+      gridMark4Update(gridID);
     }
+}
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+/*
+ at Function  gridInqNumber
+ at Title     Get the reference number to an unstructured grid
 
-  size_t datasize = (size_t)iegp->igdb[4] * (size_t)iegp->igdb[5];
-  blocklen = datasize * (size_t)dprec;
+ at Prototype int gridInqNumber(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+ at Description
+The function @func{gridInqNumber} returns the reference number to an unstructured grid.
 
-  iegp->datasize = datasize;
+ at Result
+ at func{gridInqNumber} returns the reference number to an unstructured grid.
+ at EndFunction
+*/
+int gridInqNumber(int gridID)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
+  return gridptr->number;
+}
 
-  void *buffer = iegp->buffer;
+/*
+ at Function  gridDefPosition
+ at Title     Define the position of grid in the reference file
 
-  switch ( dprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
-    }
+ at Prototype void gridDefPosition(int gridID, const int position)
+ at Parameter
+    @Item  gridID     Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  position   Position of grid in the reference file.
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+ at Description
+The function @func{gridDefPosition} defines the position of grid in the reference file.
 
-  return 0;
+ at EndFunction
+*/
+void gridDefPosition(int gridID, int position)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->position != position )
+    {
+      gridptr->position = position;
+      gridMark4Update(gridID);
+    }
 }
+
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef INCLUDE_GUARD_CDI_REFERENCE_COUNTING
-#define INCLUDE_GUARD_CDI_REFERENCE_COUNTING
+ at Function  gridInqPosition
+ at Title     Get the position of grid in the reference file
+
+ at Prototype int gridInqPosition(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
+ at Description
+The function @func{gridInqPosition} returns the position of grid in the reference file.
 
-#include <sys/types.h>
-#include <stdlib.h>
+ at Result
+ at func{gridInqPosition} returns the position of grid in the reference file.
+ at EndFunction
+*/
+int gridInqPosition(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->position;
+}
 
 /*
-This is a base class for all objects that need reference counting.
-A CdiReferencedObject has a reference count of one when it is constructed, refObjectRetain() increments the reference count, refObject Release() decrements it.
-When the reference count reaches zero, the destructor function is called before the memory of the object is deallocated with Free().
+ at Function  gridDefReference
+ at Title     Define the reference URI for an unstructured grid
 
->>> Warning <<<
-This code is currently not thread-safe.
+ at Prototype void gridDefReference(int gridID, const char *reference)
+ at Parameter
+    @Item  gridID      Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  reference   Reference URI for an unstructured grid.
 
-We are currently using the C99 standard, which does not have atomic types.
-Also, there are still tons of systems out there that have a gcc without wrong C11 atomics support
-(__STDC_NO_ATOMICS__ not defined even though stdatomics.h is not even present).
-Consequently, it is impossible to write preprocessor code to even check for the presence of atomic types.
-So, we have two options: provide multithreading support by means of locks, or wait a year or two before doing this right.
-I, for one, prefer doing things right.
-*/
-typedef struct CdiReferencedObject CdiReferencedObject;
-struct CdiReferencedObject {
-  //protected:
-    void (*destructor)(CdiReferencedObject* me);  //Subclass constructors should set this to their own destructor.
+ at Description
+The function @func{gridDefReference} defines the reference URI for an unstructured grid.
 
-  //private:    //Subclasses may read it to determine whether there is only one reference, though.
-    size_t refCount;
-};
+ at EndFunction
+*/
+void gridDefReference(int gridID, const char *reference)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-void cdiRefObject_construct(CdiReferencedObject* me);
-void cdiRefObject_retain(CdiReferencedObject* me);
-void cdiRefObject_release(CdiReferencedObject* me);
-void cdiRefObject_destruct(CdiReferencedObject* me);
+  if ( reference )
+    {
+      if ( gridptr->reference )
+        {
+          Free(gridptr->reference);
+          gridptr->reference = NULL;
+        }
 
-#endif
+      gridptr->reference = strdupx(reference);
+      gridMark4Update(gridID);
+    }
+}
 
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef INCLUDE_GUARD_CDI_GRIB_FILE_H
-#define INCLUDE_GUARD_CDI_GRIB_FILE_H
+ at Function  gridInqReference
+ at Title     Get the reference URI to an unstructured grid
 
+ at Prototype char *gridInqReference(int gridID, char *reference)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-/*
-CdiInputFile is a file abstraction that allows accessing an input file through any number of channels:
-It is reference counted, so that it is closed at the right place,
-and it is stateless, so that accesses from different callers cannot interfere with each other.
-Once the reference counting code is threadsafe, CdiInputFile will also be threadsafe.
+ at Description
+The function @func{gridInqReference} returns the reference URI to an unstructured grid.
+
+ at Result
+ at func{gridInqReference} returns the reference URI to an unstructured grid.
+ at EndFunction
 */
-typedef struct CdiInputFile {
-  //public:
-    CdiReferencedObject super;
+int gridInqReference(int gridID, char *reference)
+{
+  size_t len = 0;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  //private:
-    char* path;
-    int fileDescriptor;
-} CdiInputFile;
+  if ( gridptr->reference )
+    {
+      len = strlen(gridptr->reference);
+      if ( reference )
+        strcpy(reference, gridptr->reference);
+    }
 
-//Final class, the constructor is private and not defined here.
-CdiInputFile* cdiInputFile_make(const char* path);   //The caller is responsible to call cdiRefObject_release() on the returned object.
-int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer);       //Returns one of CDI_EINVAL, CDI_ESYSTEM, CDI_EEOF, OR CDI_NOERR.
-/* Returns path string, don't use after destruction of CdiInputFile
- * object */
-const char* cdiInputFile_getPath(const CdiInputFile* me);
-//Destructor is private as well.
+  return (int)len;
+}
 
-#endif
+const char *gridInqReferencePtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->reference;
+}
 
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#define _XOPEN_SOURCE 600
-
+ at Function  gridDefUUID
+ at Title     Define the UUID for an unstructured grid
 
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <string.h>
-#include <unistd.h>
+ at Prototype void gridDefUUID(int gridID, const char *uuid)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  uuid     UUID for an unstructured grid.
 
-static void cdiInputFile_destruct(CdiInputFile* me);
+ at Description
+The function @func{gridDefUUID} defines the UUID for an unstructured grid.
 
-//For an explanation of the condestruct() pattern, see the comment in iterator_grib.c
-//path != NULL -> construction
-//path = NULL -> destruction
-static CdiInputFile* cdiInputFile_condestruct(CdiInputFile* me, const char* path)
+ at EndFunction
+*/
+void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
 {
-  #define super() (&me->super)
-  if(!path) goto destruct;
-  cdiRefObject_construct(super());
-  me->path = strdup(path);
-  if(!me->path) goto destructSuper;
-  do
-    {
-      me->fileDescriptor = open(me->path, O_RDONLY);
-    }
-  while(me->fileDescriptor == -1 && (errno == EINTR || errno == EAGAIN));
-  if(me->fileDescriptor == -1) goto freePath;
-  //construction successfull, now we can set our own destructor
-  super()->destructor = (void(*)(CdiReferencedObject*))cdiInputFile_destruct;
-  goto success;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-// ^        constructor code       ^
-// |                               |
-// v destructor/error-cleanup code v
+  memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
+  gridMark4Update(gridID);
+}
 
-destruct:
-  close(me->fileDescriptor);
-freePath:
-  Free(me->path);
-destructSuper:
-  cdiRefObject_destruct(super());
-  me = NULL;
+/*
+ at Function  gridInqUUID
+ at Title     Get the UUID to an unstructured grid
 
-success:
-  return me;
-  #undef super
-}
+ at Prototype void gridInqUUID(int gridID, char *uuid)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-static CdiInputFile **openFileList = NULL;
-static size_t openFileCount = 0, openFileListSize = 0;
-static pthread_mutex_t openFileListLock = PTHREAD_MUTEX_INITIALIZER;
+ at Description
+The function @func{gridInqUUID} returns the UUID to an unstructured grid.
 
-//This either returns a new object, or retains and returns a preexisting open file.
-CdiInputFile* cdiInputFile_make(const char* path)
+ at Result
+ at func{gridInqUUID} returns the UUID to an unstructured grid to the parameter uuid.
+ at EndFunction
+*/
+void gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE])
 {
-  CdiInputFile* result = NULL;
-  xassert(path);
-  int error = pthread_mutex_lock(&openFileListLock);
-  xassert(!error);
-    {
-      //Check the list of open files for the given path.
-      for(size_t i = openFileCount; i-- && !result; )
-        {
-          if(!strcmp(path, openFileList[i]->path)) result = openFileList[i];
-        }
-      //If no open file was found, we open one, otherwise we just retain the existing one one more time.
-      if(result)
-        {
-          cdiRefObject_retain(&result->super);
-        }
-      else
-        {
-          result = (CdiInputFile *) Malloc(sizeof(*result));
-          if(!cdiInputFile_condestruct(result, path))
-            {
-              //An error occured during construction, avoid a memory leak.
-              Free(result);
-              result = NULL;
-            }
-          else
-            {
-              //Add the new file to the list of open files.
-              if(openFileCount == openFileListSize)
-                {
-                  openFileListSize *= 2;
-                  if(openFileListSize < 16) openFileListSize = 16;
-                  openFileList = (CdiInputFile **) Realloc(openFileList, openFileListSize);
-                }
-              xassert(openFileCount < openFileListSize);
-              openFileList[openFileCount++] = result;
-            }
-        }
-    }
-  error = pthread_mutex_unlock(&openFileListLock);
-  xassert(!error);
-  return result;
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  memcpy(uuid, gridptr->uuid, CDI_UUID_SIZE);
 }
 
-int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer)
+
+void gridDefUvRelativeToGrid(int gridID, int uvRelativeToGrid)
 {
-  char* byteBuffer = (char *)buffer;
-  size_t trash;
-  if(!outActualReadSize) outActualReadSize = &trash;
-  *outActualReadSize = 0;
-  while(readSize)
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->uvRelativeToGrid != uvRelativeToGrid )
     {
-      ssize_t bytesRead = pread(me->fileDescriptor, byteBuffer, readSize, readPosition);
-      if(bytesRead == -1) return (errno == EINVAL) ?  CDI_EINVAL : CDI_ESYSTEM;
-      if(bytesRead == 0) return CDI_EEOF;
-      byteBuffer += bytesRead;
-      readPosition += bytesRead;
-      readSize -= (size_t)bytesRead;
-      *outActualReadSize += (size_t)bytesRead;
+      gridMark4Update(gridID);
+      gridptr->uvRelativeToGrid = (bool)uvRelativeToGrid;
     }
-  return CDI_NOERR;
 }
 
-const char* cdiInputFile_getPath(const CdiInputFile* me)
+
+int gridInqUvRelativeToGrid(int gridID)
 {
-  return me->path;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->uvRelativeToGrid;
 }
 
-void cdiInputFile_destruct(CdiInputFile* me)
+
+void gridDefScanningMode(int gridID, int mode)
 {
-  int error = pthread_mutex_lock(&openFileListLock);
-  xassert(!error);
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->scanningMode != mode )
     {
-      //Find the position of me in the list of open files.
-      ssize_t position = (ssize_t)openFileCount;
-      while (position > 0 && openFileList[--position] != me);
-      //Remove me from the list
-      openFileList[position] = openFileList[--openFileCount];
+      gridMark4Update(gridID);
+      gridptr->scanningMode = mode;
     }
-  error = pthread_mutex_unlock(&openFileListLock);
-  xassert(!error);
-  cdiInputFile_condestruct(me, NULL);
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef INSTITUTION_H
-#define INSTITUTION_H
-
-int
-instituteUnpack(void *buf, int size, int *position, int originNamespace,
-                void *context, int force_id);
-
-void instituteDefaultEntries(void);
 
-#endif
+int gridInqScanningMode(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  int scanningModeTMP  = 128 * gridptr->iScansNegatively + 64 * gridptr->jScansPositively + 32 * gridptr->jPointsAreConsecutive;
+  if ( scanningModeTMP != gridptr->scanningMode )
+    Message("WARNING: scanningMode (%d) ! = (%d) 128 * iScansNegatively(%d) + 64 * jScansPositively(%d) + 32 * jPointsAreConsecutive(%d) ",
+            gridptr->scanningMode, scanningModeTMP, gridptr->iScansNegatively,gridptr->jScansPositively,gridptr->jPointsAreConsecutive );
 
-#include <assert.h>
-#include <limits.h>
+  return gridptr->scanningMode;
+}
 
 
-#undef  UNDEFID
-#define UNDEFID  -1
+void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
+{
+  reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
+}
 
-static int ECMWF  = UNDEFID,
-  MPIMET = UNDEFID,
-  MCH    = UNDEFID;
 
-typedef struct
+static int
+gridTxCode ()
 {
-  int    self;
-  int    used;
-  int    center;
-  int    subcenter;
-  char  *name;
-  char  *longname;
+  return GRID;
 }
-institute_t;
 
+enum {
+  GRID_PACK_INT_IDX_SELF,
+  GRID_PACK_INT_IDX_TYPE,
+  GRID_PACK_INT_IDX_DATATYPE,
+  GRID_PACK_INT_IDX_IS_CYCLIC,
+  GRID_PACK_INT_IDX_X_FLAG,
+  GRID_PACK_INT_IDX_Y_FLAG,
+  GRID_PACK_INT_IDX_GME_ND,
+  GRID_PACK_INT_IDX_GME_NI,
+  GRID_PACK_INT_IDX_GME_NI2,
+  GRID_PACK_INT_IDX_GME_NI3,
+  GRID_PACK_INT_IDX_NUMBER,
+  GRID_PACK_INT_IDX_POSITION,
+  GRID_PACK_INT_IDX_TRUNC,
+  GRID_PACK_INT_IDX_NVERTEX,
+  GRID_PACK_INT_IDX_NROWLON,
+  GRID_PACK_INT_IDX_SIZE,
+  GRID_PACK_INT_IDX_X_SIZE,
+  GRID_PACK_INT_IDX_Y_SIZE,
+  GRID_PACK_INT_IDX_LCOMPLEX,
+  GRID_PACK_INT_IDX_MEMBERMASK,
+  GRID_PACK_INT_IDX_XTSTDNNAME,
+  GRID_PACK_INT_IDX_YTSTDNNAME,
+  GRID_PACK_INT_IDX_UVRELATIVETOGRID,
+  GRID_PACK_INT_IDX_ISCANSNEGATIVELY,
+  GRID_PACK_INT_IDX_JSCANSPOSITIVELY,
+  GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE,
+  GRID_PACK_INT_IDX_SCANNINGMODE,
+  gridNint
+};
 
-static int instituteCompareKernel(institute_t *ip1, institute_t *ip2);
-static void instituteDestroyP(institute_t *instituteptr);
-static void   institutePrintP(institute_t *instituteptr, FILE * fp);
-static int instituteGetPackSize(institute_t *instituteptr, void *context);
-static void   institutePackP    ( void * instituteptr, void *buf, int size, int *position, void *context );
-static int    instituteTxCode   ( void );
+enum {
+  GRID_PACK_DBL_IDX_X_FIRST,
+  GRID_PACK_DBL_IDX_Y_FIRST,
+  GRID_PACK_DBL_IDX_X_LAST,
+  GRID_PACK_DBL_IDX_Y_LAST,
+  GRID_PACK_DBL_IDX_X_INC,
+  GRID_PACK_DBL_IDX_Y_INC,
+  gridNdouble
+};
 
-static const resOps instituteOps = {
-  (int (*)(void *, void *))instituteCompareKernel,
-  (void (*)(void *))instituteDestroyP,
-  (void (*)(void *, FILE *))institutePrintP,
-  (int (*)(void *, void *))instituteGetPackSize,
-  institutePackP,
-  instituteTxCode
+enum {
+       gridHasMaskFlag = 1 << 0,
+       gridHasGMEMaskFlag = 1 << 1,
+       gridHasXValsFlag = 1 << 2,
+       gridHasYValsFlag = 1 << 3,
+       gridHasAreaFlag = 1 << 4,
+       gridHasXBoundsFlag = 1 << 5,
+       gridHasYBoundsFlag = 1 << 6,
+       gridHasReferenceFlag = 1 << 7,
+       gridHasRowLonFlag = 1 << 8,
+       gridHasUUIDFlag = 1 << 9,
 };
 
-static
-void instituteDefaultValue ( institute_t * instituteptr )
+
+static int gridGetComponentFlags(const grid_t * gridP)
 {
-  instituteptr->self       = UNDEFID;
-  instituteptr->used       = 0;
-  instituteptr->center     = UNDEFID;
-  instituteptr->subcenter  = UNDEFID;
-  instituteptr->name       = NULL;
-  instituteptr->longname   = NULL;
+  int flags = (gridHasMaskFlag & (int)((unsigned)(gridP->mask == NULL) - 1U))
+    | (gridHasGMEMaskFlag & (int)((unsigned)(gridP->mask_gme == NULL) - 1U))
+    | (gridHasXValsFlag
+       & (int)((unsigned)(gridP->vtable->inqXValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasYValsFlag
+       & (int)((unsigned)(gridP->vtable->inqYValsPtr((grid_t *)gridP) == NULL) - 1U))
+    | (gridHasAreaFlag
+       & (int)((unsigned)(gridP->vtable->inqAreaPtr((grid_t *)gridP) == NULL)
+               - 1U))
+    | (gridHasXBoundsFlag & (int)((unsigned)(gridP->x.bounds == NULL) - 1U))
+    | (gridHasYBoundsFlag & (int)((unsigned)(gridP->y.bounds == NULL) - 1U))
+    | (gridHasReferenceFlag & (int)((unsigned)(gridP->reference == NULL) - 1U))
+    | (gridHasRowLonFlag & (int)((unsigned)(gridP->rowlon == NULL) - 1U))
+    | (gridHasUUIDFlag & (int)((unsigned)cdiUUIDIsNull(gridP->uuid) - 1U));
+  return flags;
 }
 
-void instituteDefaultEntries ( void )
+static int
+gridGetPackSize(void * voidP, void *context)
 {
-  cdiResH resH[]
-    = { ECMWF   = institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
-        MPIMET  = institutDef( 98, 232, "MPIMET",    "Max-Planck-Institute for Meteorology"),
-        institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
-        institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
-        institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
-        institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
-        MCH     = institutDef(215, 255, "MCH",       "MeteoSwiss"),
-        institutDef(  7,   0, "NCEP",      "National Centers for Environmental Prediction"),
-        institutDef(  7,   1, "NCEP",      "National Centers for Environmental Prediction"),
-        institutDef( 60,   0, "NCAR",      "National Center for Atmospheric Research"),
-        institutDef( 74,   0, "METOFFICE", "U.K. Met Office"),
-        institutDef( 97,   0, "ESA",       "European Space Agency"),
-        institutDef( 99,   0, "KNMI",      "Royal Netherlands Meteorological Institute"),
-  };
-  /*     (void) institutDef(  0,   0, "IPSL", "IPSL (Institut Pierre Simon Laplace, Paris, France)"); */
+  grid_t * gridP = ( grid_t * ) voidP;
+  int packBuffSize = 0, count;
 
-  size_t n = sizeof(resH)/sizeof(*resH);
+  packBuffSize += serializeGetSize(gridNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
-  for (size_t i = 0; i < n ; i++ )
-    reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
-}
+  if (gridP->rowlon)
+    {
+      xassert(gridP->nrowlon);
+      packBuffSize += serializeGetSize(gridP->nrowlon, CDI_DATATYPE_INT, context)
+        + serializeGetSize( 1, CDI_DATATYPE_UINT32, context);
+    }
 
+  packBuffSize += serializeGetSize(gridNdouble, CDI_DATATYPE_FLT64, context);
 
-static int
-instituteCompareKernel(institute_t *  ip1, institute_t * ip2)
-{
-  int differ = 0;
-  size_t len1, len2;
+  if (gridP->vtable->inqXValsPtr(gridP))
+    {
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
+	count = gridP->size;
+      else
+	count = gridP->x.size;
+      xassert(count);
+      packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
+    }
 
-  if ( ip1->name )
+  if (gridP->vtable->inqYValsPtr(gridP))
     {
-      if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
-      if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
+	count = gridP->size;
+      else
+	count = gridP->y.size;
+      xassert(count);
+      packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
+    }
 
-      if ( !differ )
-        {
-          if ( ip2->name )
-            {
-              len1 = strlen(ip1->name);
-              len2 = strlen(ip2->name);
-              if ( (len1 != len2) || memcmp(ip2->name, ip1->name, len2) ) differ = 1;
-            }
-        }
+  if (gridP->vtable->inqAreaPtr(gridP))
+    {
+      xassert(gridP->size);
+      packBuffSize +=
+        serializeGetSize(gridP->size, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
-  else if ( ip1->longname )
+
+  if (gridP->x.bounds)
     {
-      if ( ip2->longname )
-        {
-          len1 = strlen(ip1->longname);
-          len2 = strlen(ip2->longname);
-          if ( (len1 < len2) || memcmp(ip2->longname, ip1->longname, len2) ) differ = 1;
-        }
+      xassert(gridP->nvertex);
+      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
+	count = gridP->size;
+      else
+	count = gridP->x.size;
+      xassert(count);
+      packBuffSize
+        += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
+            + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
     }
-  else
+
+  if (gridP->y.bounds)
     {
-      if ( !( ip2->center    == ip1->center &&
-              ip2->subcenter == ip1->subcenter )) differ = 1;
+      xassert(gridP->nvertex);
+      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
+	count = gridP->size;
+      else
+	count = gridP->y.size;
+      xassert(count);
+      packBuffSize
+        += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
+            + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
     }
 
-  return differ;
-}
+  {
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
+    int numStr = (int)(sizeof (strTab) / sizeof (strTab[0]));
+    packBuffSize
+      += serializeStrTabGetPackSize(strTab, numStr, context);
+  }
 
+  if (gridP->reference)
+    {
+      size_t len = strlen(gridP->reference);
+      packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context)
+        + serializeGetSize((int)len + 1, CDI_DATATYPE_TXT, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
+    }
 
-struct instLoc
-{
-  institute_t *ip;
-  int id;
-};
+  if (gridP->mask)
+    {
+      xassert(gridP->size);
+      packBuffSize
+        += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
+    }
 
-static enum cdiApplyRet
-findInstitute(int id, void *res, void *data)
-{
-  institute_t * ip1 = ((struct instLoc *)data)->ip;
-  institute_t * ip2 = (institute_t*) res;
-  if (ip2->used && !instituteCompareKernel(ip1, ip2))
+  if (gridP->mask_gme)
     {
-      ((struct instLoc *)data)->id = id;
-      return CDI_APPLY_STOP;
+      xassert(gridP->size);
+      packBuffSize += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
-  else
-    return CDI_APPLY_GO_ON;
-}
 
+  if (!cdiUUIDIsNull(gridP->uuid))
+    packBuffSize += serializeGetSize(CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
+
+  return packBuffSize;
+}
 
-int institutInq(int center, int subcenter, const char *name, const char *longname)
+void
+gridUnpack(char * unpackBuffer, int unpackBufferSize,
+           int * unpackBufferPos, int originNamespace, void *context,
+           int force_id)
 {
-  institute_t * ip_ref = (institute_t *) Malloc(sizeof (*ip_ref));
-  ip_ref->self       = UNDEFID;
-  ip_ref->used       = 0;
-  ip_ref->center     = center;
-  ip_ref->subcenter  = subcenter;
-  ip_ref->name       = name && name[0] ? (char *)name : NULL;
-  ip_ref->longname   = longname && longname[0] ? (char *)longname : NULL;
+  grid_t * gridP;
+  uint32_t d;
+  int memberMask, size;
 
-  struct instLoc state = { .ip = ip_ref, .id = UNDEFID };
-  cdiResHFilterApply(&instituteOps, findInstitute, &state);
+  gridInit();
 
-  Free(ip_ref);
+  {
+    int intBuffer[gridNint];
+    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                    intBuffer, gridNint, CDI_DATATYPE_INT, context);
+    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                    &d, 1, CDI_DATATYPE_UINT32, context);
 
-  return state.id;
-}
+    xassert(cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer) == d);
+    int targetID = namespaceAdaptKey(intBuffer[0], originNamespace);
+    gridP = gridNewEntry(force_id?targetID:CDI_UNDEFID);
+
+    xassert(!force_id || targetID == gridP->self);
+
+    gridP->type          =   intBuffer[GRID_PACK_INT_IDX_TYPE];
+    gridP->datatype      =   intBuffer[GRID_PACK_INT_IDX_DATATYPE];
+    gridP->isCyclic      =   (signed char)intBuffer[GRID_PACK_INT_IDX_IS_CYCLIC];
+    gridP->x.flag        =   (short)intBuffer[GRID_PACK_INT_IDX_X_FLAG];
+    gridP->y.flag        =   (short)intBuffer[GRID_PACK_INT_IDX_Y_FLAG];
+    gridP->gme.nd        =   intBuffer[GRID_PACK_INT_IDX_GME_ND];
+    gridP->gme.ni        =   intBuffer[GRID_PACK_INT_IDX_GME_NI];
+    gridP->gme.ni2       =   intBuffer[GRID_PACK_INT_IDX_GME_NI2];
+    gridP->gme.ni3       =   intBuffer[GRID_PACK_INT_IDX_GME_NI3];
+    gridP->number        =   intBuffer[GRID_PACK_INT_IDX_NUMBER];
+    gridP->position      =   intBuffer[GRID_PACK_INT_IDX_POSITION];
+    gridP->trunc         =   intBuffer[GRID_PACK_INT_IDX_TRUNC];
+    gridP->nvertex       =   intBuffer[GRID_PACK_INT_IDX_NVERTEX];
+    gridP->nrowlon       =   intBuffer[GRID_PACK_INT_IDX_NROWLON];
+    gridP->size          =   intBuffer[GRID_PACK_INT_IDX_SIZE];
+    gridP->x.size        =   intBuffer[GRID_PACK_INT_IDX_X_SIZE];
+    gridP->y.size        =   intBuffer[GRID_PACK_INT_IDX_Y_SIZE];
+    gridP->lcomplex      =   (bool)intBuffer[GRID_PACK_INT_IDX_LCOMPLEX];
+    memberMask           =   intBuffer[GRID_PACK_INT_IDX_MEMBERMASK];
+    gridP->x.stdname     =
+      xystdname_tab[intBuffer[GRID_PACK_INT_IDX_XTSTDNNAME]][0];
+    gridP->y.stdname     =
+      xystdname_tab[intBuffer[GRID_PACK_INT_IDX_YTSTDNNAME]][1];
+    gridP->uvRelativeToGrid         =   intBuffer[GRID_PACK_INT_IDX_UVRELATIVETOGRID];
+    gridP->iScansNegatively         =   (bool)intBuffer[GRID_PACK_INT_IDX_ISCANSNEGATIVELY];
+    gridP->jScansPositively         =   (bool)intBuffer[GRID_PACK_INT_IDX_JSCANSPOSITIVELY];
+    gridP->jPointsAreConsecutive    =   (bool)intBuffer[GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE];
+    gridP->scanningMode             =   intBuffer[GRID_PACK_INT_IDX_SCANNINGMODE];
+  }
+
+  if (memberMask & gridHasRowLonFlag)
+    {
+      xassert(gridP->nrowlon);
+      gridP->rowlon = (int *) Malloc((size_t)gridP->nrowlon * sizeof (int));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->rowlon, gridP->nrowlon , CDI_DATATYPE_INT, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_INT, gridP->nrowlon, gridP->rowlon) == d);
+    }
+
+  {
+    double doubleBuffer[gridNdouble];
+    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                    doubleBuffer, gridNdouble, CDI_DATATYPE_FLT64, context);
+    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                    &d, 1, CDI_DATATYPE_UINT32, context);
+    xassert(d == cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer));
+
+    gridP->x.first = doubleBuffer[GRID_PACK_DBL_IDX_X_FIRST];
+    gridP->y.first = doubleBuffer[GRID_PACK_DBL_IDX_Y_FIRST];
+    gridP->x.last = doubleBuffer[GRID_PACK_DBL_IDX_X_LAST];
+    gridP->y.last = doubleBuffer[GRID_PACK_DBL_IDX_Y_LAST];
+    gridP->x.inc = doubleBuffer[GRID_PACK_DBL_IDX_X_INC];
+    gridP->y.inc = doubleBuffer[GRID_PACK_DBL_IDX_Y_INC];
+  }
+
+  bool irregular = gridP->type == GRID_UNSTRUCTURED
+    || gridP->type == GRID_CURVILINEAR;
+  if (memberMask & gridHasXValsFlag)
+    {
+      size = irregular ? gridP->size : gridP->x.size;
+
+      gridP->x.vals = (double *) Malloc(size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->x.vals, size, CDI_DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.vals) == d );
+    }
+
+  if (memberMask & gridHasYValsFlag)
+    {
+      size = irregular ? gridP->size : gridP->y.size;
+
+      gridP->y.vals = (double *) Malloc(size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->y.vals, size, CDI_DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.vals) == d);
+    }
+
+  if (memberMask & gridHasAreaFlag)
+    {
+      size = gridP->size;
+      xassert(size);
+      gridP->area = (double *) Malloc(size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->area, size, CDI_DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->area) == d);
+    }
+
+  if (memberMask & gridHasXBoundsFlag)
+    {
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->x.size);
+      xassert(size);
+
+      gridP->x.bounds = (double *) Malloc(size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->x.bounds, size, CDI_DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.bounds) == d);
+    }
+
+  if (memberMask & gridHasYBoundsFlag)
+    {
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->y.size);
+      xassert(size);
+
+      gridP->y.bounds = (double *) Malloc(size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+			  gridP->y.bounds, size, CDI_DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds) == d);
+    }
+
+  {
+    char *strTab[] = GRID_STR_SERIALIZE(gridP);
+    int numStr = sizeof (strTab) / sizeof (strTab[0]);
+    serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                          strTab, numStr, context);
+  }
 
-static
-institute_t *instituteNewEntry(cdiResH resH, int center, int subcenter,
-                               const char *name, const char *longname)
-{
-  institute_t *instituteptr = (institute_t*) Malloc(sizeof(institute_t));
-  instituteDefaultValue(instituteptr);
-  if (resH == CDI_UNDEFID)
-    instituteptr->self = reshPut(instituteptr, &instituteOps);
-  else
+  if (memberMask & gridHasReferenceFlag)
     {
-      instituteptr->self = resH;
-      reshReplace(resH, instituteptr, &instituteOps);
+      int referenceSize;
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &referenceSize, 1, CDI_DATATYPE_INT, context);
+      gridP->reference = (char *) Malloc(referenceSize);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->reference, referenceSize, CDI_DATATYPE_TXT, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_TXT, referenceSize, gridP->reference) == d);
     }
-  instituteptr->used = 1;
-  instituteptr->center = center;
-  instituteptr->subcenter = subcenter;
-  if ( name && *name )
-    instituteptr->name = strdupx(name);
-  if (longname && *longname)
-    instituteptr->longname = strdupx(longname);
-  return  instituteptr;
-}
 
+  if (memberMask & gridHasMaskFlag)
+    {
+      xassert((size = gridP->size));
+      gridP->mask = (mask_t *) Malloc(size * sizeof (mask_t));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->mask, gridP->size, CDI_DATATYPE_UCHAR, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_UCHAR, gridP->size, gridP->mask) == d);
+    }
 
-int institutDef(int center, int subcenter, const char *name, const char *longname)
-{
-  institute_t * instituteptr
-    = instituteNewEntry(CDI_UNDEFID, center, subcenter, name, longname);
-  return instituteptr->self;
+  if (memberMask & gridHasGMEMaskFlag)
+    {
+      xassert((size = gridP->size));
+      gridP->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->mask_gme, gridP->size, CDI_DATATYPE_UCHAR, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_UCHAR, gridP->size, gridP->mask_gme) == d);
+    }
+  if (memberMask & gridHasUUIDFlag)
+    {
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
+    }
+
+  reshSetStatus(gridP->self, &gridOps,
+                reshGetStatus(gridP->self, &gridOps) & ~RESH_SYNC_BIT);
 }
 
 
-int institutInqCenter(int instID)
+static void
+gridPack(void * voidP, void * packBuffer, int packBufferSize,
+         int * packBufferPos, void *context)
 {
-  institute_t * instituteptr = NULL;
-
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+  grid_t   * gridP = ( grid_t * )   voidP;
+  int size;
+  uint32_t d;
+  int memberMask;
 
-  return  instituteptr ? instituteptr->center : UNDEFID;
-}
+  {
+    int intBuffer[gridNint];
 
+    intBuffer[GRID_PACK_INT_IDX_SELF]         = gridP->self;
+    intBuffer[GRID_PACK_INT_IDX_TYPE]         = gridP->type;
+    intBuffer[GRID_PACK_INT_IDX_DATATYPE]     = gridP->datatype;
+    intBuffer[GRID_PACK_INT_IDX_IS_CYCLIC]    = gridP->isCyclic;
+    intBuffer[GRID_PACK_INT_IDX_X_FLAG]       = gridP->x.flag;
+    intBuffer[GRID_PACK_INT_IDX_Y_FLAG]       = gridP->y.flag;
+    intBuffer[GRID_PACK_INT_IDX_GME_ND]       = gridP->gme.nd;
+    intBuffer[GRID_PACK_INT_IDX_GME_NI]       = gridP->gme.ni;
+    intBuffer[GRID_PACK_INT_IDX_GME_NI2]      = gridP->gme.ni2;
+    intBuffer[GRID_PACK_INT_IDX_GME_NI3]      = gridP->gme.ni3;
+    intBuffer[GRID_PACK_INT_IDX_NUMBER]       = gridP->number;
+    intBuffer[GRID_PACK_INT_IDX_POSITION]     = gridP->position;
+    intBuffer[GRID_PACK_INT_IDX_TRUNC]        = gridP->trunc;
+    intBuffer[GRID_PACK_INT_IDX_NVERTEX]      = gridP->nvertex;
+    intBuffer[GRID_PACK_INT_IDX_NROWLON]      = gridP->nrowlon;
+    intBuffer[GRID_PACK_INT_IDX_SIZE]         = gridP->size;
+    intBuffer[GRID_PACK_INT_IDX_X_SIZE]       = gridP->x.size;
+    intBuffer[GRID_PACK_INT_IDX_Y_SIZE]       = gridP->y.size;
+    intBuffer[GRID_PACK_INT_IDX_LCOMPLEX]     = gridP->lcomplex;
+    intBuffer[GRID_PACK_INT_IDX_MEMBERMASK]   = memberMask
+                                              = gridGetComponentFlags(gridP);
+    intBuffer[GRID_PACK_INT_IDX_XTSTDNNAME]   =
+      (int)((const char (*)[2][24])gridP->x.stdname - xystdname_tab);
+    intBuffer[GRID_PACK_INT_IDX_YTSTDNNAME]   =
+      (int)((const char (*)[2][24])gridP->y.stdname
+            - (const char (*)[2][24])xystdname_tab[0][1]);
+
+    intBuffer[GRID_PACK_INT_IDX_UVRELATIVETOGRID] = gridP->uvRelativeToGrid;
+    intBuffer[GRID_PACK_INT_IDX_ISCANSNEGATIVELY] = gridP->iScansNegatively;
+    intBuffer[GRID_PACK_INT_IDX_JSCANSPOSITIVELY] = gridP->jScansPositively;
+    intBuffer[GRID_PACK_INT_IDX_JPOINTSARECONSECUTIVE] = gridP->jPointsAreConsecutive;
+    intBuffer[GRID_PACK_INT_IDX_SCANNINGMODE] = gridP->scanningMode;
+
+    serializePack(intBuffer, gridNint, CDI_DATATYPE_INT,
+                  packBuffer, packBufferSize, packBufferPos, context);
+    d = cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer);
+    serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                  packBuffer, packBufferSize, packBufferPos, context);
+  }
 
-int institutInqSubcenter(int instID)
-{
-  institute_t * instituteptr = NULL;
+  if (memberMask & gridHasRowLonFlag)
+    {
+      size = gridP->nrowlon;
+      xassert(size > 0);
+      serializePack(gridP->rowlon, size, CDI_DATATYPE_INT,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_INT , size, gridP->rowlon);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+  {
+    double doubleBuffer[gridNdouble];
 
-  return instituteptr ? instituteptr->subcenter: UNDEFID;
-}
+    doubleBuffer[GRID_PACK_DBL_IDX_X_FIRST]        = gridP->x.first;
+    doubleBuffer[GRID_PACK_DBL_IDX_Y_FIRST]        = gridP->y.first;
+    doubleBuffer[GRID_PACK_DBL_IDX_X_LAST]         = gridP->x.last;
+    doubleBuffer[GRID_PACK_DBL_IDX_Y_LAST]         = gridP->y.last;
+    doubleBuffer[GRID_PACK_DBL_IDX_X_INC]          = gridP->x.inc;
+    doubleBuffer[GRID_PACK_DBL_IDX_Y_INC]          = gridP->y.inc;
 
+    serializePack(doubleBuffer, gridNdouble, CDI_DATATYPE_FLT64,
+                  packBuffer, packBufferSize, packBufferPos, context);
+    d = cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer);
+    serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                  packBuffer, packBufferSize, packBufferPos, context);
+  }
 
-const char *institutInqNamePtr(int instID)
-{
-  institute_t * instituteptr = NULL;
+  if (memberMask & gridHasXValsFlag)
+    {
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
+	size = gridP->size;
+      else
+	size = gridP->x.size;
+      xassert(size);
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+      const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
+      serializePack(gridP_xvals, size, CDI_DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_xvals);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-  return instituteptr ? instituteptr->name : NULL;
-}
+  if (memberMask & gridHasYValsFlag)
+    {
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR )
+	size = gridP->size;
+      else
+	size = gridP->y.size;
+      xassert(size);
+      const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
+      serializePack(gridP_yvals, size, CDI_DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_yvals);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
+  if (memberMask & gridHasAreaFlag)
+    {
+      xassert(gridP->size);
 
-const char *institutInqLongnamePtr(int instID)
-{
-  institute_t * instituteptr = NULL;
+      serializePack(gridP->area, gridP->size, CDI_DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_FLT, gridP->size, gridP->area);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+  if (memberMask & gridHasXBoundsFlag)
+    {
+      xassert ( gridP->nvertex );
+      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
+	size = gridP->nvertex * gridP->size;
+      else
+	size = gridP->nvertex * gridP->x.size;
+      xassert ( size );
 
-  return instituteptr ? instituteptr->longname : NULL;
-}
+      serializePack(gridP->x.bounds, size, CDI_DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.bounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-static enum cdiApplyRet
-activeInstitutes(int id, void *res, void *data)
-{
-  (void)id;
-  if (res && ((institute_t *)res)->used)
-    ++(*(int *)data);
-  return CDI_APPLY_GO_ON;
-}
+  if (memberMask & gridHasYBoundsFlag)
+    {
+      xassert(gridP->nvertex);
+      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
+	size = gridP->nvertex * gridP->size;
+      else
+	size = gridP->nvertex * gridP->y.size;
+      xassert ( size );
 
-int institutInqNumber(void)
-{
-  int instNum = 0;
+      serializePack(gridP->y.bounds, size, CDI_DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-  cdiResHFilterApply(&instituteOps, activeInstitutes, &instNum);
-  return instNum;
-}
+  {
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
+    int numStr = sizeof (strTab) / sizeof (strTab[0]);
+    serializeStrTabPack(strTab, numStr,
+                        packBuffer, packBufferSize, packBufferPos, context);
+  }
 
+  if (memberMask & gridHasReferenceFlag)
+    {
+      size = (int)strlen(gridP->reference) + 1;
+      serializePack(&size, 1, CDI_DATATYPE_INT,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      serializePack(gridP->reference, size, CDI_DATATYPE_TXT,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_TXT, size, gridP->reference);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-static void
-instituteDestroyP(institute_t *instituteptr)
-{
-  xassert(instituteptr);
+  if (memberMask & gridHasMaskFlag)
+    {
+      xassert((size = gridP->size));
+      serializePack(gridP->mask, size, CDI_DATATYPE_UCHAR,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-  int instituteID = instituteptr->self;
-  Free(instituteptr->name);
-  Free(instituteptr->longname);
-  reshRemove(instituteID, &instituteOps);
-  Free(instituteptr);
-}
+  if (memberMask & gridHasGMEMaskFlag)
+    {
+      xassert((size = gridP->size));
 
+      serializePack(gridP->mask_gme, size, CDI_DATATYPE_UCHAR,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask_gme);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-static void institutePrintP(institute_t *ip, FILE * fp )
-{
-  if (ip)
-    fprintf(fp, "#\n"
-            "# instituteID %d\n"
-            "#\n"
-            "self          = %d\n"
-            "used          = %d\n"
-            "center        = %d\n"
-            "subcenter     = %d\n"
-            "name          = %s\n"
-            "longname      = %s\n",
-            ip->self, ip->self, ip->used, ip->center, ip->subcenter,
-            ip->name ? ip->name : "NN",
-            ip->longname ? ip->longname : "NN");
+  if (memberMask & gridHasUUIDFlag)
+    serializePack(gridP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR,
+                  packBuffer, packBufferSize, packBufferPos, context);
 }
 
+#undef GRID_STR_SERIALIZE
 
-static int
-instituteTxCode ( void )
-{
-  return INSTITUTE;
-}
-
-enum {
-  institute_nints = 5,
-};
 
-static int instituteGetPackSize(institute_t *ip, void *context)
+struct gridCompareSearchState
 {
-  size_t namelen = strlen(ip->name), longnamelen = strlen(ip->longname);
-  xassert(namelen < INT_MAX && longnamelen < INT_MAX);
-  size_t txsize = (size_t)serializeGetSize(institute_nints, DATATYPE_INT, context)
-    + (size_t)serializeGetSize((int)namelen + 1, DATATYPE_TXT, context)
-    + (size_t)serializeGetSize((int)longnamelen + 1, DATATYPE_TXT, context);
-  xassert(txsize <= INT_MAX);
-  return (int)txsize;
-}
+  int resIDValue;
+  const grid_t *queryKey;
+};
 
-static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
+static enum cdiApplyRet
+gridCompareSearch(int id, void *res, void *data)
 {
-  institute_t *p = (institute_t*) instituteptr;
-  int tempbuf[institute_nints];
-  tempbuf[0] = p->self;
-  tempbuf[1] = p->center;
-  tempbuf[2] = p->subcenter;
-  tempbuf[3] = (int)strlen(p->name) + 1;
-  tempbuf[4] = (int)strlen(p->longname) + 1;
-  serializePack(tempbuf, institute_nints, DATATYPE_INT, buf, size, position, context);
-  serializePack(p->name, tempbuf[3], DATATYPE_TXT, buf, size, position, context);
-  serializePack(p->longname, tempbuf[4], DATATYPE_TXT, buf, size, position, context);
+  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
+  (void)res;
+  if ( gridCompare(id, state->queryKey, true) == false )
+    {
+      state->resIDValue = id;
+      return CDI_APPLY_STOP;
+    }
+  else
+    return CDI_APPLY_GO_ON;
 }
 
-int instituteUnpack(void *buf, int size, int *position, int originNamespace,
-                    void *context, int force_id)
+/* Add grid (which must be Malloc'ed to vlist if not already found) */
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
 {
-  int tempbuf[institute_nints];
-  int instituteID;
-  char *name, *longname;
-  serializeUnpack(buf, size, position, tempbuf, institute_nints, DATATYPE_INT, context);
-  name = (char *) Malloc((size_t)tempbuf[3] + (size_t)tempbuf[4]);
-  longname = name + tempbuf[3];
-  serializeUnpack(buf, size, position, name, tempbuf[3], DATATYPE_TXT, context);
-  serializeUnpack(buf, size, position, longname, tempbuf[4], DATATYPE_TXT, context);
-  int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
-  institute_t *ip = instituteNewEntry(force_id?targetID:CDI_UNDEFID,
-                                      tempbuf[1], tempbuf[2], name, longname);
-  instituteID = ip->self;
-  xassert(!force_id || instituteID == targetID);
-  Free(name);
-  reshSetStatus(instituteID, &instituteOps,
-                reshGetStatus(instituteID, &instituteOps) & ~RESH_SYNC_BIT);
-  return instituteID;
-}
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-/*
- * This file is for the use of iterator.c and the CdiIterator subclasses only.
- */
-
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_INT_H
-#define INCLUDE_GUARD_CDI_ITERATOR_INT_H
-
-
-#include <stdbool.h>
+  /*
+    mode: 0 search in vlist and grid table
+          1 search in grid table only
+          2 search in grid table only and don't store the grid in vlist
+   */
+  bool gridglobdefined = false;
+  bool griddefined = false;
+  int gridID = CDI_UNDEFID;
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-/*
-class CdiIterator
+  unsigned ngrids = (unsigned)vlistptr->ngrids;
 
-An iterator is an object that identifies the position of one record in a file, where a record is defined as the data belonging to one level, timestep, and variable.
-Using iterators to read a file can be significantly faster than using streams, because they can avoid building an index of the file.
-For file formats like grib that do not provide an index within the file, this makes the difference between reading the file once or reading the file twice.
+  if ( mode == 0 )
+    for ( unsigned index = 0; index < ngrids; index++ )
+      {
+	if ( (gridID = vlistptr->gridIDs[index]) != CDI_UNDEFID )
+          {
+            if ( gridCompare(gridID, grid, false) == false )
+              {
+                griddefined = true;
+                break;
+              }
+          }
+        else
+          Error("Internal problem: undefined gridID in vlist "
+                "%d, position %u!", vlistID, index);
+      }
 
-CdiIterator is an abstract base class. Which derived class is used depends on the type of the file. The class hierarchy currently looks like this:
+  if ( ! griddefined )
+    {
+      struct gridCompareSearchState query;
+      query.queryKey = grid;// = { .queryKey = grid };
+      if ( (gridglobdefined = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
+              == CDI_APPLY_STOP)) )
+        gridID = query.resIDValue;
 
-    CdiIterator <|--+-- CdiFallbackIterator
-                    |
-                    +-- CdiGribIterator
+      if ( mode == 1 && gridglobdefined )
+	for ( unsigned index = 0; index < ngrids; index++ )
+	  if ( vlistptr->gridIDs[index] == gridID )
+	    {
+	      gridglobdefined = false;
+	      break;
+	    }
+    }
 
-The fallback implementation currently uses the stream interface of CDI under the hood to provide full functionality for all filetypes for which no iterator implementation exists yet.
-*/
-//TODO[NH]: Debug messages, print function.
+  if ( ! griddefined )
+    {
+      if ( ! gridglobdefined )
+        {
+          grid->self = gridID = reshPut(grid, &gridOps);
+          gridComplete(grid);
+        }
+      if ( mode < 2 )
+        {
+          vlistptr->gridIDs[ngrids] = gridID;
+          vlistptr->ngrids++;
+        }
+    }
 
-struct CdiIterator {
-  int filetype;      //This is used to dispatch calls to the correct subclass.
-  bool isAdvanced;    //Used to catch inquiries before the first call to CdiIteratorNextField(). //XXX: Advanced is probably not a good word (initialized?)
+  return (struct addIfNewRes){ .Id = gridID, .isNew = !griddefined && !gridglobdefined };
+}
 
-  //The metadata that can be accessed by the inquiry calls.
-  //While theoretically redundant, these fields allow the handling of most inquiry calls within the base class.
-  //Only the name is excempted because it needs an allocation.
-  //These fields are set by the subclasses in the xxxIterNextField() method.
-  int datatype, timesteptype;
-  int gridId;
-  CdiParam param;
 
-  //The status information for reading/advancing is added in the subclasses.
+const struct gridVirtTable cdiGridVtable
+  = {
+  .destroy = gridDestroyKernel,
+  .copy = grid_copy_base,
+  .copyScalarFields = grid_copy_base_scalar_fields,
+  .copyArrayFields = grid_copy_base_array_fields,
+  .defXVals = gridDefXValsSerial,
+  .defYVals = gridDefYValsSerial,
+  .defMask = gridDefMaskSerial,
+  .defMaskGME = gridDefMaskGMESerial,
+  .defXBounds = gridDefXBoundsSerial,
+  .defYBounds = gridDefYBoundsSerial,
+  .defArea = gridDefAreaSerial,
+  .inqXVal = gridInqXValSerial,
+  .inqYVal = gridInqYValSerial,
+  .inqXVals = gridInqXValsSerial,
+  .inqXCvals = gridInqXCvalsSerial,
+  .inqXIsc = gridInqXIscSerial,
+  .inqYVals = gridInqYValsSerial,
+  .inqYCvals = gridInqYCvalsSerial,
+  .inqYIsc = gridInqYIscSerial,
+  .inqXValsPtr = gridInqXValsPtrSerial,
+  .inqYValsPtr = gridInqYValsPtrSerial,
+  .inqXCvalsPtr = gridInqXCvalsPtrSerial,
+  .inqYCvalsPtr = gridInqYCvalsPtrSerial,
+  .compareXYFull = compareXYvals,
+  .compareXYAO = compareXYvals2,
+  .inqArea = gridInqAreaSerial,
+  .inqAreaPtr = gridInqAreaPtrBase,
+  .hasArea = gridHasAreaBase,
+  .inqMask = gridInqMaskSerial,
+  .inqMaskGME = gridInqMaskGMESerial,
+  .inqXBounds = gridInqXBoundsSerial,
+  .inqYBounds = gridInqYBoundsSerial,
+  .inqXBoundsPtr = gridInqXBoundsPtrSerial,
+  .inqYBoundsPtr = gridInqYBoundsPtrSerial,
 };
 
-void baseIterConstruct(CdiIterator *me, int filetype);
-const char* baseIter_constructFromString(CdiIterator *me, const char *description);     //Returns a pointer past the end of the parsed portion of the description string.
-void baseIterDestruct(CdiIterator *me);
-
-#endif
-
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -30300,1218 +29585,822 @@ void baseIterDestruct(CdiIterator *me);
  * require-trailing-newline: t
  * End:
  */
-/*
- * A fallback implementation of the iterator interface that opens a stream under the hood.
- *
- * This implementation is mainly available to provide iterator access to file formats that don't support iterator access natively,
- * nevertheless, it allows the file to dictate the order in which data is read, possibly providing performance benefits.
- */
-
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
-#define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
-
-
-typedef struct CdiFallbackIterator CdiFallbackIterator;
-
-CdiIterator *cdiFallbackIterator_new(const char *path, int filetype);
-CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *me);
-CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me);
-char *cdiFallbackIterator_serialize(CdiIterator *me);
-CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
+#if defined (HAVE_CONFIG_H)
+#endif
 
-int cdiFallbackIterator_nextField(CdiIterator *me);
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
-char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
-int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
-int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
-int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
-char *cdiFallbackIterator_copyVariableName(CdiIterator *me);
-int cdiFallbackIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute);
-int cdiFallbackIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount);
 
-void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
-void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
 
-void cdiFallbackIterator_delete(CdiIterator *super);
+static int initIegLib      = 0;
+static int iegDefaultDprec = 0;
 
-#endif
 
 /*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-/*
- * An implementation of the iterator interface for GRIB files.
- * Since GRIB files do not contain an index, this avoids scanning the entire file to generate an in-memory index as streamOpenRead() does.
- * Consequently, using this interface is much more efficient for GRIB files.
+ * A version string.
  */
+#undef  LIBVERSION
+#define LIBVERSION      1.4.0
+#define XSTRING(x)	#x
+#define STRING(x)	XSTRING(x)
+static const char ieg_libvers[] = STRING(LIBVERSION) " of " __DATE__ " " __TIME__;
 
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
-#define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
-
-
-#ifdef HAVE_LIBGRIB_API
-#include <grib_api.h>
-#endif
-
-typedef struct recordList recordList;
-
-CdiIterator *cdiGribIterator_new(const char *path, int filetype);
-CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *me);
-CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me);
-char *cdiGribIterator_serialize(CdiIterator *me);
-CdiGribIterator *cdiGribIterator_deserialize(const char *me);
+const char *iegLibraryVersion(void)
+{
+  return ieg_libvers;
+}
 
-int cdiGribIterator_nextField(CdiIterator *me);
 
-char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
-int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
-int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
-int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
-int cdiGribIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute);
-int cdiGribIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount);
-char *cdiGribIterator_copyVariableName(CdiIterator *me);
+static int IEG_Debug = 0;    /* If set to 1, debugging */
 
-void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
-void cdiGribIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
+static
+void iegLibInit(void)
+{
+  const char *envName = "IEG_PRECISION";
 
-#endif
+  char *envString = getenv(envName);
+  if ( envString )
+    {
+      int pos;
+      int nrun;
+      if ( strlen(envString) == 2 ) nrun = 1;
+      else                          nrun = 2;
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
+      pos = 0;
+      while ( nrun-- )
+	{
+	  switch ( tolower((int) envString[pos]) )
+	    {
+	    case 'r':
+	      {
+		switch ( (int) envString[pos+1] )
+		  {
+		  case '4': iegDefaultDprec = EXSE_SINGLE_PRECISION; break;
+		  case '8': iegDefaultDprec = EXSE_DOUBLE_PRECISION; break;
+		  default:
+		    Message("Invalid digit in %s: %s", envName, envString);
+		  }
+		break;
+	      }
+	    default:
+              {
+                Message("Invalid character in %s: %s", envName, envString);
+                break;
+              }
+            }
+	  pos += 2;
+	}
+    }
 
-#include <assert.h>
-#include <ctype.h>
+  initIegLib = 1;
+}
 
-static const char kUnexpectedFileTypeMessage[]
-  = "Internal error: Unexpected file type encountered in iterator.\n"
-  "This is either due to an illegal memory access by the application\n"
-  " or an internal logical error in CDI (unlikely, but possible).";
-static const char kAdvancedString[] = "advanced";
-static const char kUnadvancedString[] = "unadvanced";
 
-//Returns a static string.
-static const char* fileType2String(int fileType)
+void iegDebug(int debug)
 {
-  switch(fileType)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB: return "CDI::Iterator::GRIB1";
-        case FILETYPE_GRB2: return "CDI::Iterator::GRIB2";
-#endif
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC: return "CDI::Iterator::NetCDF";
-        case FILETYPE_NC2: return "CDI::Iterator::NetCDF2";
-        case FILETYPE_NC4: return "CDI::Iterator::NetCDF4";
-        case FILETYPE_NC4C: return "CDI::Iterator::NetCDF4C";
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV: return "CDI::Iterator::SRV";
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT: return "CDI::Iterator::EXT";
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG: return "CDI::Iterator::IEG";
-#endif
+  IEG_Debug = debug;
 
-      default: return NULL;
-    }
+  if ( IEG_Debug )
+    Message("debug level %d", debug);
 }
 
-static int string2FileType(const char* fileType, const char **outRestString)
+static
+void iegInit(iegrec_t *iegp)
 {
-  //This first part unconditionally checks all known type strings, and only if the given string matches one of these strings, we use fileType2string() to check whether support for this type has been compiled in. This is to avoid throwing "invalid type string" errors when we just have a library version mismatch.
-#define check(givenString, typeString, typeConstant) do \
-    { \
-      if(givenString == strstr(givenString, typeString)) \
-        { \
-          if(outRestString) *outRestString = givenString + strlen(typeString); \
-          if(fileType2String(typeConstant)) return typeConstant; \
-          Error("Support for " typeString " not compiled in. Please check that the result of `cdiIterator_serialize()` is only passed to a `cdiIterator_deserialize()` implementation of the same CDI library version."); \
-          return FILETYPE_UNDEF; \
-        } \
-    } while(0)
-  check(fileType, "CDI::Iterator::GRIB1", FILETYPE_GRB);
-  check(fileType, "CDI::Iterator::GRIB2", FILETYPE_GRB2);
-  check(fileType, "CDI::Iterator::NetCDF", FILETYPE_NC);
-  check(fileType, "CDI::Iterator::NetCDF2", FILETYPE_NC2);
-  check(fileType, "CDI::Iterator::NetCDF4", FILETYPE_NC4);
-  check(fileType, "CDI::Iterator::NetCDF4C", FILETYPE_NC4C);
-  check(fileType, "CDI::Iterator::SRV", FILETYPE_SRV);
-  check(fileType, "CDI::Iterator::EXT", FILETYPE_EXT);
-  check(fileType, "CDI::Iterator::IEG", FILETYPE_IEG);
-#undef check
-
-  //If this point is reached, the given string does not seem to be produced by a cdiIterator_serialize() call.
-  Error("The string \"%s\" does not start with a valid iterator type. Please check the source of this string.", fileType);
-  *outRestString = fileType;
-  return FILETYPE_UNDEF;
+  iegp->checked    = 0;
+  iegp->byteswap   = 0;
+  iegp->dprec      = 0;
+  iegp->refval     = 0;
+  iegp->datasize   = 0;
+  iegp->buffersize = 0;
+  iegp->buffer     = NULL;
 }
 
-/*
- at Function cdiIterator_new
- at Title Create an iterator for an input file
 
- at Prototype CdiIterator* cdiIterator_new(const char* path)
- at Parameter
-    @item path Path to the file that is to be read.
+void iegInitMem(void *ieg)
+{
+  iegrec_t *iegp = (iegrec_t *) ieg;
 
- at Result An iterator for the given file.
+  memset(iegp->ipdb, 0, sizeof(iegp->ipdb));
+  memset(iegp->igdb, 0, sizeof(iegp->igdb));
+  memset(iegp->vct,  0, sizeof(iegp->vct));
+}
 
- at Description
-    Combined allocator and constructor for CdiIterator.
 
-    The returned iterator does not point to the first field yet,
-    it must first be advanced once before the first field can be introspected.
-    This design decision has two benefits: 1. Empty files require no special
-    cases, 2. Users can start a while(!cdiIterator_nextField(iterator)) loop
-    right after the call to cdiIterator_new().
-*/
-CdiIterator* cdiIterator_new(const char* path)
+void *iegNew(void)
 {
-  int trash;
-  int filetype = cdiGetFiletype(path, &trash);
-  switch(filetype)
-    {
-      case FILETYPE_UNDEF:
-        Warning("Can't open file \"%s\": unknown format\n", path);
-        return NULL;
+  if ( ! initIegLib ) iegLibInit();
 
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_new(path, filetype);
-#endif
+  iegrec_t *iegp = (iegrec_t *) Malloc(sizeof(iegrec_t));
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_new(path, filetype);
+  iegInit(iegp);
+  iegInitMem(iegp);
 
-      default:
-        Warning("the file \"%s\" is of type %s, but support for this format is not compiled in!", path, strfiletype(filetype));
-        return NULL;
-    }
+  return (void*)iegp;
 }
 
-void baseIterConstruct(CdiIterator* me, int filetype)
-{
-  me->filetype = filetype;
-  me->isAdvanced = false;
-}
 
-const char* baseIter_constructFromString(CdiIterator* me, const char* description)
+void iegDelete(void *ieg)
 {
-  const char* result = description;
-  me->filetype = string2FileType(result, &result);
-  assert(me->filetype != FILETYPE_UNDEF && "Please report this error.");        //This condition should have been checked for in a calling function.
-  for(; *result && isspace(*result); result++);
-  if(result == strstr(result, kAdvancedString))
-    {
-      me->isAdvanced = true;
-      result += sizeof (kAdvancedString) - 1;
-    }
-  else if(result == strstr(result, kUnadvancedString))
-    {
-      me->isAdvanced = false;
-      result += sizeof (kUnadvancedString) - 1;
-    }
-  else
+  iegrec_t *iegp = (iegrec_t *) ieg;
+
+  if ( iegp )
     {
-      Error("Invalid iterator description string \"%s\". Please check the origin of this string.", description);
-      return NULL;
+      if ( iegp->buffer ) Free(iegp->buffer);
+      Free(iegp);
     }
-  return result;
 }
 
-#define sanityCheck(me) do { \
-    if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
-    if(!me->isAdvanced) xabort("Calling %s is not allowed without calling cdiIterator_nextField() first.", __func__); \
-} while(0)
 
-/*
- at Function cdiIterator_clone
- at Title Make a copy of an iterator
+int iegCheckFiletype(int fileID, int *swap)
+{
+  size_t data = 0;
+  size_t dimx = 0, dimy = 0;
+  size_t fact = 0;
+  unsigned char buffer[1048], *pbuf;
 
- at Prototype CdiIterator* cdiIterator_clone(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to copy.
+  if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
 
- at Result The clone.
+  size_t blocklen  = get_UINT32(buffer);
+  size_t sblocklen = get_SUINT32(buffer);
 
- at Description
-    Clones the given iterator. Make sure to call cdiIterator_delete() on both
-    the copy and the original.
+  if ( IEG_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
-    This is not a cheap operation: Depending on the type of the file, it will
-    either make a copy of the current field in memory (GRIB files), or reopen
-    the file (all other file types). Use it sparingly. And if you do, try to
-    avoid keeping too many clones around: their memory footprint is
-    significant.
-*/
-CdiIterator* cdiIterator_clone(CdiIterator* me)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  if ( blocklen == 636 || blocklen == 640 )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_getSuper(cdiGribIterator_clone(me));
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_getSuper(cdiFallbackIterator_clone(me));
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+     *swap = 0;
+      fact = 4;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
+      pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
     }
-}
-
-/*
- at Function cdiGribIterator_clone
- at Title Gain access to GRIB specific functionality
-
- at Prototype CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
-
- at Result A clone that allows access to GRIB specific functionality, or NULL if the underlying file is not a GRIB file.
-
- at Description
-    Clones the given iterator iff the underlying file is a GRIB file, the returned iterator allows access to GRIB specific functionality.
-    Make sure to check that the return value is not NULL, and to call cdiGribIterator_delete() on the copy.
-
-    This is not a cheap operation: It will make a copy of the current field in memory. Use it sparingly. And if you do, try to avoid keeping too many clones around, their memory footprint is significant.
-*/
-CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  else if ( blocklen == 1040 || blocklen == 1036 )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_makeClone(me);
-#endif
-
-      default:
-        return NULL;
+     *swap = 0;
+      fact = 8;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return 0;
+      pbuf = buffer+(37+4)*4;    dimx = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+(37+5)*4;    dimy = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
+    }
+  else if ( sblocklen == 636 || sblocklen == 640 )
+    {
+     *swap = 1;
+      fact = 4;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
+      pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
+    }
+  else if ( sblocklen == 1040 || sblocklen == 1036 )
+    {
+     *swap = 1;
+      fact = 8;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return 0;
+      pbuf = buffer+(37+4)*4;     dimx = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+(37+5)*4;     dimy = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
     }
-}
-
-/*
- at Function cdiIterator_serialize
- at Title Serialize an iterator for sending it to another process
 
- at Prototype char* cdiIterator_serialize(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
+  fileRewind(fileID);
 
- at Result A malloc'ed string that contains the full description of the iterator.
+  int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
 
- at Description
-    Make sure to call Free() on the resulting string.
-*/
-char* cdiIterator_serialize(CdiIterator* me)
-{
-  if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
-  char* subclassDescription = NULL;
-  switch(me->filetype)
+  if ( IEG_Debug )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          subclassDescription = cdiGribIterator_serialize(me);
-          break;
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          subclassDescription = cdiFallbackIterator_serialize(me);
-          break;
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
     }
 
-  const char *ftypeStr = fileType2String(me->filetype),
-    *advStr = me->isAdvanced ? kAdvancedString : kUnadvancedString;
-  char* result = (char *) Malloc(strlen(ftypeStr) + 1 + strlen(advStr) + 1
-                         + strlen(subclassDescription) + 1);
-  sprintf(result, "%s %s %s", ftypeStr, advStr, subclassDescription);
-  Free(subclassDescription);
-  return result;
+  return found;
 }
 
-/*
- at Function cdiIterator_deserialize
- at Title Recreate an iterator from its textual description
 
- at Prototype CdiIterator* cdiIterator_deserialize(const char* description)
- at Parameter
-    @item description The result of a call to cdiIterator_serialize().
+void iegCopyMeta(void *dieg, void *sieg)
+{
+  iegrec_t *diegp = (iegrec_t *) dieg;
+  iegrec_t *siegp = (iegrec_t *) sieg;
 
- at Result A clone of the original iterator.
+  /*  diegp->byteswap = siegp->byteswap; */
+  diegp->dprec    = siegp->dprec;
+  diegp->refval   = siegp->refval;
 
- at Description
-    A pair of cdiIterator_serialize() and cdiIterator_deserialize() is functionally equivalent to a call to cdiIterator_clone()
+  memcpy(diegp->ipdb, siegp->ipdb, sizeof(siegp->ipdb));
+  memcpy(diegp->igdb, siegp->igdb, sizeof(siegp->igdb));
+  memcpy(diegp->vct,  siegp->vct,  sizeof(siegp->vct));
+}
 
-    This function will reread the current field from disk, so don't expect immediate return.
-*/
-//This only checks the type of the iterator and calls the corresponding subclass function,
-//the real deserialization is done in baseIter_constructFromString().
-CdiIterator* cdiIterator_deserialize(const char* description)
+static
+int iegInqData(void *ieg, int prec, void *data)
 {
-  switch(string2FileType(description, NULL))
+  iegrec_t *iegp = (iegrec_t *) ieg;
+  int ierr = 0;
+  int byteswap = iegp->byteswap;
+  size_t datasize = iegp->datasize;
+  void *buffer = iegp->buffer;
+  int dprec = iegp->dprec;
+
+  switch ( dprec )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
-#endif
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( sizeof(FLT32) == 4 )
+	  {
+	    if ( byteswap ) swap4byte(buffer, datasize);
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_getSuper(cdiFallbackIterator_deserialize(description));
+	    if ( dprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT32));
+	    else
+              {
+                const float *restrict p = (float *)buffer;
+                double *restrict q = (double *)data;
+                for ( size_t i = 0; i < datasize; i++)
+                  q[i] = p[i];
+              }
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT32));
+	  }
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+	if ( sizeof(FLT64) == 8 )
+	  {
+	    if ( byteswap ) swap8byte(buffer, datasize);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+	    if ( dprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT64));
+	    else
+              {
+                const double *restrict p = (double *)buffer;
+                float *restrict q = (float *)data;
+                for ( size_t i = 0; i < datasize; i++)
+                  q[i] = (float)p[i];
+              }
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT64));
+	  }
+	break;
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
     }
+
+  return ierr;
 }
 
 
-/*
- at Function cdiIterator_print
- at Title Print a textual description of the iterator to a stream
+int iegInqDataSP(void *ieg, float *data)
+{
+  return iegInqData(ieg, EXSE_SINGLE_PRECISION, (void *) data);
+}
 
- at Prototype void cdiIterator_print(CdiIterator* iterator, FILE* stream);
- at Parameter
-    @item iterator The iterator to print.
-    @item stream The stream to print to.
 
- at Description
-    Use for debugging output.
-*/
-void cdiIterator_print(CdiIterator* me, FILE* stream)
+int iegInqDataDP(void *ieg, double *data)
 {
-  char* description = cdiIterator_serialize(me);
-  fprintf(stream, "%s\n", description);
-  Free(description);
+  return iegInqData(ieg, EXSE_DOUBLE_PRECISION, (void *) data);
 }
 
 
-/*
- at Function cdiIterator_nextField
- at Title Advance an iterator to the next field in the file
+static int
+iegDefData(iegrec_t *iegp, int prec, const void *data)
+{
+  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
 
- at Prototype int cdiIterator_nextField(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  iegp->dprec = dprec = dprec ? dprec : prec;
 
- at Result An error code. May be one of:
-  * CDI_NOERR: The iterator has successfully been advanced to the next field.
-  * CDI_EEOF: No more fields to read in this file.
+  size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
+  size_t blocklen = datasize * (size_t)dprec;
 
- at Description
-    One call to cdiIterator_nextField() is required before the metadata of the first field can be examined.
-    Usually, it will be used directly as the condition for a while() loop.
-*/
-int cdiIterator_nextField(CdiIterator* me)
-{
-  if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
-  me->isAdvanced = true;
-  switch(me->filetype)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_nextField(me);
-#endif
+  iegp->datasize = datasize;
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_nextField(me);
+  size_t buffersize = iegp->buffersize;
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_EINVAL;
+  void *buffer = iegp->buffer;
+  if ( buffersize != blocklen )
+    {
+      buffersize = blocklen;
+      buffer = Realloc(buffer, buffersize);
+      iegp->buffer = buffer;
+      iegp->buffersize = buffersize;
     }
-}
 
-static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  switch ( dprec )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_inqTime(me, timeType);
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_inqTime(me, timeType);
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( dprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT32));
+	else
+          {
+            const double *restrict p = (const double *)data;
+            float *restrict q = (float *)buffer;
+            for (size_t i = 0; i < datasize; i++)
+              q[i] = (float)p[i];
+          }
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	if ( dprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT64));
+	else
+          {
+            const float *restrict p = (const float *)data;
+            double *restrict q = (double *)buffer;
+            for ( size_t i = 0; i < datasize; i++)
+              q[i] = p[i];
+          }
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
     }
-}
-
-/*
- at Function cdiIterator_inqStartTime
- at Title Get the start time of a measurement
-
- at Prototype char* cdiIterator_inqStartTime(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
-
- at Result A malloc'ed string containing the (start) time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
 
- at Description
-The returned time is either the time of the data (fields defined at a time point),
-or the start time of an integration time range (statistical fields).
+  return 0;
+}
 
-Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
-The caller is responsible to Free() the resulting string.
 
-If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
-as it is implemented by the standard C mktime() function.
-This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
-*/
-char* cdiIterator_inqStartTime(CdiIterator* me)
+int iegDefDataSP(void *ieg, const float *data)
 {
-  return cdiIterator_inqTime(me, kCdiTimeType_startTime);
+  return iegDefData((iegrec_t *)ieg, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
-/*
- at Function cdiIterator_inqEndTime
- at Title Get the end time of a measurement
-
- at Prototype char* cdiIterator_inqEndTime(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
-
- at Result A malloc'ed string containing the end time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm", or NULL if no such time is defined.
 
- at Description
-The returned time is the end time of an integration period if such a time exists (statistical fields).
-Otherwise, NULL is returned.
+int iegDefDataDP(void *ieg, const double *data)
+{
+  return iegDefData((iegrec_t *)ieg, EXSE_DOUBLE_PRECISION, (void *) data);
+}
 
-Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
-The caller is responsible to Free() the resulting string.
 
-If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
-as it is implemented by the standard C mktime() function.
-This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
-*/
-char* cdiIterator_inqEndTime(CdiIterator* me)
+int iegRead(int fileID, void *ieg)
 {
-  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
-}
+  iegrec_t *iegp = (iegrec_t *) ieg;
+  union { double d[200]; float f[200]; int32_t i32[200]; } buf;
 
-/*
- at Function cdiIterator_inqRTime
- at Title Get the validity time of the current field
+  if ( ! iegp->checked )
+    {
+      int status = iegCheckFiletype(fileID, &iegp->byteswap);
+      if ( status == 0 ) Error("Not a IEG file!");
+      iegp->checked = 1;
+    }
 
- at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
+  int byteswap = iegp->byteswap;
 
- at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
+  /* read header record */
+  size_t blocklen = binReadF77Block(fileID, byteswap);
 
- at Description
-The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
-That is, if the field is a time point, its time is returned,
-if it is a statistical field with an integration period, the end time of the integration period is returned.
+  if ( fileEOF(fileID) ) return -1;
 
-Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
-The caller is responsible to Free() the resulting string.
+  if ( IEG_Debug )
+    Message("blocklen = %lu", blocklen);
 
-If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
-as it is implemented by the standard C mktime() function.
-This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
-*/
-char* cdiIterator_inqRTime(CdiIterator* me)
-{
-  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
-}
+  int dprec = 0;
+  if ( blocklen == 636 || blocklen == 640 )
+    dprec = 4;
+  else if ( blocklen == 1040 || blocklen == 1036 )
+    dprec = 8;
+  else
+    {
+      Warning("unexpecteted header size %d!", (int) blocklen);
+      return -1;
+    }
 
-/*
- at Function cdiIterator_inqVTime
- at Title Get the validity time of the current field
+  iegp->dprec = dprec;
 
- at Prototype char* cdiIterator_inqVTime(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
+  binReadInt32(fileID, byteswap, 37, buf.i32);
+  for ( size_t i = 0; i < 37; i++ ) iegp->ipdb[i] = (int)buf.i32[i];
 
- at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
+  binReadInt32(fileID, byteswap, 18, buf.i32);
+  for ( size_t i = 0; i < 18; i++ ) iegp->igdb[i] = (int)buf.i32[i];
 
- at Description
-The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
-That is, if the field is a time point, its time is returned,
-if it is a statistical field with an integration period, the end time of the integration period is returned.
+  if ( blocklen == 636 || blocklen == 1036 )
+    {
+      fileRead(fileID, buf.f, 4);
+      if ( byteswap ) swap4byte(buf.f, 1);
+      iegp->refval = (double)buf.f[0];
+    }
+  else
+    {
+      fileRead(fileID, buf.d, 8);
+      if ( byteswap ) swap8byte(buf.d, 1);
+      iegp->refval = (double)buf.d[0];
+    }
 
-Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
-The caller is responsible to Free() the resulting string.
+  binReadInt32(fileID, byteswap, 3, buf.i32);
+  for ( size_t i = 0; i < 3; i++ ) iegp->igdb[18+i] = (int)buf.i32[i];
 
-If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
-as it is implemented by the standard C mktime() function.
-This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
-*/
-char* cdiIterator_inqVTime(CdiIterator* me)
-{
-  char* result = cdiIterator_inqEndTime(me);
-  return (result) ? result : cdiIterator_inqStartTime(me);
-}
+  if ( dprec == EXSE_SINGLE_PRECISION )
+    {
+      fileRead(fileID, buf.f, 400);
+      if ( byteswap ) swap4byte(buf.f, 100);
+      for ( size_t i = 0; i < 100; i++ )
+	iegp->vct[i] = (double)buf.f[i];
+    }
+  else
+    {
+      fileRead(fileID, buf.d, 800);
+      if ( byteswap ) swap8byte(buf.d, 100);
+      for ( size_t i = 0; i < 100; i++ )
+	iegp->vct[i] = buf.d[i];
+    }
 
-/*
- at Function cdiIterator_inqLevelType
- at Title Get the type of a level
+  /*
+  fprintf(stderr, "refval %g\n", iegp->refval);
 
- at Prototype int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName = NULL, char **outLongName = NULL, char **outStdName = NULL, char **outUnit = NULL)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item levelSelector Zero for the top level, one for the bottom level
-    @item outName Will be set to a Malloc()'ed string with the name of the level if not NULL.
-    @item outLongName Will be set to a Malloc()'ed string with the long name of the level if not NULL.
-    @item outStdName Will be set to a Malloc()'ed string with the standard name of the level if not NULL.
-    @item outUnit Will be set to a Malloc()'ed string with the unit of the level if not NULL.
+  for ( size_t i = 0; i < 100; i++ )
+    fprintf(stderr, "%3d %g\n", i, iegp->vct[i]);
 
- at Result An integer indicating the type of the level.
+  {
+    int i;
+    for ( size_t i = 0; i < 37; i++ )
+      fprintf(stderr, "pdb: %d %d\n", i, iegp->ipdb[i]);
+    for ( size_t i = 0; i < 22; i++ )
+      fprintf(stderr, "gdb: %d %d\n", i, iegp->igdb[i]);
+  }
+  */
+  size_t blocklen2 = binReadF77Block(fileID, byteswap);
 
- at Description
-Find out some basic information about the given level, the levelSelector selects the function of the requested level.
-If the requested level does not exist, this returns CDI_UNDEFID.
-*/
-int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  if ( blocklen2 != blocklen )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
-#endif
+      Warning("header blocklen differ!");
+      return -1;
+    }
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
+  size_t datasize = iegp->datasize
+    = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_UNDEFID;
-    }
-}
+  if ( IEG_Debug )
+    Message("datasize = %lu", iegp->datasize);
 
-/*
- at Function cdiIterator_inqLevel
- at Title Get the value of the z-coordinate
+  blocklen = binReadF77Block(fileID, byteswap);
 
- at Prototype void cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2 = NULL)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item levelSelector Zero for the top level, one for the bottom level
-    @item outValue1 For "normal" levels this returns the value, for hybrid levels the first coordinate, for generalized levels the level number.
-    @item outValue2 Zero for "normal" levels, for hybrid levels, this returns the second coordinate, for generalized levels the level count.
 
- at Result An error code.
+  void *buffer = iegp->buffer;
+  if ( iegp->buffersize < blocklen )
+    {
+      iegp->buffer = buffer = Realloc(buffer, blocklen);
+      iegp->buffersize = blocklen;
+    }
 
- at Description
-Returns the value of the z-coordinate, whatever that may be.
-*/
-int cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  if ( dprec != (int) (blocklen/datasize) )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
-#endif
+      Warning("data precision differ! (h = %d; d = %d)",
+	      (int) dprec, (int) (blocklen/datasize));
+      return -1;
+    }
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_level(me, levelSelector, outValue1, outValue2);
+  fileRead(fileID, buffer, blocklen);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_EINVAL;
-    }
-}
+  blocklen2 = binReadF77Block(fileID, byteswap);
 
-/*
- at Function cdiIterator_inqLevelUuid
- at Title Get the UUID of the z-axis used by this field
+  if ( blocklen2 != blocklen )
+    {
+      Warning("data blocklen differ!");
+      return -1;
+    }
 
- at Prototype int cdiIterator_inqLevelUuid(CdiIterator* me, int levelSelector, unsigned char (*outUuid)[16])
- at Parameter
-    @item iterator The iterator to operate on.
-    @item outVgridNumber The number of the associated vertical grid description.
-    @item outLevelCount The number of levels in the associated vertical grid description.
-    @item outUuid A pointer to a user supplied buffer of 16 bytes to store the UUID in.
+  return 0;
+}
 
- at Result An error code.
 
- at Description
-Returns identifying information for the external z-axis description. May only be called for generalized levels.
-*/
-int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
+int iegWrite(int fileID, void *ieg)
 {
-  sanityCheck(me);
-  switch(me->filetype)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
-#endif
+  iegrec_t *iegp = (iegrec_t *) ieg;
+  union { INT32 i32[200]; float fvct[100]; } buf;
+  int dprec  = iegp->dprec;
+  int byteswap = iegp->byteswap;
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+  /* write header record */
+  size_t blocklen = ( dprec == EXSE_SINGLE_PRECISION ) ? 636 : 1040;
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
-    }
-}
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-/*
- at Function cdiIterator_inqTile
- at Title Inquire the tile information for the current field
+  for ( size_t i = 0; i < 37; i++ ) buf.i32[i] = (INT32) iegp->ipdb[i];
+  binWriteInt32(fileID, byteswap, 37, buf.i32);
 
- at Prototype int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item outTileIndex The index of the current tile, -1 if no tile information is available.
-    @item outTileAttribute The attribute of the current tile, -1 if no tile information is available.
+  for ( size_t i = 0; i < 18; i++ ) buf.i32[i] = (INT32) iegp->igdb[i];
+  binWriteInt32(fileID, byteswap, 18, buf.i32);
 
- at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+  FLT64 refval = (FLT64)iegp->refval;
+  FLT32 refvalf = (FLT32)iegp->refval;
+  if ( dprec == EXSE_SINGLE_PRECISION )
+    binWriteFlt32(fileID, byteswap, 1, &refvalf);
+  else
+    binWriteFlt64(fileID, byteswap, 1, &refval);
 
- at Description
-Inquire the tile index and attribute for the current field.
-*/
-int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  for ( size_t i = 0; i < 3; i++ ) buf.i32[i] = (INT32) iegp->igdb[18+i];
+  binWriteInt32(fileID, byteswap, 3, buf.i32);
+
+  if ( dprec == EXSE_SINGLE_PRECISION )
     {
-      #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
-      #endif
+      for ( size_t i = 0; i < 100; i++ ) buf.fvct[i] = (float) iegp->vct[i];
+      binWriteFlt32(fileID, byteswap, 100, buf.fvct);
+    }
+  else
+    {
+      binWriteFlt64(fileID, byteswap, 100, iegp->vct);
+    }
 
-      #ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-      #endif
-      #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-      #endif
-      #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-      #endif
-      #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-      #endif
-          return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
-    }
-}
+  size_t datasize = (size_t)iegp->igdb[4] * (size_t)iegp->igdb[5];
+  blocklen = datasize * (size_t)dprec;
 
-/**
- at Function cdiIterator_inqTileCount
- at Title Inquire the tile count and tile attribute counts for the current field
+  binWriteF77Block(fileID, byteswap, blocklen);
 
- at Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item outTileCount The number of tiles used for this variable, zero if no tile information is available.
-    @item outTileAttributeCount The number of attributes available for the tile of this field, zero if no tile information is available.
-          Note: This is not the global attribute count, which would be impossible to infer without reading the entire file if it's a GRIB file.
+  iegp->datasize = datasize;
 
- at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+  void *buffer = iegp->buffer;
 
- at Description
-Inquire the tile count and tile attribute counts for the current field.
-*/
-int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  switch ( dprec )
     {
-      #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
-      #endif
+    case EXSE_SINGLE_PRECISION:
+      {
+	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
+    }
 
-      #ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-      #endif
-      #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-      #endif
-      #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-      #endif
-      #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-      #endif
-          return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
-    }
+  return 0;
 }
-
 /*
- at Function cdiIterator_inqParam
- at Title Get discipline, category, and number
-
- at Prototype CdiParam cdiIterator_inqParam(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef INCLUDE_GUARD_CDI_REFERENCE_COUNTING
+#define INCLUDE_GUARD_CDI_REFERENCE_COUNTING
 
- at Result A struct containing the requested information.
 
- at Description
-    Simple metadata inspection function.
-*/
-CdiParam cdiIterator_inqParam(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->param;
-}
+#include <sys/types.h>
+#include <stdlib.h>
 
 /*
- at Function cdiIterator_inqParamParts
- at Title Get discipline, category, and number
-
- at Prototype void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item outDiscipline This is used to return the discipline.
-    @item outCategory This is used to return the category.
-    @item outNumber This is used to return the number.
+This is a base class for all objects that need reference counting.
+A CdiReferencedObject has a reference count of one when it is constructed, refObjectRetain() increments the reference count, refObject Release() decrements it.
+When the reference count reaches zero, the destructor function is called before the memory of the object is deallocated with Free().
 
- at Description
-    Simple metadata inspection function.
+>>> Warning <<<
+This code is currently not thread-safe.
 
-    Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
-    rendering it unusable from FORTRAN. This function is the workaround.
+We are currently using the C99 standard, which does not have atomic types.
+Also, there are still tons of systems out there that have a gcc without wrong C11 atomics support
+(__STDC_NO_ATOMICS__ not defined even though stdatomics.h is not even present).
+Consequently, it is impossible to write preprocessor code to even check for the presence of atomic types.
+So, we have two options: provide multithreading support by means of locks, or wait a year or two before doing this right.
+I, for one, prefer doing things right.
 */
-void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
-{
-  CdiParam result = cdiIterator_inqParam(me);
-  if(outDiscipline) *outDiscipline = result.discipline;
-  if(outCategory) *outCategory = result.category;
-  if(outNumber) *outNumber = result.number;
-}
+typedef struct CdiReferencedObject CdiReferencedObject;
+struct CdiReferencedObject {
+  //protected:
+    void (*destructor)(CdiReferencedObject* me);  //Subclass constructors should set this to their own destructor.
 
-/*
- at Function cdiIterator_inqDatatype
- at Title Get the datatype of the current field
+  //private:    //Subclasses may read it to determine whether there is only one reference, though.
+    size_t refCount;
+};
 
- at Prototype int cdiIterator_inqDatatype(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+void cdiRefObject_construct(CdiReferencedObject* me);
+void cdiRefObject_retain(CdiReferencedObject* me);
+void cdiRefObject_release(CdiReferencedObject* me);
+void cdiRefObject_destruct(CdiReferencedObject* me);
 
- at Result The datatype that is used to store this field on disk.
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef INCLUDE_GUARD_CDI_GRIB_FILE_H
+#define INCLUDE_GUARD_CDI_GRIB_FILE_H
 
- at Description
-    Simple metadata inspection function.
-*/
-int cdiIterator_inqDatatype(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->datatype;
-}
 
 /*
- at Function cdiIterator_inqTsteptype
- at Title Get the timestep type
+CdiInputFile is a file abstraction that allows accessing an input file through any number of channels:
+It is reference counted, so that it is closed at the right place,
+and it is stateless, so that accesses from different callers cannot interfere with each other.
+Once the reference counting code is threadsafe, CdiInputFile will also be threadsafe.
+*/
+typedef struct CdiInputFile {
+  //public:
+    CdiReferencedObject super;
 
- at Prototype int cdiIterator_inqTsteptype(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  //private:
+    char* path;
+    int fileDescriptor;
+} CdiInputFile;
 
- at Result The timestep type.
+//Final class, the constructor is private and not defined here.
+CdiInputFile* cdiInputFile_make(const char* path);   //The caller is responsible to call cdiRefObject_release() on the returned object.
+int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer);       //Returns one of CDI_EINVAL, CDI_ESYSTEM, CDI_EEOF, OR CDI_NOERR.
+/* Returns path string, don't use after destruction of CdiInputFile
+ * object */
+const char* cdiInputFile_getPath(const CdiInputFile* me);
+//Destructor is private as well.
 
- at Description
-    Simple metadata inspection function.
-*/
-int cdiIterator_inqTsteptype(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->timesteptype;
-}
+#endif
 
 /*
- at Function cdiIterator_inqVariableName
- at Title Get the variable name of the current field
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#define _XOPEN_SOURCE 600
 
- at Prototype char* cdiIterator_inqVariableName(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
 
- at Result A pointer to a C-string containing the name. The storage for this string is allocated with Malloc(), and it is the responsibility of the caller to Free() it.
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
 
- at Description
-    Allocates a buffer to hold the string, copies the current variable name into this buffer, and returns the buffer.
-    The caller is responsible to make the corresponding Free() call.
-*/
-char* cdiIterator_inqVariableName(CdiIterator* me)
+static void cdiInputFile_destruct(CdiInputFile* me);
+
+//For an explanation of the condestruct() pattern, see the comment in iterator_grib.c
+//path != NULL -> construction
+//path = NULL -> destruction
+static CdiInputFile* cdiInputFile_condestruct(CdiInputFile* me, const char* path)
 {
-  sanityCheck(me);
-  switch(me->filetype)
+  #define super() (&me->super)
+  if(!path) goto destruct;
+  cdiRefObject_construct(super());
+  me->path = strdup(path);
+  if(!me->path) goto destructSuper;
+  do
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_copyVariableName(me);
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          return cdiFallbackIterator_copyVariableName(me);
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+      me->fileDescriptor = open(me->path, O_RDONLY);
     }
-}
-
-/*
- at Function cdiIterator_inqGridId
- at Title Get the ID of the current grid
+  while(me->fileDescriptor == -1 && (errno == EINTR || errno == EAGAIN));
+  if(me->fileDescriptor == -1) goto freePath;
+  //construction successfull, now we can set our own destructor
+  super()->destructor = (void(*)(CdiReferencedObject*))cdiInputFile_destruct;
+  goto success;
 
- at Prototype int cdiIterator_inqGridId(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+// ^        constructor code       ^
+// |                               |
+// v destructor/error-cleanup code v
 
- at Result A gridId that can be used for further introspection.
+destruct:
+  close(me->fileDescriptor);
+freePath:
+  Free(me->path);
+destructSuper:
+  cdiRefObject_destruct(super());
+  me = NULL;
 
- at Description
-    This provides access to the grid related metadata.
-    The resulting ID is only valid until the next time cdiIterator_nextField() is called.
-*/
-int cdiIterator_inqGridId(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->gridId;
+success:
+  return me;
+  #undef super
 }
 
-/*
- at Function cdiIterator_readField
- at Title Read the whole field into a double buffer
-
- at Prototype void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item buffer A pointer to the double array that the data should be written to.
-    @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
+static CdiInputFile **openFileList = NULL;
+static size_t openFileCount = 0, openFileListSize = 0;
+static pthread_mutex_t openFileListLock = PTHREAD_MUTEX_INITIALIZER;
 
- at Description
-    It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
-    Failing to do so results in undefined behavior. You have been warned.
-*/
-void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
+//This either returns a new object, or retains and returns a preexisting open file.
+CdiInputFile* cdiInputFile_make(const char* path)
 {
-  sanityCheck(me);
-  if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
-  switch(me->filetype)
+  CdiInputFile* result = NULL;
+  xassert(path);
+  int error = pthread_mutex_lock(&openFileListLock);
+  xassert(!error);
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          cdiGribIterator_readField(me, buffer, nmiss);
-	  return;
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          cdiFallbackIterator_readField(me, buffer, nmiss);
-          return;
-      default:
-        Error(kUnexpectedFileTypeMessage);
+      //Check the list of open files for the given path.
+      for(size_t i = openFileCount; i-- && !result; )
+        {
+          if(!strcmp(path, openFileList[i]->path)) result = openFileList[i];
+        }
+      //If no open file was found, we open one, otherwise we just retain the existing one one more time.
+      if(result)
+        {
+          cdiRefObject_retain(&result->super);
+        }
+      else
+        {
+          result = (CdiInputFile *) Malloc(sizeof(*result));
+          if(!cdiInputFile_condestruct(result, path))
+            {
+              //An error occured during construction, avoid a memory leak.
+              Free(result);
+              result = NULL;
+            }
+          else
+            {
+              //Add the new file to the list of open files.
+              if(openFileCount == openFileListSize)
+                {
+                  openFileListSize *= 2;
+                  if(openFileListSize < 16) openFileListSize = 16;
+                  openFileList = (CdiInputFile **) Realloc(openFileList, openFileListSize);
+                }
+              xassert(openFileCount < openFileListSize);
+              openFileList[openFileCount++] = result;
+            }
+        }
     }
+  error = pthread_mutex_unlock(&openFileListLock);
+  xassert(!error);
+  return result;
 }
 
-/*
- at Function cdiIterator_readFieldF
- at Title Read the whole field into a double buffer
+int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer)
+{
+  char* byteBuffer = (char *)buffer;
+  size_t trash;
+  if(!outActualReadSize) outActualReadSize = &trash;
+  *outActualReadSize = 0;
+  while(readSize)
+    {
+      ssize_t bytesRead = pread(me->fileDescriptor, byteBuffer, readSize, readPosition);
+      if(bytesRead == -1) return (errno == EINVAL) ?  CDI_EINVAL : CDI_ESYSTEM;
+      if(bytesRead == 0) return CDI_EEOF;
+      byteBuffer += bytesRead;
+      readPosition += bytesRead;
+      readSize -= (size_t)bytesRead;
+      *outActualReadSize += (size_t)bytesRead;
+    }
+  return CDI_NOERR;
+}
 
- at Prototype void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
- at Parameter
-    @item iterator The iterator to operate on.
-    @item buffer A pointer to the double array that the data should be written to.
-    @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
+const char* cdiInputFile_getPath(const CdiInputFile* me)
+{
+  return me->path;
+}
 
- at Description
-    It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
-    Failing to do so results in undefined behavior. You have been warned.
-*/
-void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
+void cdiInputFile_destruct(CdiInputFile* me)
 {
-  sanityCheck(me);
-  if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
-  switch(me->filetype)
+  int error = pthread_mutex_lock(&openFileListLock);
+  xassert(!error);
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          cdiGribIterator_readFieldF(me, buffer, nmiss);
-	  return;
-#endif
-
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
-#endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          cdiFallbackIterator_readFieldF(me, buffer, nmiss);
-          return; 
-      default:
-        Error(kUnexpectedFileTypeMessage);
+      //Find the position of me in the list of open files.
+      ssize_t position = (ssize_t)openFileCount;
+      while (position > 0 && openFileList[--position] != me);
+      //Remove me from the list
+      openFileList[position] = openFileList[--openFileCount];
     }
+  error = pthread_mutex_unlock(&openFileListLock);
+  xassert(!error);
+  cdiInputFile_condestruct(me, NULL);
 }
 
 /*
- at Function cdiIterator_delete
- at Title Destroy an iterator
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef INSTITUTION_H
+#define INSTITUTION_H
 
- at Prototype void cdiIterator_delete(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+int
+instituteUnpack(void *buf, int size, int *position, int originNamespace,
+                void *context, int force_id);
 
- at Description
-    Combined destructor & deallocator.
-*/
-void cdiIterator_delete(CdiIterator* me)
-{
-  if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
-  switch(me->filetype)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          cdiGribIterator_delete((CdiGribIterator*)me);
-          break;
-#endif
+void instituteDefaultEntries(void);
 
-#ifdef HAVE_LIBNETCDF
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
-#endif
-#ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
 #endif
-#ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
-#endif
-#ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
-#endif
-          cdiFallbackIterator_delete(me);
-          break;
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
-    }
-}
-
-void baseIterDestruct(CdiIterator* me)
-{
-  /*currently empty, but that's no reason not to call it*/
-  (void)me;
-}
 
 /*
  * Local Variables:
@@ -31522,394 +30411,341 @@ void baseIterDestruct(CdiIterator* me)
  * require-trailing-newline: t
  * End:
  */
-
+#if defined (HAVE_CONFIG_H)
+#endif
 
 #include <assert.h>
 #include <limits.h>
-#include <stdlib.h>
-
-struct CdiFallbackIterator {
-  CdiIterator super;
-  int streamId, vlistId, subtypeId;
-  char *path;   //needed for clone() & serialize()
 
-  int variableCount, curVariable;
-  int curLevelCount, curLevel;
-  int curSubtypeCount, curSubtype;
-  int curTimestep;
-};
 
-CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me)
-{
-  return &me->super;
-}
 
+static int ECMWF  = CDI_UNDEFID,
+  MPIMET = CDI_UNDEFID,
+  MCH    = CDI_UNDEFID;
 
-//For more information on the condestruct() pattern, see comment in src/iterator_grib.c
-static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator *me, const char *path, int filetype)
+typedef struct
 {
-  if(me) goto destruct;
-
-  me = (CdiFallbackIterator *) Malloc(sizeof(*me));
-  baseIterConstruct(&me->super, filetype);
-
-  me->streamId = streamOpenRead(path);
-  if(me->streamId == CDI_UNDEFID) goto destructSuper;
-  me->vlistId = streamInqVlist(me->streamId);
-  if(me->vlistId == CDI_UNDEFID) goto closeStream;
-  me->variableCount = vlistNvars(me->vlistId);
-  if(me->variableCount <= 0) goto closeStream;
-  me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
-  me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
-  me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()
-
-  //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
-  me->curTimestep = 0;
-  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  me->curVariable = -1;
-  me->curSubtype = -1;
-  me->curLevel = -1;
-  me->path = strdup(path);
-  if(!me->path) goto closeStream;
+  int    self;
+  int    used;
+  int    center;
+  int    subcenter;
+  char  *name;
+  char  *longname;
+}
+institute_t;
 
-  return me;
 
-// ^        constructor code        ^
-// |                                |
-// v destructor/error-cleanup code  v
+static int instituteCompareKernel(institute_t *ip1, institute_t *ip2);
+static void instituteDestroyP(institute_t *instituteptr);
+static void   institutePrintP(institute_t *instituteptr, FILE * fp);
+static int instituteGetPackSize(institute_t *instituteptr, void *context);
+static void   institutePackP    ( void * instituteptr, void *buf, int size, int *position, void *context );
+static int    instituteTxCode   ( void );
 
-destruct:
-  Free(me->path);
-closeStream:
-  streamClose(me->streamId);
-destructSuper:
-  baseIterDestruct(&me->super);
-  Free(me);
-  return NULL;
-}
+static const resOps instituteOps = {
+  (int (*)(void *, void *))instituteCompareKernel,
+  (void (*)(void *))instituteDestroyP,
+  (void (*)(void *, FILE *))institutePrintP,
+  (int (*)(void *, void *))instituteGetPackSize,
+  institutePackP,
+  instituteTxCode
+};
 
-CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
+static
+void instituteDefaultValue ( institute_t * instituteptr )
 {
-  return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
+  instituteptr->self       = CDI_UNDEFID;
+  instituteptr->used       = 0;
+  instituteptr->center     = CDI_UNDEFID;
+  instituteptr->subcenter  = CDI_UNDEFID;
+  instituteptr->name       = NULL;
+  instituteptr->longname   = NULL;
 }
 
-//Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
-static void fetchVariableInfo(CdiFallbackIterator *me)
+void instituteDefaultEntries ( void )
 {
-  //Fetch data that's published via base class data members.
-  me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
-  me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
-  me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
-  int param = vlistInqVarParam(me->vlistId, me->curVariable);
-  cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
-
-  //Fetch the current level and subtype counts.
-  me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
-  me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
-  me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
-}
+  cdiResH resH[]
+    = { ECMWF   = institutDef( 98,   0, "ECMWF",     "European Centre for Medium-Range Weather Forecasts"),
+        MPIMET  = institutDef( 98, 232, "MPIMET",    "Max-Planck-Institute for Meteorology"),
+        institutDef( 98, 255, "MPIMET",    "Max-Planck-Institute for Meteorology"),
+        institutDef( 98, 232, "MPIMET",    "Max Planck Institute for Meteorology"),
+        institutDef( 78,   0, "DWD",       "Deutscher Wetterdienst"),
+        institutDef( 78, 255, "DWD",       "Deutscher Wetterdienst"),
+        MCH     = institutDef(215, 255, "MCH",       "MeteoSwiss"),
+        institutDef(  7,   0, "NCEP",      "National Centers for Environmental Prediction"),
+        institutDef(  7,   1, "NCEP",      "National Centers for Environmental Prediction"),
+        institutDef( 60,   0, "NCAR",      "National Center for Atmospheric Research"),
+        institutDef( 74,   0, "METOFFICE", "U.K. Met Office"),
+        institutDef( 97,   0, "ESA",       "European Space Agency"),
+        institutDef( 99,   0, "KNMI",      "Royal Netherlands Meteorological Institute"),
+  };
+  /*     (void) institutDef(  0,   0, "IPSL", "IPSL (Institut Pierre Simon Laplace, Paris, France)"); */
 
-CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  size_t n = sizeof(resH)/sizeof(*resH);
 
-  //Make another stream for this file. This yields an unadvanced iterator.
-  CdiFallbackIterator *clone = cdiFallbackIterator_condestruct(NULL, me->path, me->super.filetype);
-  if(!clone) return NULL;
+  for (size_t i = 0; i < n ; i++ )
+    reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
+}
 
-  //Point the clone to the same position in the file.
-  clone->variableCount = me->variableCount;
-  clone->curVariable = me->curVariable;
-  clone->curLevelCount = me->curLevelCount;
-  clone->curLevel = me->curLevel;
-  clone->curSubtypeCount = me->curSubtypeCount;
-  clone->curSubtype = me->curSubtype;
-  clone->curTimestep = me->curTimestep;
 
-  clone->super.isAdvanced = super->isAdvanced;
-  if(super->isAdvanced) fetchVariableInfo(clone);
+static int
+instituteCompareKernel(institute_t *  ip1, institute_t * ip2)
+{
+  int differ = 0;
+  size_t len1, len2;
 
-  return clone;
-}
+  if ( ip1->name )
+    {
+      if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
+      if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
 
-char *cdiFallbackIterator_serialize(CdiIterator *super)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+      if ( !differ )
+        {
+          if ( ip2->name )
+            {
+              len1 = strlen(ip1->name);
+              len2 = strlen(ip2->name);
+              if ( (len1 != len2) || memcmp(ip2->name, ip1->name, len2) ) differ = 1;
+            }
+        }
+    }
+  else if ( ip1->longname )
+    {
+      if ( ip2->longname )
+        {
+          len1 = strlen(ip1->longname);
+          len2 = strlen(ip2->longname);
+          if ( (len1 < len2) || memcmp(ip2->longname, ip1->longname, len2) ) differ = 1;
+        }
+    }
+  else
+    {
+      if ( !( ip2->center    == ip1->center &&
+              ip2->subcenter == ip1->subcenter )) differ = 1;
+    }
 
-  char *escapedPath = cdiEscapeSpaces(me->path);
-  char *result = (char *) Malloc(strlen(escapedPath)
-                         + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
-  sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
-  Free(escapedPath);
-  return result;
+  return differ;
 }
 
-CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
-  if(!me) goto fail;
 
-  description = baseIter_constructFromString(&me->super, description);
+struct instLoc
+{
+  institute_t *ip;
+  int id;
+};
 
-  while(*description == ' ') description++;
-  me->path = cdiUnescapeSpaces(description, &description);
-  if(!me->path) goto destructSuper;
+static enum cdiApplyRet
+findInstitute(int id, void *res, void *data)
+{
+  institute_t * ip1 = ((struct instLoc *)data)->ip;
+  institute_t * ip2 = (institute_t*) res;
+  if (ip2->used && !instituteCompareKernel(ip1, ip2))
+    {
+      ((struct instLoc *)data)->id = id;
+      return CDI_APPLY_STOP;
+    }
+  else
+    return CDI_APPLY_GO_ON;
+}
 
-  me->streamId = streamOpenRead(me->path);
-  if(me->streamId == CDI_UNDEFID) goto freePath;
-  me->vlistId = streamInqVlist(me->streamId);
-  if(me->vlistId == CDI_UNDEFID) goto closeStream;
 
-  //This reads one variable from the description string, does error checking, and advances the given string pointer.
-#define decodeValue(variable, description) do \
-    { \
-      const char *savedStart = description; \
-      long long decodedValue = strtoll(description, (char**)&description, 0);   /*The cast is a workaround for the wrong signature of strtoll().*/ \
-      variable = (int)decodedValue; \
-      if(savedStart == description) goto closeStream; \
-      if((long long)decodedValue != (long long)variable) goto closeStream; \
-    } while(0)
-  decodeValue(me->variableCount, description);
-  decodeValue(me->curVariable, description);
-  decodeValue(me->curLevelCount, description);
-  decodeValue(me->curLevel, description);
-  decodeValue(me->curSubtypeCount, description);
-  decodeValue(me->curSubtype, description);
-  decodeValue(me->curTimestep, description);
-#undef decodeValue
+int institutInq(int center, int subcenter, const char *name, const char *longname)
+{
+  institute_t * ip_ref = (institute_t *) Malloc(sizeof (*ip_ref));
+  ip_ref->self       = CDI_UNDEFID;
+  ip_ref->used       = 0;
+  ip_ref->center     = center;
+  ip_ref->subcenter  = subcenter;
+  ip_ref->name       = name && name[0] ? (char *)name : NULL;
+  ip_ref->longname   = longname && longname[0] ? (char *)longname : NULL;
 
-  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
-  if(me->super.isAdvanced) fetchVariableInfo(me);
+  struct instLoc state = { .ip = ip_ref, .id = CDI_UNDEFID };
+  cdiResHFilterApply(&instituteOps, findInstitute, &state);
 
-  return me;
+  Free(ip_ref);
 
-closeStream:
-  streamClose(me->streamId);
-freePath:
-  Free(me->path);
-destructSuper:
-  baseIterDestruct(&me->super);
-  Free(me);
-fail:
-  return NULL;
+  return state.id;
 }
 
-static int advance(CdiFallbackIterator *me)
+static
+institute_t *instituteNewEntry(cdiResH resH, int center, int subcenter,
+                               const char *name, const char *longname)
 {
-  me->curLevel++;
-  if(me->curLevel >= me->curLevelCount)
+  institute_t *instituteptr = (institute_t*) Malloc(sizeof(institute_t));
+  instituteDefaultValue(instituteptr);
+  if (resH == CDI_UNDEFID)
+    instituteptr->self = reshPut(instituteptr, &instituteOps);
+  else
     {
-      me->curLevel = 0;
-      me->curSubtype++;
-      if(me->curSubtype >= me->curSubtypeCount)
-        {
-          me->curSubtype = 0;
-          me->curVariable++;
-          if(me->curVariable >= me->variableCount)
-            {
-              me->curVariable = 0;
-              me->curTimestep++;
-              if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
-            }
-        }
+      instituteptr->self = resH;
+      reshReplace(resH, instituteptr, &instituteOps);
     }
-  return CDI_NOERR;
+  instituteptr->used = 1;
+  instituteptr->center = center;
+  instituteptr->subcenter = subcenter;
+  if ( name && *name )
+    instituteptr->name = strdupx(name);
+  if (longname && *longname)
+    instituteptr->longname = strdupx(longname);
+  return  instituteptr;
 }
 
-int cdiFallbackIterator_nextField(CdiIterator *super)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int result = advance(me);
-  if(result) return result;
 
-  if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
-  return CDI_NOERR;
+int institutDef(int center, int subcenter, const char *name, const char *longname)
+{
+  institute_t * instituteptr
+    = instituteNewEntry(CDI_UNDEFID, center, subcenter, name, longname);
+  return instituteptr->self;
 }
 
-char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
+
+int institutInqCenter(int instID)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
+  institute_t * instituteptr = NULL;
 
-  //retrieve the time information
-  int taxisId = vlistInqTaxis(me->vlistId);
-  int date = 0, time = 0;
-  switch(timeType)
-    {
-      case kCdiTimeType_referenceTime:
-        date = taxisInqRdate(taxisId);
-        time = taxisInqRtime(taxisId);
-        break;
+  if ( instID != CDI_UNDEFID )
+    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
-      case kCdiTimeType_startTime:
-        date = taxisInqVdate(taxisId);
-        time = taxisInqVtime(taxisId);
-        break;
+  return  instituteptr ? instituteptr->center : CDI_UNDEFID;
+}
 
-      case kCdiTimeType_endTime:
-        return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
 
-      default:
-        assert(0 && "internal error, please report this bug");
-    }
+int institutInqSubcenter(int instID)
+{
+  institute_t * instituteptr = NULL;
 
-  //decode the time information and reencode it into an ISO-compliant string
-  int year, month, day, hour, minute, second;
-  cdiDecodeDate(date, &year, &month, &day);
-  cdiDecodeTime(time, &hour, &minute, &second);
-  char *result
-    = (char *) Malloc(   4+1 +2+1 +2+1 +2+1 +2+1 +2+4+1);
-  sprintf(result,     "%04d-%02d-%02dT%02d:%02d:%02d.000", year, month, day, hour, minute, second);
-  return result;
+  if ( instID != CDI_UNDEFID )
+    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+
+  return instituteptr ? instituteptr->subcenter: CDI_UNDEFID;
 }
 
-int cdiFallbackIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
+
+const char *institutInqNamePtr(int instID)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
-  (void)levelSelector;
-#define copyString(outPointer, function) do \
-    { \
-      if(outPointer) \
-        { \
-          char tempBuffer[CDI_MAX_NAME]; \
-          function(zaxisId, tempBuffer); \
-          *outPointer = strdup(tempBuffer); \
-        } \
-    } \
-  while(0)
-  copyString(outName, zaxisInqName);    //FIXME: zaxisInqName is unsafe.
-  copyString(outLongName, zaxisInqLongname);    //FIXME: zaxisInqLongname is unsafe.
-  copyString(outStdName, zaxisInqStdname);    //FIXME: zaxisInqStdname is unsafe.
-  copyString(outUnit, zaxisInqUnits);    //FIXME: zaxisInqUnits is unsafe.
-#undef copyString
-  return zaxisInqLtype(zaxisId);
+  institute_t * instituteptr = NULL;
+
+  if ( instID != CDI_UNDEFID )
+    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+
+  return instituteptr ? instituteptr->name : NULL;
 }
 
-int cdiFallbackIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
 
-  //handle NULL pointers once and for all
-  double trash;
-  if(!outValue1) outValue1 = &trash;
-  if(!outValue2) outValue2 = &trash;
+const char *institutInqLongnamePtr(int instID)
+{
+  institute_t * instituteptr = NULL;
 
-  //get the level value
-  if(levelSelector)
-    {
-      *outValue1 = (zaxisInqLbounds(zaxisId, NULL))
-                 ? zaxisInqLbound(zaxisId, me->curLevel)
-                 : zaxisInqLevel(zaxisId, me->curLevel);
-    }
-  else
-    {
-      *outValue1 = (zaxisInqUbounds(zaxisId, NULL))
-                 ? zaxisInqUbound(zaxisId, me->curLevel)
-                 : zaxisInqLevel(zaxisId, me->curLevel);
-    }
-  *outValue2 = 0.0;
+  if ( instID != CDI_UNDEFID )
+    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
-  //if this is a hybrid zaxis, lookup the coordinates in the vertical coordinate table
-  ssize_t intLevel = (ssize_t)(2**outValue1);
-  if(0 <= intLevel && intLevel < zaxisInqVctSize(zaxisId) - 1)
-    {
-      const double *coordinateTable = zaxisInqVctPtr(zaxisId);
-      *outValue1 = coordinateTable[intLevel];
-      *outValue2 = coordinateTable[intLevel + 1];
-    }
-  return CDI_NOERR;
+  return instituteptr ? instituteptr->longname : NULL;
 }
 
-int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
+static enum cdiApplyRet
+activeInstitutes(int id, void *res, void *data)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
-  if(zaxisInqLtype(zaxisId) != ZAXIS_HYBRID) return CDI_EINVAL;
-  if(outVgridNumber) *outVgridNumber = zaxisInqNumber(zaxisId);
-  if(outLevelCount) *outLevelCount = zaxisInqNlevRef(zaxisId);
-  if(outUuid) zaxisInqUUID(zaxisId, outUuid);
-  return CDI_NOERR;
+  (void)id;
+  if (res && ((institute_t *)res)->used)
+    ++(*(int *)data);
+  return CDI_APPLY_GO_ON;
 }
 
-int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+int institutInqNumber(void)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-#ifndef __cplusplus
-  if(!outTileIndex) outTileIndex = &(int){0};
-  if(!outTileAttribute) outTileAttribute = &(int){0};
-#else
-  int dummy = 0;
-  if(!outTileIndex) outTileIndex = &dummy;
-  if(!outTileAttribute) outTileAttribute = &dummy;
-#endif
+  int instNum = 0;
 
-  int error = CDI_NOERR;
-  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
-    {
-      error = CDI_EINVAL;
-    }
-  else
-    {
-      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
-      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
-    }
-  if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
-  return error;
+  cdiResHFilterApply(&instituteOps, activeInstitutes, &instNum);
+  return instNum;
 }
 
-int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+
+static void
+instituteDestroyP(institute_t *instituteptr)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-#ifndef __cplusplus
-  if(!outTileCount) outTileCount = &(int){0};
-  if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
-#else
-  int temp = 0;
-  if(!outTileCount) outTileCount = &temp;
-  if(!outTileAttributeCount) outTileAttributeCount = &temp;
-#endif
+  xassert(instituteptr);
 
-  int error = CDI_NOERR;
-  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
-    {
-      error = CDI_EINVAL;
-    }
-  else
-    {
-      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
-      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
-    }
-  if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
-  return CDI_NOERR;
+  int instituteID = instituteptr->self;
+  Free(instituteptr->name);
+  Free(instituteptr->longname);
+  reshRemove(instituteID, &instituteOps);
+  Free(instituteptr);
 }
 
-char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
+
+static void institutePrintP(institute_t *ip, FILE * fp )
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  return vlistCopyVarName(me->vlistId, me->curVariable);
+  if (ip)
+    fprintf(fp, "#\n"
+            "# instituteID %d\n"
+            "#\n"
+            "self          = %d\n"
+            "used          = %d\n"
+            "center        = %d\n"
+            "subcenter     = %d\n"
+            "name          = %s\n"
+            "longname      = %s\n",
+            ip->self, ip->self, ip->used, ip->center, ip->subcenter,
+            ip->name ? ip->name : "NN",
+            ip->longname ? ip->longname : "NN");
 }
 
-void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
+
+static int
+instituteTxCode ( void )
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int missingValues = 0;
-  streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
-  if(nmiss) *nmiss = (size_t)missingValues;
+  return INSTITUTE;
 }
 
-void cdiFallbackIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
+enum {
+  institute_nints = 5,
+};
+
+static int instituteGetPackSize(institute_t *ip, void *context)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int missingValues = 0;
-  streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
-  if(nmiss) *nmiss = (size_t)missingValues;
+  size_t namelen = strlen(ip->name), longnamelen = strlen(ip->longname);
+  xassert(namelen < INT_MAX && longnamelen < INT_MAX);
+  size_t txsize = (size_t)serializeGetSize(institute_nints, CDI_DATATYPE_INT, context)
+    + (size_t)serializeGetSize((int)namelen + 1, CDI_DATATYPE_TXT, context)
+    + (size_t)serializeGetSize((int)longnamelen + 1, CDI_DATATYPE_TXT, context);
+  xassert(txsize <= INT_MAX);
+  return (int)txsize;
 }
 
-void cdiFallbackIterator_delete(CdiIterator *super)
+static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  cdiFallbackIterator_condestruct(me, NULL, 0);
+  institute_t *p = (institute_t*) instituteptr;
+  int tempbuf[institute_nints];
+  tempbuf[0] = p->self;
+  tempbuf[1] = p->center;
+  tempbuf[2] = p->subcenter;
+  tempbuf[3] = (int)strlen(p->name) + 1;
+  tempbuf[4] = (int)strlen(p->longname) + 1;
+  serializePack(tempbuf, institute_nints, CDI_DATATYPE_INT, buf, size, position, context);
+  serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
+  serializePack(p->longname, tempbuf[4], CDI_DATATYPE_TXT, buf, size, position, context);
+}
+
+int instituteUnpack(void *buf, int size, int *position, int originNamespace,
+                    void *context, int force_id)
+{
+  int tempbuf[institute_nints];
+  int instituteID;
+  char *name, *longname;
+  serializeUnpack(buf, size, position, tempbuf, institute_nints, CDI_DATATYPE_INT, context);
+  name = (char *) Malloc((size_t)tempbuf[3] + (size_t)tempbuf[4]);
+  longname = name + tempbuf[3];
+  serializeUnpack(buf, size, position, name, tempbuf[3], CDI_DATATYPE_TXT, context);
+  serializeUnpack(buf, size, position, longname, tempbuf[4], CDI_DATATYPE_TXT, context);
+  int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
+  institute_t *ip = instituteNewEntry(force_id?targetID:CDI_UNDEFID,
+                                      tempbuf[1], tempbuf[2], name, longname);
+  instituteID = ip->self;
+  xassert(!force_id || instituteID == targetID);
+  Free(name);
+  reshSetStatus(instituteID, &instituteOps,
+                reshGetStatus(instituteID, &instituteOps) & ~RESH_SYNC_BIT);
+  return instituteID;
 }
 
 /*
@@ -31921,33 +30757,54 @@ void cdiFallbackIterator_delete(CdiIterator *super)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _STREAM_GRB_H
-#define _STREAM_GRB_H
+/*
+ * This file is for the use of iterator.c and the CdiIterator subclasses only.
+ */
 
-int   grbBitsPerValue(int datatype);
+#ifndef INCLUDE_GUARD_CDI_ITERATOR_INT_H
+#define INCLUDE_GUARD_CDI_ITERATOR_INT_H
 
-int   grbInqContents(stream_t *streamptr);
-int   grbInqTimestep(stream_t *streamptr, int tsID);
 
-int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
-void  grbDefRecord(stream_t *streamptr);
-void  grb_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
-void  grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
-void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
+#include <stdbool.h>
+
+/*
+class CdiIterator
 
-void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
-void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
+An iterator is an object that identifies the position of one record in a file, where a record is defined as the data belonging to one level, timestep, and variable.
+Using iterators to read a file can be significantly faster than using streams, because they can avoid building an index of the file.
+For file formats like grib that do not provide an index within the file, this makes the difference between reading the file once or reading the file twice.
 
-void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
-void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
+CdiIterator is an abstract base class. Which derived class is used depends on the type of the file. The class hierarchy currently looks like this:
 
-int   grib1ltypeToZaxisType(int grib_ltype);
-int   grib2ltypeToZaxisType(int grib_ltype);
+    CdiIterator <|--+-- CdiFallbackIterator
+                    |
+                    +-- CdiGribIterator
 
-int   zaxisTypeToGrib1ltype(int zaxistype);
-int   zaxisTypeToGrib2ltype(int zaxistype);
+The fallback implementation currently uses the stream interface of CDI under the hood to provide full functionality for all filetypes for which no iterator implementation exists yet.
+*/
+//TODO[NH]: Debug messages, print function.
+
+struct CdiIterator {
+  int filetype;      //This is used to dispatch calls to the correct subclass.
+  bool isAdvanced;    //Used to catch inquiries before the first call to CdiIteratorNextField(). //XXX: Advanced is probably not a good word (initialized?)
+
+  //The metadata that can be accessed by the inquiry calls.
+  //While theoretically redundant, these fields allow the handling of most inquiry calls within the base class.
+  //Only the name is excempted because it needs an allocation.
+  //These fields are set by the subclasses in the xxxIterNextField() method.
+  int datatype, timesteptype;
+  int gridId;
+  CdiParam param;
+
+  //The status information for reading/advancing is added in the subclasses.
+};
+
+void baseIterConstruct(CdiIterator *me, int filetype);
+const char* baseIter_constructFromString(CdiIterator *me, const char *description);     //Returns a pointer past the end of the parsed portion of the description string.
+void baseIterDestruct(CdiIterator *me);
+
+#endif
 
-#endif  /* _STREAM_GRB_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -31957,25 +30814,93 @@ int   zaxisTypeToGrib2ltype(int zaxistype);
  * require-trailing-newline: t
  * End:
  */
-#ifndef _ZAXIS_H
-#define _ZAXIS_H
+/*
+ * A fallback implementation of the iterator interface that opens a stream under the hood.
+ *
+ * This implementation is mainly available to provide iterator access to file formats that don't support iterator access natively,
+ * nevertheless, it allows the file to dictate the order in which data is read, possibly providing performance benefits.
+ */
 
-void zaxisGetTypeDescription(int zaxisType, int* outPositive, const char** outName, const char** outLongName, const char** outStdName, const char** outUnit);  //The returned const char* point to static storage. Don't free or modify them.
+#ifndef INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
+#define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
 
-unsigned cdiZaxisCount(void);
+#if defined (HAVE_CONFIG_H)
+#endif
 
-void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
+#include <stdlib.h>
 
-void
-zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
-            int * unpackBufferPos, int originNamespace, void *context,
-            int force_id);
 
-void zaxisDefLtype2(int zaxisID, int ltype2);
+typedef struct CdiFallbackIterator CdiFallbackIterator;
 
-const resOps *getZaxisOps(void);
+CdiIterator *cdiFallbackIterator_new(const char *path, int filetype);
+CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *me);
+CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me);
+char *cdiFallbackIterator_serialize(CdiIterator *me);
+CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *me);
 
-const char *zaxisInqNamePtr(int zaxisID);
+int cdiFallbackIterator_nextField(CdiIterator *me);
+
+char *cdiFallbackIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
+int cdiFallbackIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
+int cdiFallbackIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
+int cdiFallbackIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
+char *cdiFallbackIterator_copyVariableName(CdiIterator *me);
+int cdiFallbackIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute);
+int cdiFallbackIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount);
+
+void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
+void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
+
+void cdiFallbackIterator_delete(CdiIterator *super);
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+/*
+ * An implementation of the iterator interface for GRIB files.
+ * Since GRIB files do not contain an index, this avoids scanning the entire file to generate an in-memory index as streamOpenRead() does.
+ * Consequently, using this interface is much more efficient for GRIB files.
+ */
+
+#ifndef INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
+#define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
+
+#if defined (HAVE_CONFIG_H)
+#endif
+
+
+#ifdef HAVE_LIBGRIB_API
+#include <grib_api.h>
+#endif
+
+typedef struct recordList recordList;
+
+CdiIterator *cdiGribIterator_new(const char *path, int filetype);
+CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *me);
+CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me);
+char *cdiGribIterator_serialize(CdiIterator *me);
+CdiGribIterator *cdiGribIterator_deserialize(const char *me);
+
+int cdiGribIterator_nextField(CdiIterator *me);
+
+char *cdiGribIterator_inqTime(CdiIterator *me, CdiTimeType timeType);
+int cdiGribIterator_levelType(CdiIterator *me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit);
+int cdiGribIterator_level(CdiIterator *me, int levelSelector, double *outValue1, double *outValue2);
+int cdiGribIterator_zaxisUuid(CdiIterator *me, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE]);
+int cdiGribIterator_inqTile(CdiIterator *me, int *outTileIndex, int *outTileAttribute);
+int cdiGribIterator_inqTileCount(CdiIterator *me, int *outTileCount, int *outTileAttributeCount);
+char *cdiGribIterator_copyVariableName(CdiIterator *me);
+
+void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
+void cdiGribIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
 
 #endif
 
@@ -31989,988 +30914,1144 @@ const char *zaxisInqNamePtr(int zaxisID);
  * End:
  */
 
-
 #include <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#ifdef HAVE_LIBGRIB_API
+#include <ctype.h>
 
-struct CdiGribIterator {
-  CdiIterator super;
+static const char kUnexpectedFileTypeMessage[]
+  = "Internal error: Unexpected file type encountered in iterator.\n"
+  "This is either due to an illegal memory access by the application\n"
+  " or an internal logical error in CDI (unlikely, but possible).";
+static const char kAdvancedString[] = "advanced";
+static const char kUnadvancedString[] = "unadvanced";
 
-  CdiInputFile *file;
-  off_t fileOffset;
-  unsigned char *gribBuffer;
-  size_t bufferSize, curRecordSize;
+//Returns a static string.
+static const char* fileType2String(int fileType)
+{
+  switch(fileType)
+    {
 #ifdef HAVE_LIBGRIB_API
-  grib_handle *gribHandle;
-#else
-  void *gribHandle;
+        case CDI_FILETYPE_GRB: return "CDI::Iterator::GRIB1";
+        case CDI_FILETYPE_GRB2: return "CDI::Iterator::GRIB2";
+#endif
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC: return "CDI::Iterator::NetCDF";
+        case CDI_FILETYPE_NC2: return "CDI::Iterator::NetCDF2";
+        case CDI_FILETYPE_NC4: return "CDI::Iterator::NetCDF4";
+        case CDI_FILETYPE_NC4C: return "CDI::Iterator::NetCDF4C";
+        case CDI_FILETYPE_NC5: return "CDI::Iterator::NetCDF5";
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV: return "CDI::Iterator::SRV";
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT: return "CDI::Iterator::EXT";
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG: return "CDI::Iterator::IEG";
 #endif
-};
 
-CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
-{
-  return &me->super;
+      default: return NULL;
+    }
 }
 
-//Since the error handling in constructors is usually very closely related to the workings of a destructor,
-//this function combines both functions in one, using a centralized exit.
-//The mode of operation depends on whether me is a NULL pointer on entry:
-//If it is NULL, a new object is allocated and constructed, which is returned if construction is successful.
-//If a non-NULL pointer is passed in, the object is destructed and NULL is returned. In this case, the other arguments are ignored.
-static CdiGribIterator *cdiGribIterator_condestruct(CdiGribIterator *me, const char *path, int filetype)
+static int string2FileType(const char* fileType, const char **outRestString)
 {
-#define super() (&me->super)
-  if(me) goto destruct;
-  me = (CdiGribIterator *) Malloc(sizeof(*me));
-  baseIterConstruct(super(), filetype);
+  //This first part unconditionally checks all known type strings, and only if the given string matches one of these strings, we use fileType2string() to check whether support for this type has been compiled in. This is to avoid throwing "invalid type string" errors when we just have a library version mismatch.
+#define check(givenString, typeString, typeConstant) do \
+    { \
+      if(givenString == strstr(givenString, typeString)) \
+        { \
+          if(outRestString) *outRestString = givenString + strlen(typeString); \
+          if(fileType2String(typeConstant)) return typeConstant; \
+          Error("Support for " typeString " not compiled in. Please check that the result of `cdiIterator_serialize()` is only passed to a `cdiIterator_deserialize()` implementation of the same CDI library version."); \
+          return CDI_FILETYPE_UNDEF; \
+        } \
+    } while(0)
+  check(fileType, "CDI::Iterator::GRIB1", CDI_FILETYPE_GRB);
+  check(fileType, "CDI::Iterator::GRIB2", CDI_FILETYPE_GRB2);
+  check(fileType, "CDI::Iterator::NetCDF", CDI_FILETYPE_NC);
+  check(fileType, "CDI::Iterator::NetCDF2", CDI_FILETYPE_NC2);
+  check(fileType, "CDI::Iterator::NetCDF4", CDI_FILETYPE_NC4);
+  check(fileType, "CDI::Iterator::NetCDF4C", CDI_FILETYPE_NC4C);
+  check(fileType, "CDI::Iterator::NetCDF5", CDI_FILETYPE_NC5);
+  check(fileType, "CDI::Iterator::SRV", CDI_FILETYPE_SRV);
+  check(fileType, "CDI::Iterator::EXT", CDI_FILETYPE_EXT);
+  check(fileType, "CDI::Iterator::IEG", CDI_FILETYPE_IEG);
+#undef check
 
-  me->file = cdiInputFile_make(path);
-  if(!me->file) goto destructSuper;
-  me->fileOffset = 0;
-  me->gribHandle = NULL;
-  me->gribBuffer = NULL;
-  me->bufferSize = me->curRecordSize = 0;
-  me->super.gridId = CDI_UNDEFID;
+  //If this point is reached, the given string does not seem to be produced by a cdiIterator_serialize() call.
+  Error("The string \"%s\" does not start with a valid iterator type. Please check the source of this string.", fileType);
+  *outRestString = fileType;
+  return CDI_FILETYPE_UNDEF;
+}
 
-  goto success;
+/*
+ at Function cdiIterator_new
+ at Title Create an iterator for an input file
 
-// ^        constructor code        ^
-// |                                |
-// v destructor/error-cleanup code  v
+ at Prototype CdiIterator* cdiIterator_new(const char* path)
+ at Parameter
+    @item path Path to the file that is to be read.
 
-destruct:
-  if(me->super.gridId != CDI_UNDEFID) gridDestroy(me->super.gridId);
-  if(me->gribHandle) grib_handle_delete((struct grib_handle *)me->gribHandle);
-  Free(me->gribBuffer);
-  cdiRefObject_release(&me->file->super);
-destructSuper:
-  baseIterDestruct(super());
-  Free(me);
-  me = NULL;
+ at Result An iterator for the given file.
 
-success:
-  return me;
-#undef super
-}
+ at Description
+    Combined allocator and constructor for CdiIterator.
 
-CdiIterator *cdiGribIterator_new(const char *path, int filetype)
+    The returned iterator does not point to the first field yet,
+    it must first be advanced once before the first field can be introspected.
+    This design decision has two benefits: 1. Empty files require no special
+    cases, 2. Users can start a while(!cdiIterator_nextField(iterator)) loop
+    right after the call to cdiIterator_new().
+*/
+CdiIterator* cdiIterator_new(const char* path)
 {
-  return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
-}
+  int trash;
+  int filetype = cdiGetFiletype(path, &trash);
+  switch(filetype)
+    {
+      case CDI_FILETYPE_UNDEF:
+        Warning("Can't open file \"%s\": unknown format\n", path);
+        return NULL;
 
-CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_new(path, filetype);
+#endif
 
-  //Allocate memory and copy data. (operations that may fail)
-  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
-  if(!result) goto fail;
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_new(path, filetype);
 
-  result->file = me->file;
-  result->fileOffset = me->fileOffset;
-  result->gribBuffer = NULL;
-  result->bufferSize = me->bufferSize;
-  result->curRecordSize = me->curRecordSize;
-  result->gribHandle = NULL;
+      default:
+        Warning("the file \"%s\" is of type %s, but support for this format is not compiled in!", path, strfiletype(filetype));
+        return NULL;
+    }
+}
 
-  if(me->gribBuffer)
+void baseIterConstruct(CdiIterator* me, int filetype)
+{
+  me->filetype = filetype;
+  me->isAdvanced = false;
+}
+
+const char* baseIter_constructFromString(CdiIterator* me, const char* description)
+{
+  const char* result = description;
+  me->filetype = string2FileType(result, &result);
+  assert(me->filetype != CDI_FILETYPE_UNDEF && "Please report this error.");        //This condition should have been checked for in a calling function.
+  for(; *result && isspace(*result); result++);
+  if(result == strstr(result, kAdvancedString))
     {
-      result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
-      if(!result->gribBuffer) goto freeResult;
-      memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
+      me->isAdvanced = true;
+      result += sizeof (kAdvancedString) - 1;
     }
-  if(me->gribHandle)
+  else if(result == strstr(result, kUnadvancedString))
     {
-      result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
-      if(!result->gribHandle) goto freeBuffer;
+      me->isAdvanced = false;
+      result += sizeof (kUnadvancedString) - 1;
     }
-  if(super->gridId != CDI_UNDEFID)
+  else
     {
-      result->super.gridId = gridDuplicate(super->gridId);
-      if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
+      Error("Invalid iterator description string \"%s\". Please check the origin of this string.", description);
+      return NULL;
     }
-
-  //Finish construction. (operations that cannot fail)
-  baseIterConstruct(&result->super, super->filetype);
-  result->super.datatype = super->datatype;
-  result->super.timesteptype = super->timesteptype;
-  result->super.param = super->param;
-  cdiRefObject_retain(&result->file->super);
-
   return result;
-
-  //Error handling.
-deleteGribHandle:
-  if(result->gribHandle) grib_handle_delete(result->gribHandle);
-freeBuffer:
-  Free(result->gribBuffer);
-freeResult:
-  Free(result);
-fail:
-  return NULL;
 }
 
-char *cdiGribIterator_serialize(CdiIterator *super)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+#define sanityCheck(me) do { \
+    if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
+    if(!me->isAdvanced) xabort("Calling %s is not allowed without calling cdiIterator_nextField() first.", __func__); \
+} while(0)
 
-  const char *path = cdiInputFile_getPath(me->file);
-  char *escapedPath = cdiEscapeSpaces(path);
-  char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
-  sprintf(result, "%s %zu", escapedPath, me->fileOffset);
-  Free(escapedPath);
-  return result;
-}
+/*
+ at Function cdiIterator_clone
+ at Title Make a copy of an iterator
 
+ at Prototype CdiIterator* cdiIterator_clone(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to copy.
 
-CdiGribIterator *cdiGribIterator_deserialize(const char *description)
-{
-  char *path;
-  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
-  if(!me) goto fail;
+ at Result The clone.
 
-  description = baseIter_constructFromString(&me->super, description);
+ at Description
+    Clones the given iterator. Make sure to call cdiIterator_delete() on both
+    the copy and the original.
 
-  while(*description == ' ') description++;
-  path = cdiUnescapeSpaces(description, &description);
-  if(!path) goto destructSuper;
+    This is not a cheap operation: Depending on the type of the file, it will
+    either make a copy of the current field in memory (GRIB files), or reopen
+    the file (all other file types). Use it sparingly. And if you do, try to
+    avoid keeping too many clones around: their memory footprint is
+    significant.
+*/
+CdiIterator* cdiIterator_clone(CdiIterator* me)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_getSuper(cdiGribIterator_clone(me));
+#endif
 
-  me->file = cdiInputFile_make(path);
-  Free(path);
-  if(!me->file) goto destructSuper;
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_getSuper(cdiFallbackIterator_clone(me));
 
-  {
-    const char *savedStart = description;
-    long long decodedOffset = strtoll(description, (char**)&description, 0);    //The cast is a workaround for the wrong signature of strtoll() (it should have been `long long strtoll(const char*, const char**, int)`, not `long long strtoll(const char*, char**, int)`.
-    me->fileOffset = (off_t)decodedOffset;
-    if(savedStart == description) goto closeFile;
-    if((unsigned long long)decodedOffset > (unsigned long long)me->fileOffset) goto closeFile;
-  }
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
+    }
+}
 
-  me->gribBuffer = NULL;
-  me->bufferSize = me->curRecordSize = 0;
-  me->gribHandle = NULL;
-  me->super.gridId = CDI_UNDEFID;
-  if(me->super.isAdvanced && cdiGribIterator_nextField(&me->super)) goto closeFile;
+/*
+ at Function cdiGribIterator_clone
+ at Title Gain access to GRIB specific functionality
 
-  return me;
+ at Prototype CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
+ at Result A clone that allows access to GRIB specific functionality, or NULL if the underlying file is not a GRIB file.
 
-closeFile:
-  cdiRefObject_release(&me->file->super);
-destructSuper:
-  baseIterDestruct(&me->super);
-  Free(me);
-fail:
-  return NULL;
-}
+ at Description
+    Clones the given iterator iff the underlying file is a GRIB file, the returned iterator allows access to GRIB specific functionality.
+    Make sure to check that the return value is not NULL, and to call cdiGribIterator_delete() on the copy.
 
-static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
+    This is not a cheap operation: It will make a copy of the current field in memory. Use it sparingly. And if you do, try to avoid keeping too many clones around, their memory footprint is significant.
+*/
+CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
 {
-  if(me->bufferSize < requiredSize)
+  sanityCheck(me);
+  switch(me->filetype)
     {
-      me->bufferSize *= 2;
-      if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
-      me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
-    }
-}
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_makeClone(me);
+#endif
 
-static bool isGrib1DualLevel(int levelType)
-{
-  switch(levelType)
-    {
-      case 101: case 104: case 106: case 108: case 110: case 112:
-      case 114: case 116: case 120: case 121: case 128: case 141:   //This is the complete list after grib_api-1.12.3/definitions/grib1/sections.1.def:106-117:, the code in cdi/src/stream_gribapi.c:grib1GetLevel() seems to be incomplete.
-        return true;
       default:
-        return false;
+        return NULL;
     }
 }
 
-static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
-{
-  for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
-    {
-      currentPosition = (unsigned char *)memchr(currentPosition, 'G', size - (size_t)(currentPosition - data) - 3);      //-3 to ensure that we don't overrun the buffer during the strncmp() call.
-      if(!currentPosition) return NULL;
-      if(!strncmp((const char*)currentPosition, "GRIB", 4)) return currentPosition;
-    }
-  return NULL;
-}
+/*
+ at Function cdiIterator_serialize
+ at Title Serialize an iterator for sending it to another process
 
-//This clobbers the contents of the gribBuffer!
-//Returns the file offset of the next 'GRIB' marker.
-static ssize_t scanToGribMarker(CdiGribIterator *me)
+ at Prototype char* cdiIterator_serialize(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
+
+ at Result A malloc'ed string that contains the full description of the iterator.
+
+ at Description
+    Make sure to call Free() on the resulting string.
+*/
+char* cdiIterator_serialize(CdiIterator* me)
 {
-  cdiGribIterator_ensureBuffer(me, 8*1024);
-  const size_t kMaxScanSize = 16*1024*1024;
-  for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
+  if(!me) xabort("NULL was passed to %s as an iterator. Please check the return value of cdiIterator_new().", __func__); \
+  char* subclassDescription = NULL;
+  switch(me->filetype)
     {
-      //Load a chunk of data into our buffer.
-      scanSize = me->bufferSize;
-      if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
-      assert(scanSize <= me->bufferSize);
-      int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
-      if(status != CDI_NOERR && status != CDI_EEOF) return -1;
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          subclassDescription = cdiGribIterator_serialize(me);
+          break;
+#endif
 
-      const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
-      if(startPosition)
-        {
-          return (ssize_t)(me->fileOffset + (off_t)scannedBytes + (off_t)(startPosition - me->gribBuffer));
-        }
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          subclassDescription = cdiFallbackIterator_serialize(me);
+          break;
 
-      //Get the offset for the next iteration if there is a next iteration.
-      scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
-      scanSize &= ~(size_t)0xf; //make 16 bytes aligned
-      if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
     }
-  return -1;
-}
-
-static unsigned decode24(void *beData)
-{
-  unsigned char *bytes = (unsigned char *)beData;
-  return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
-}
 
-static uint64_t decode64(void *beData)
-{
-  unsigned char *bytes = (unsigned char *)beData;
-  uint64_t result = 0;
-  for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
+  const char *ftypeStr = fileType2String(me->filetype),
+    *advStr = me->isAdvanced ? kAdvancedString : kUnadvancedString;
+  char* result = (char *) Malloc(strlen(ftypeStr) + 1 + strlen(advStr) + 1
+                         + strlen(subclassDescription) + 1);
+  sprintf(result, "%s %s %s", ftypeStr, advStr, subclassDescription);
+  Free(subclassDescription);
   return result;
 }
 
-//Determine the size of the GRIB record that begins at the given file offset.
-static int getRecordSize(CdiGribIterator *me, off_t gribFileOffset, size_t *outRecordSize)
-{
-  char buffer[16];
-  size_t readSize;
-  int status = cdiInputFile_read(me->file, gribFileOffset, sizeof(buffer), &readSize, buffer);
-  if(status != CDI_NOERR && status != CDI_EEOF) return status;
-  if(readSize < sizeof(buffer)) return CDI_EEOF;
-  *outRecordSize = 0;
-  switch(buffer[7])
-    {
-      case 1:
-        *outRecordSize = decode24(&buffer[4]);
-        if(*outRecordSize & (1 << 23))
-          {
-            *outRecordSize = 120*(*outRecordSize & ((1 << 23) - 1));    //Rescaling for long records.
-            //The corresponding code in cgribexlib.c:4532-4570: is much more complicated
-            //due to the fact that it subtracts the padding bytes that are inserted after section 4.
-            //However, we are only interested in the total size of data we need to read here,
-            //so we can ignore the presence of some padding bytes.
-          }
-        return CDI_NOERR;
+/*
+ at Function cdiIterator_deserialize
+ at Title Recreate an iterator from its textual description
 
-      case 2:
-        *outRecordSize =  decode64(&buffer[8]);
-        return CDI_NOERR;
+ at Prototype CdiIterator* cdiIterator_deserialize(const char* description)
+ at Parameter
+    @item description The result of a call to cdiIterator_serialize().
 
-      default:
-        return CDI_EUFTYPE;
-    }
-}
+ at Result A clone of the original iterator.
 
-#if 0
-static void hexdump(void *data, size_t size)
+ at Description
+    A pair of cdiIterator_serialize() and cdiIterator_deserialize() is functionally equivalent to a call to cdiIterator_clone()
+
+    This function will reread the current field from disk, so don't expect immediate return.
+*/
+//This only checks the type of the iterator and calls the corresponding subclass function,
+//the real deserialization is done in baseIter_constructFromString().
+CdiIterator* cdiIterator_deserialize(const char* description)
 {
-  unsigned char *charData = data;
-  for(size_t offset = 0; offset < size; )
+  switch(string2FileType(description, NULL))
     {
-      printf("%016zx:", offset);
-      for(size_t i = 0; i < 64 && offset < size; i++, offset++)
-        {
-          if((i & 63) && !(i & 15)) printf(" |");
-          if((i & 15) && !(i & 3)) printf("  ");
-          printf(" %02x", charData[offset]);
-        }
-      printf("\n");
-    }
-}
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
 #endif
 
-//Read a record into memory and wrap it in a grib_handle.
-//XXX: I have omitted checking for szip compression as it is done in grbReadVarDP() & friends since that appears to be a non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip compressio is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with such szip compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this [...]
-static int readMessage(CdiGribIterator *me)
-{
-  //Destroy the old grib_handle.
-  if(me->gribHandle) grib_handle_delete(me->gribHandle), me->gribHandle = NULL;
-  me->fileOffset += (off_t)me->curRecordSize;
-
-  //Find the next record and determine its size.
-  ssize_t gribFileOffset = scanToGribMarker(me);
-  int result = CDI_EEOF;
-  if(gribFileOffset < 0) goto fail;
-  result = getRecordSize(me, gribFileOffset, &me->curRecordSize);
-  if(result) goto fail;
-
-  //Load the whole record into our buffer and create a grib_handle for it.
-  cdiGribIterator_ensureBuffer(me, me->curRecordSize);
-  result = cdiInputFile_read(me->file, gribFileOffset, me->curRecordSize, NULL, me->gribBuffer);
-  if(result) goto fail;
-  me->gribHandle = grib_handle_new_from_message(NULL, me->gribBuffer, me->curRecordSize);
-  result = CDI_EUFSTRUCT;
-  if(!me->gribHandle) goto fail;
-
-  return CDI_NOERR;
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_getSuper(cdiFallbackIterator_deserialize(description));
 
-fail:
-  me->curRecordSize = 0;        //This ensures that we won't jump to an uncontrolled file position if cdiGribIterator_nextField() is called another time after it has returned an error.
-  return result;
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
+    }
 }
 
-int cdiGribIterator_nextField(CdiIterator *super)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
-
-  if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;
-
-  //Get the next GRIB message into our buffer.
-  int result = readMessage(me);
-  if(result) return result;
 
-  //Get the metadata that's published as variables in the base class.
-  super->datatype = gribGetDatatype(me->gribHandle);
-  super->timesteptype = gribapiGetTsteptype(me->gribHandle);
-  cdiDecodeParam(gribapiGetParam(me->gribHandle), &super->param.number, &super->param.category, &super->param.discipline);
-  grid_t grid;
-  gribapiGetGrid(me->gribHandle, &grid);
-  super->gridId = gridGenerate(&grid);
+/*
+ at Function cdiIterator_print
+ at Title Print a textual description of the iterator to a stream
 
-  return CDI_NOERR;
-}
+ at Prototype void cdiIterator_print(CdiIterator* iterator, FILE* stream);
+ at Parameter
+    @item iterator The iterator to print.
+    @item stream The stream to print to.
 
-char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
+ at Description
+    Use for debugging output.
+*/
+void cdiIterator_print(CdiIterator* me, FILE* stream)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  return gribMakeTimeString(me->gribHandle, timeType);
+  char* description = cdiIterator_serialize(me);
+  fprintf(stream, "%s\n", description);
+  Free(description);
 }
 
-int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
 
-  //First determine the zaxis type corresponding to the given level.
-  int zaxisType = ZAXIS_GENERIC;
-  if(gribEditionNumber(me->gribHandle) <= 1)
-    {
-      int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
-      if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
-      zaxisType = grib1ltypeToZaxisType(levelType);
-    }
-  else
-    {
-      int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
-      zaxisType = grib2ltypeToZaxisType(levelType);
-    }
+/*
+ at Function cdiIterator_nextField
+ at Title Advance an iterator to the next field in the file
 
-  //Then lookup the requested names.
-  const char *name, *longName, *stdName, *unit;
-  zaxisGetTypeDescription(zaxisType, NULL, &name, &longName, &stdName, &unit);
-  if(outName) *outName = strdup(name);
-  if(outLongName) *outLongName = strdup(longName);
-  if(outStdName) *outStdName = strdup(stdName);
-  if(outUnit) *outUnit = strdup(unit);
+ at Prototype int cdiIterator_nextField(CdiIterator* iterator)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-  return zaxisType;
-}
+ at Result An error code. May be one of:
+  * CDI_NOERR: The iterator has successfully been advanced to the next field.
+  * CDI_EEOF: No more fields to read in this file.
 
-static double logicalLevelValue2(long gribType, long storedValue, long power)
+ at Description
+    One call to cdiIterator_nextField() is required before the metadata of the first field can be examined.
+    Usually, it will be used directly as the condition for a while() loop.
+*/
+int cdiIterator_nextField(CdiIterator* me)
 {
-  double factor = 1;
-  assert(power >= 0);
-  while(power--) factor *= 10;      //this is precise up to factor == 22.
-  switch(gribType)
+  if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
+  me->isAdvanced = true;
+  switch(me->filetype)
     {
-      case GRIB2_LTYPE_LANDDEPTH:
-      case GRIB2_LTYPE_ISOBARIC:
-      case GRIB2_LTYPE_SIGMA:
-        return (double)storedValue * (1000.0/factor);      //The evaluation order allows the factors of ten to cancel out before rounding.
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_nextField(me);
+#endif
 
-      case 255:
-        return 0;
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_nextField(me);
 
       default:
-        return (double)storedValue/factor;
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_EINVAL;
     }
 }
 
-//The output values must be preinitialized, this function does not always write them.
-static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const char *powerKey, const char *valueKey, double *outValue1, double *outValue2)
+static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
 {
-  assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);
-
-  long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
-  switch(levelType)
+  sanityCheck(me);
+  switch(me->filetype)
     {
-      case 255: break;
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_inqTime(me, timeType);
+#endif
 
-      case 105: case 113:
-        {
-          unsigned long value = (unsigned long)gribGetLongDefault(gribHandle, valueKey, 0);
-          unsigned long coordinateCount = (unsigned long)gribGetLongDefault(gribHandle, "numberOfCoordinatesValues", 0);
-          if(value >= coordinateCount/2)
-            {
-              Error("Invalid level coordinate: Level has the hybrid coordinate index %lu, but only %lu coordinate pairs are present.", value, coordinateCount/2);
-              return CDI_EUFSTRUCT;
-            }
-          int status;
-          //XXX: I'm not 100% sure about how the coordinate pairs are stored in the file.
-          //     I'm assuming an array of pairs due to the example code in grib_api-1.12.3/examples/F90/set_pv.f90, but that may be wrong.
-          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2    , outValue1))) return status;
-          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2 + 1, outValue2))) return status;
-          break;
-        }
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_inqTime(me, timeType);
 
       default:
-        {
-          long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
-          if(power == 255) power = 0;
-          long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
-          *outValue1 = logicalLevelValue2(levelType, value, power);
-        }
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
     }
-  return CDI_NOERR;
 }
 
-int cdiGribIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  double trash;
-  if(!outValue1) outValue1 = &trash;
-  if(!outValue2) outValue2 = &trash;
-  *outValue1 = *outValue2 = 0;
+/*
+ at Function cdiIterator_inqStartTime
+ at Title Get the start time of a measurement
 
-  if(gribEditionNumber(me->gribHandle) > 1)
-    {
-      if(levelSelector)
-        {
-          return readLevel2(me->gribHandle, "typeOfFirstFixedSurface", "scaleFactorOfFirstFixedSurface", "scaledValueOfFirstFixedSurface", outValue1, outValue2);
-        }
-      else
-        {
-          return readLevel2(me->gribHandle, "typeOfSecondFixedSurface", "scaleFactorOfSecondFixedSurface", "scaledValueOfSecondFixedSurface", outValue1, outValue2);
-        }
-    }
-  else
-    {
-      long levelType = (uint8_t)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", -1);    //1 byte
-      if(levelType == 255)
-        {}
-      else if(isGrib1DualLevel((int)levelType))
-        {
-          *outValue1 = (double)gribGetLongDefault(me->gribHandle, (levelSelector ? "bottomLevel" : "topLevel"), 0);
-        }
-      else if(levelType == 100)
-        {
-          *outValue1 = 100 * (double)gribGetLongDefault(me->gribHandle, "level", 0);        //2 bytes
-        }
-      else
-        {
-          *outValue1 = (double)gribGetLongDefault(me->gribHandle, "level", 0);        //2 bytes
-        }
-    }
-  return CDI_NOERR;
-}
+ at Prototype char* cdiIterator_inqStartTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+ at Result A malloc'ed string containing the (start) time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
 
-  if(outVgridNumber)
-    {
-      long temp;
-      if(grib_get_long(me->gribHandle, "numberOfVGridUsed", &temp)) return CDI_EINVAL;
-      *outVgridNumber = (int)temp;
-    }
-  if(outLevelCount)
-    {
-      long temp;
-      if(grib_get_long(me->gribHandle, "nlev", &temp)) return CDI_EINVAL;
-      *outLevelCount = (int)temp;
-    }
-  if(outUuid)
-    {
-      size_t size = CDI_UUID_SIZE;
-      if(grib_get_bytes(me->gribHandle, "uuidOfVGrid", outUuid, &size)) return CDI_EINVAL;
-      if(size != CDI_UUID_SIZE) return CDI_EUFSTRUCT;
-    }
+ at Description
+The returned time is either the time of the data (fields defined at a time point),
+or the start time of an integration time range (statistical fields).
 
-  return CDI_NOERR;
-}
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
 
-int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
+*/
+char* cdiIterator_inqStartTime(CdiIterator* me)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  int trash;
-  if(!outTileIndex) outTileIndex = &trash;
-  if(!outTileAttribute) outTileAttribute = &trash;
+  return cdiIterator_inqTime(me, kCdiTimeType_startTime);
+}
 
-  //Get the values if possible.
-  int error = CDI_NOERR;
-  long value;
-  if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
-  *outTileIndex = (int)value;
-  if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
-  *outTileAttribute = (int)value;
+/*
+ at Function cdiIterator_inqEndTime
+ at Title Get the end time of a measurement
 
-  //Ensure defined return values in case of failure.
-  if(error) *outTileIndex = *outTileAttribute = -1;
-  return error;
-}
+ at Prototype char* cdiIterator_inqEndTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  int trash;
-  if(!outTileCount) outTileCount = &trash;
-  if(!outTileAttributeCount) outTileAttributeCount = &trash;
+ at Result A malloc'ed string containing the end time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm", or NULL if no such time is defined.
 
-  //Get the values if possible.
-  int error = CDI_NOERR;
-  long value;
-  if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
-  *outTileCount = (int)value;
-  if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
-  *outTileAttributeCount = (int)value;
+ at Description
+The returned time is the end time of an integration period if such a time exists (statistical fields).
+Otherwise, NULL is returned.
 
-  //Ensure defined return values in case of failure.
-  if(error) *outTileCount = *outTileAttributeCount = 0;
-  return error;
-}
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
 
-char *cdiGribIterator_copyVariableName(CdiIterator *super)
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
+*/
+char* cdiIterator_inqEndTime(CdiIterator* me)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  return gribCopyString(me->gribHandle, "shortName");
+  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
 }
 
-void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+/*
+ at Function cdiIterator_inqRTime
+ at Title Get the validity time of the current field
 
-  GRIB_CHECK(my_grib_set_double(me->gribHandle, "missingValue", cdiDefaultMissval), 0);
-  gribGetDoubleArray(me->gribHandle, "values", buffer);
-  long gridType = gribGetLong(me->gribHandle, "gridDefinitionTemplateNumber");
-  if(nmiss)
-    {
-      *nmiss = (gridType >= 50 && gridType <= 53) ? (size_t)0 : (size_t)gribGetLong(me->gribHandle, "numberOfMissing");        //The condition excludes harmonic data.
-    }
-}
+ at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+ at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
 
-  size_t valueCount = gribGetArraySize(me->gribHandle, "values");
-  double *temp = (double *) Malloc(valueCount*sizeof(*temp));
-  cdiGribIterator_readField(super, temp, nmiss);
-  for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
-  Free(temp);
+ at Description
+The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
+That is, if the field is a time point, its time is returned,
+if it is a statistical field with an integration period, the end time of the integration period is returned.
+
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
+
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
+*/
+char* cdiIterator_inqRTime(CdiIterator* me)
+{
+  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
 }
-#endif
 
 /*
- at Function cdiGribIterator_delete
- at Title Dispose off a CdiGribIterator instance.
+ at Function cdiIterator_inqVTime
+ at Title Get the validity time of the current field
 
- at Prototype void cdiGribIterator_delete(CdiGribIterator *me)
+ at Prototype char* cdiIterator_inqVTime(CdiIterator* me)
 @Parameter
-    @item me The iterator to delete.
+    @item iterator The iterator to operate on.
+
+ at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
 
 @Description
-    Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
+The returned time is the validity time as it is returned by taxisInqVtime(), only more precise.
+That is, if the field is a time point, its time is returned,
+if it is a statistical field with an integration period, the end time of the integration period is returned.
+
+Converts the time to the ISO-8601 format and returns it in a newly allocated buffer.
+The caller is responsible to Free() the resulting string.
+
+If the file is a GRIB file, the calendar that is used to resolve the relative times is the proleptic calendar
+as it is implemented by the standard C mktime() function.
+This is due to the fact that GRIB-API version 1.12.3 still does not implement the calendar identification fields.
 */
-void cdiGribIterator_delete(CdiGribIterator *me)
+char* cdiIterator_inqVTime(CdiIterator* me)
 {
-#ifdef HAVE_LIBGRIB_API
-  if(me) cdiGribIterator_condestruct(me, NULL, 0);
-#else
-  if (me)
-    xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  char* result = cdiIterator_inqEndTime(me);
+  return (result) ? result : cdiIterator_inqStartTime(me);
 }
 
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// callthroughs to provide direct access to the grib keys //////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
 /*
- at Function cdiGribIterator_inqEdition
- at Title Get the version of the GRIB standard that is used
+ at Function cdiIterator_inqLevelType
+ at Title Get the type of a level
 
- at Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
+ at Prototype int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName = NULL, char **outLongName = NULL, char **outStdName = NULL, char **outUnit = NULL)
 @Parameter
-    @item me The iterator to operate on.
+    @item iterator The iterator to operate on.
+    @item levelSelector Zero for the top level, one for the bottom level
+    @item outName Will be set to a Malloc()'ed string with the name of the level if not NULL.
+    @item outLongName Will be set to a Malloc()'ed string with the long name of the level if not NULL.
+    @item outStdName Will be set to a Malloc()'ed string with the standard name of the level if not NULL.
+    @item outUnit Will be set to a Malloc()'ed string with the unit of the level if not NULL.
 
- at Result The GRIB version.
+ at Result An integer indicating the type of the level.
 
 @Description
-    Returns the version of the file format.
+Find out some basic information about the given level, the levelSelector selects the function of the requested level.
+If the requested level does not exist, this returns CDI_UNDEFID.
 */
-int cdiGribIterator_inqEdition(CdiGribIterator *me)
+int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
 {
+  sanityCheck(me);
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return (int)gribEditionNumber(me->gribHandle);
-#else
-  (void)me;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
 #endif
+          return cdiFallbackIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_UNDEFID;
+    }
 }
 
 /*
- at Function cdiGribIterator_getLong
- at Title Access to grib_get_long()
+ at Function cdiIterator_inqLevel
+ at Title Get the value of the z-coordinate
 
- at Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
+ at Prototype void cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2 = NULL)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
+    @item levelSelector Zero for the top level, one for the bottom level
+    @item outValue1 For "normal" levels this returns the value, for hybrid levels the first coordinate, for generalized levels the level number.
+    @item outValue2 Zero for "normal" levels, for hybrid levels, this returns the second coordinate, for generalized levels the level count.
 
 @Result An error code.
 
 @Description
-    Callthrough to grib_get_long().
+Returns the value of the z-coordinate, whatever that may be.
 */
-int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
+int cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2)
 {
+  sanityCheck(me);
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return grib_get_long(me->gribHandle, key, result);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
 #endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          return cdiFallbackIterator_level(me, levelSelector, outValue1, outValue2);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_EINVAL;
+    }
 }
 
 /*
- at Function cdiGribIterator_getLength
- at Title Access to grib_get_length()
+ at Function cdiIterator_inqLevelUuid
+ at Title Get the UUID of the z-axis used by this field
 
- at Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+ at Prototype int cdiIterator_inqLevelUuid(CdiIterator* me, int levelSelector, unsigned char (*outUuid)[16])
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
+    @item outVgridNumber The number of the associated vertical grid description.
+    @item outLevelCount The number of levels in the associated vertical grid description.
+    @item outUuid A pointer to a user supplied buffer of 16 bytes to store the UUID in.
 
 @Result An error code.
 
 @Description
-    Callthrough to grib_get_length().
+Returns identifying information for the external z-axis description. May only be called for generalized levels.
 */
-int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
 {
-#ifdef HAVE_GRIB_GET_LENGTH
-  return grib_get_length(me->gribHandle, key, result);
-#elif defined(HAVE_LIBGRIB_API)
-  (void)me;
-  (void)key;
-  (void)result;
-  Error("grib_get_length() is not available, so cdiGribIterator_getLength() can't be used");
-  return -1;
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+#ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
 #endif
+          return cdiFallbackIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
 }
 
 /*
- at Function cdiGribIterator_getString
- at Title Access to grib_get_string()
+ at Function cdiIterator_inqTile
+ at Title Inquire the tile information for the current field
 
- at Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
+ at Prototype int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
+    @item outTileIndex The index of the current tile, -1 if no tile information is available.
+    @item outTileAttribute The attribute of the current tile, -1 if no tile information is available.
+
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+
+ at Description
+Inquire the tile index and attribute for the current field.
+*/
+int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
+{
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
+}
+
+/**
+ at Function cdiIterator_inqTileCount
+ at Title Inquire the tile count and tile attribute counts for the current field
+
+ at Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
+ at Parameter
+    @item iterator The iterator to operate on.
+    @item outTileCount The number of tiles used for this variable, zero if no tile information is available.
+    @item outTileAttributeCount The number of attributes available for the tile of this field, zero if no tile information is available.
+          Note: This is not the global attribute count, which would be impossible to infer without reading the entire file if it's a GRIB file.
 
- at Result An error code.
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
 
 @Description
-    Callthrough to grib_get_string().
+Inquire the tile count and tile attribute counts for the current field.
 */
-int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
+int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
 {
-#ifdef HAVE_LIBGRIB_API
-  return grib_get_string(me->gribHandle, key, result, length);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  (void)length;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+      #endif
+
+      #ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+      #endif
+      #ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+      #endif
+      #ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+      #endif
+      #ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+      #endif
+          return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
 }
 
 /*
- at Function cdiGribIterator_inqLongValue
- at Title Get the value of a GRIB-API key as a long
+ at Function cdiIterator_inqParam
+ at Title Get discipline, category, and number
 
- at Prototype long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
+ at Prototype CdiParam cdiIterator_inqParam(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item key The GRIB-API key to retrieve.
+    @item iterator The iterator to operate on.
 
- at Result The value of the key.
+ at Result A struct containing the requested information.
 
 @Description
-    Use this to fetch a grib value if you are certain that the given key must be present.
-    This will abort the process if the key cannot be retrieved.
+    Simple metadata inspection function.
 */
-long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
+CdiParam cdiIterator_inqParam(CdiIterator* me)
 {
-#ifdef HAVE_LIBGRIB_API
-  return gribGetLong(me->gribHandle, key);
-#else
-  (void)me;
-  (void)key;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  sanityCheck(me);
+  return me->param;
 }
 
 /*
- at Function cdiGribIterator_inqLongDefaultValue
- at Title Get the value of a GRIB-API key as a long
+ at Function cdiIterator_inqParamParts
+ at Title Get discipline, category, and number
 
- at Prototype long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
+ at Prototype void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
 @Parameter
-    @item me The iterator to operate on.
-    @item key The GRIB-API key to retrieve.
-    @item defaultValue The value to return if the key is not present.
-
- at Result The value of the key or the given default value.
+    @item iterator The iterator to operate on.
+    @item outDiscipline This is used to return the discipline.
+    @item outCategory This is used to return the category.
+    @item outNumber This is used to return the number.
 
 @Description
-    Use this if you can handle failure to fetch the key by supplying a default value.
-    This function cannot fail.
+    Simple metadata inspection function.
+
+    Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
+    rendering it unusable from FORTRAN. This function is the workaround.
 */
-long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
+void cdiIterator_inqParamParts(CdiIterator *me, int *outDiscipline, int *outCategory, int *outNumber)
 {
-#ifdef HAVE_LIBGRIB_API
-  return gribGetLongDefault(me->gribHandle, key, defaultValue);
-#else
-  (void)me;
-  (void)key;
-  (void)defaultValue;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  CdiParam result = cdiIterator_inqParam(me);
+  if(outDiscipline) *outDiscipline = result.discipline;
+  if(outCategory) *outCategory = result.category;
+  if(outNumber) *outNumber = result.number;
 }
 
 /*
- at Function cdiGribIterator_inqStringValue
- at Title Safely retrieve a GRIB-API key with a string value
+ at Function cdiIterator_inqDatatype
+ at Title Get the datatype of the current field
 
- at Prototype char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
+ at Prototype int cdiIterator_inqDatatype(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item key The GRIB-API key to retrieve.
+    @item iterator The iterator to operate on.
 
- at Result A malloc'ed string or NULL.
+ at Result The datatype that is used to store this field on disk.
 
 @Description
-    This will first call grib_get_length() to inquire the actual size of the string,
-    allocate memory accordingly, call grib_get_string(), and return the pointer to the new string.
-    Returns NULL on failure.
+    Simple metadata inspection function.
 */
-char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
+int cdiIterator_inqDatatype(CdiIterator* me)
 {
-#ifdef HAVE_LIBGRIB_API
-  return gribCopyString(me->gribHandle, key);
-#else
-  (void)me;
-  (void)key;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  sanityCheck(me);
+  return me->datatype;
 }
 
 /*
- at Function cdiGribIterator_getDouble
- at Title Access to grib_get_double()
+ at Function cdiIterator_inqTsteptype
+ at Title Get the timestep type
 
- at Prototype int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
+ at Prototype int cdiIterator_inqTsteptype(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
 
- at Result An error code.
+ at Result The timestep type.
 
 @Description
-    Callthrough to grib_get_double().
+    Simple metadata inspection function.
 */
-int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
+int cdiIterator_inqTsteptype(CdiIterator* me)
 {
-#ifdef HAVE_LIBGRIB_API
-  return grib_get_double(me->gribHandle, key, result);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  sanityCheck(me);
+  return me->timesteptype;
 }
 
 /*
- at Function cdiGribIterator_getSize
- at Title Access to grib_get_size()
+ at Function cdiIterator_inqVariableName
+ at Title Get the variable name of the current field
 
- at Prototype int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
+ at Prototype char* cdiIterator_inqVariableName(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
 
- at Result An error code.
+ at Result A pointer to a C-string containing the name. The storage for this string is allocated with Malloc(), and it is the responsibility of the caller to Free() it.
 
 @Description
-    Callthrough to grib_get_size().
+    Allocates a buffer to hold the string, copies the current variable name into this buffer, and returns the buffer.
+    The caller is responsible to make the corresponding Free() call.
 */
-int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
+char* cdiIterator_inqVariableName(CdiIterator* me)
 {
+  sanityCheck(me);
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return grib_get_size(me->gribHandle, key, result);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          return cdiGribIterator_copyVariableName(me);
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
 #endif
+          return cdiFallbackIterator_copyVariableName(me);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
+    }
 }
 
 /*
- at Function cdiGribIterator_getLongArray
- at Title Access to grib_get_long_array()
+ at Function cdiIterator_inqGridId
+ at Title Get the ID of the current grid
 
- at Prototype int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
+ at Prototype int cdiIterator_inqGridId(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
+    @item iterator The iterator to operate on.
 
- at Result An error code.
+ at Result A gridId that can be used for further introspection.
 
 @Description
-    Callthrough to grib_get_long_array().
+    This provides access to the grid related metadata.
+    The resulting ID is only valid until the next time cdiIterator_nextField() is called.
 */
-int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
+int cdiIterator_inqGridId(CdiIterator* me)
 {
-#ifdef HAVE_LIBGRIB_API
-  return grib_get_long_array(me->gribHandle, key, result, size);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  (void)size;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
-#endif
+  sanityCheck(me);
+  return me->gridId;
 }
 
 /*
- at Function cdiGribIterator_getDoubleArray
- at Title Access to grib_get_double_array()
+ at Function cdiIterator_readField
+ at Title Read the whole field into a double buffer
 
- at Prototype int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
+ at Prototype void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
 @Parameter
-    @item me The iterator to operate on.
-    @item ... The arguments to the underlying GRIB-API function.
-
- at Result An error code.
+    @item iterator The iterator to operate on.
+    @item buffer A pointer to the double array that the data should be written to.
+    @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
 
 @Description
-    Callthrough to grib_get_double_array().
+    It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
+    Failing to do so results in undefined behavior. You have been warned.
 */
-int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
+void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
 {
+  sanityCheck(me);
+  if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return grib_get_double_array(me->gribHandle, key, result, size);
-#else
-  (void)me;
-  (void)key;
-  (void)result;
-  (void)size;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          cdiGribIterator_readField(me, buffer, nmiss);
+	  return;
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
 #endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          cdiFallbackIterator_readField(me, buffer, nmiss);
+          return;
+      default:
+        Error(kUnexpectedFileTypeMessage);
+    }
 }
 
 /*
- at Function cdiGribIterator_inqDoubleValue
- at Title Get the value of a GRIB-API key as a double
+ at Function cdiIterator_readFieldF
+ at Title Read the whole field into a double buffer
 
- at Prototype double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
+ at Prototype void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
 @Parameter
-    @item me The iterator to operate on.
-    @item key The GRIB-API key to retrieve.
-
- at Result The value of the key.
+    @item iterator The iterator to operate on.
+    @item buffer A pointer to the double array that the data should be written to.
+    @item nmiss A pointer to a variable where the count of missing values will be stored. May be NULL.
 
 @Description
-    Use this to fetch a grib value if you are certain that the given key must be present.
-    This will abort the process if the key cannot be retrieved.
+    It is assumed that the caller first analyses the return value of cdiIterator_inqGridId to determine the required size of the buffer.
+    Failing to do so results in undefined behavior. You have been warned.
 */
-double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
+void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
 {
+  sanityCheck(me);
+  if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return gribGetDouble(me->gribHandle, key);
-#else
-  (void)me;
-  (void)key;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          cdiGribIterator_readFieldF(me, buffer, nmiss);
+	  return;
+#endif
+
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
 #endif
+          cdiFallbackIterator_readFieldF(me, buffer, nmiss);
+          return;
+      default:
+        Error(kUnexpectedFileTypeMessage);
+    }
 }
 
 /*
- at Function cdiGribIterator_inqDoubleDefaultValue
- at Title Get the value of a GRIB-API key as a double
+ at Function cdiIterator_delete
+ at Title Destroy an iterator
 
- at Prototype double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
+ at Prototype void cdiIterator_delete(CdiIterator* iterator)
 @Parameter
-    @item me The iterator to operate on.
-    @item key The GRIB-API key to retrieve.
-    @item defaultValue The value to return if the key is not present.
-
- at Result The value of the key or the given default value.
+    @item iterator The iterator to operate on.
 
 @Description
-    Use this if you can handle failure to fetch the key by supplying a default value.
-    This function cannot fail.
+    Combined destructor & deallocator.
 */
-double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
+void cdiIterator_delete(CdiIterator* me)
 {
+  if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
+  switch(me->filetype)
+    {
 #ifdef HAVE_LIBGRIB_API
-  return gribGetDoubleDefault(me->gribHandle, key, defaultValue);
-#else
-  (void)me;
-  (void)key;
-  (void)defaultValue;
-  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          cdiGribIterator_delete((CdiGribIterator*)me);
+          break;
 #endif
-}
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef MODEL_H
-#define MODEL_H
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+#endif
+#ifdef HAVE_LIBSERVICE
+        case CDI_FILETYPE_SRV:
+#endif
+#ifdef HAVE_LIBEXTRA
+        case CDI_FILETYPE_EXT:
+#endif
+#ifdef HAVE_LIBIEG
+        case CDI_FILETYPE_IEG:
+#endif
+          cdiFallbackIterator_delete(me);
+          break;
 
-int
-modelUnpack(void *buf, int size, int *position,
-            int originNamespace, void *context, int force_id);
+      default:
+        Error(kUnexpectedFileTypeMessage);
+    }
+}
 
-void modelDefaultEntries(void);
+void baseIterDestruct(CdiIterator* me)
+{
+  /*currently empty, but that's no reason not to call it*/
+  (void)me;
+}
 
-#endif
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -32983,342 +32064,394 @@ void modelDefaultEntries(void);
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <limits.h>
 
 
-#undef  UNDEFID
-#define UNDEFID -1
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
 
-static int ECHAM4 = UNDEFID,
-  ECHAM5 = UNDEFID,
-  COSMO  = UNDEFID;
+struct CdiFallbackIterator {
+  CdiIterator super;
+  int streamId, vlistId, subtypeId;
+  char *path;   //needed for clone() & serialize()
 
-typedef struct
+  int variableCount, curVariable;
+  int curLevelCount, curLevel;
+  int curSubtypeCount, curSubtype;
+  int curTimestep;
+};
+
+CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me)
 {
-  int      self;
-  int      used;
-  int      instID;
-  int      modelgribID;
-  char    *name;
+  return &me->super;
 }
-model_t;
 
 
-static int  MODEL_Debug = 0;   /* If set to 1, debugging */
+//For more information on the condestruct() pattern, see comment in src/iterator_grib.c
+static CdiFallbackIterator *cdiFallbackIterator_condestruct(CdiFallbackIterator *me, const char *path, int filetype)
+{
+  if(me) goto destruct;
 
-static void modelInit(void);
+  me = (CdiFallbackIterator *) Malloc(sizeof(*me));
+  baseIterConstruct(&me->super, filetype);
 
+  me->streamId = streamOpenRead(path);
+  if(me->streamId == CDI_UNDEFID) goto destructSuper;
+  me->vlistId = streamInqVlist(me->streamId);
+  if(me->vlistId == CDI_UNDEFID) goto closeStream;
+  me->variableCount = vlistNvars(me->vlistId);
+  if(me->variableCount <= 0) goto closeStream;
+  me->subtypeId = CDI_UNDEFID;   //Will be set in cdiFallbackIterator_nextField()
+  me->curSubtypeCount = -1;      //Will be set in cdiFallbackIterator_nextField()
+  me->curLevelCount = -1;        //Will be set in cdiFallbackIterator_nextField()
 
-static int modelCompareP(void *modelptr1, void *modelptr2);
-static void   modelDestroyP ( void * modelptr );
-static void   modelPrintP   ( void * modelptr, FILE * fp );
-static int    modelGetSizeP ( void * modelptr, void *context);
-static void   modelPackP    ( void * modelptr, void * buff, int size,
-                              int *position, void *context);
-static int    modelTxCode   ( void );
+  //These values are chosen so that the natural increment at the start of cdiFallbackIterator_nextField() will correctly position us at the first slice.
+  me->curTimestep = 0;
+  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
+  me->curVariable = -1;
+  me->curSubtype = -1;
+  me->curLevel = -1;
+  me->path = path ? strdup(path) : NULL;
+  if(!me->path) goto closeStream;
 
-static const resOps modelOps = {
-  modelCompareP,
-  modelDestroyP,
-  modelPrintP,
-  modelGetSizeP,
-  modelPackP,
-  modelTxCode
-};
+  return me;
 
-static
-void modelDefaultValue ( model_t *modelptr )
-{
-  modelptr->self        = UNDEFID;
-  modelptr->used        = 0;
-  modelptr->instID      = UNDEFID;
-  modelptr->modelgribID = UNDEFID;
-  modelptr->name        = NULL;
+// ^        constructor code        ^
+// |                                |
+// v destructor/error-cleanup code  v
+
+destruct:
+  Free(me->path);
+closeStream:
+  streamClose(me->streamId);
+destructSuper:
+  baseIterDestruct(&me->super);
+  Free(me);
+  return NULL;
 }
 
-static model_t *
-modelNewEntry(cdiResH resH, int instID, int modelgribID, const char *name)
+CdiIterator *cdiFallbackIterator_new(const char *path, int filetype)
 {
-  model_t *modelptr;
-
-  modelptr = (model_t *) Malloc(sizeof(model_t));
-  modelDefaultValue ( modelptr );
-  if (resH == CDI_UNDEFID)
-    modelptr->self = reshPut(modelptr, &modelOps);
-  else
-    {
-      modelptr->self = resH;
-      reshReplace(resH, modelptr, &modelOps);
-    }
-  modelptr->used = 1;
-  modelptr->instID = instID;
-  modelptr->modelgribID = modelgribID;
-  if ( name && *name ) modelptr->name = strdupx(name);
-
-  return (modelptr);
+  return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
 }
 
-void modelDefaultEntries ( void )
+//Fetches the info that is derived from the current variable. Most of this is published by the data members in the base class.
+static void fetchVariableInfo(CdiFallbackIterator *me)
 {
-  int instID, i;
-  enum { nDefModels = 10 };
-  cdiResH resH[nDefModels];
-
-  instID  = institutInq(  0,   0, "ECMWF", NULL);
-  /* (void)    modelDef(instID, 131, "ERA15"); */
-  /* (void)    modelDef(instID, 199, "ERA40"); */
-  instID  = institutInq(  0,   0, "MPIMET", NULL);
+  //Fetch data that's published via base class data members.
+  me->super.datatype = vlistInqVarDatatype(me->vlistId, me->curVariable);
+  me->super.timesteptype = vlistInqVarTsteptype(me->vlistId, me->curVariable);
+  me->super.gridId = vlistInqVarGrid(me->vlistId, me->curVariable);
+  int param = vlistInqVarParam(me->vlistId, me->curVariable);
+  cdiDecodeParam(param, &me->super.param.number, &me->super.param.category, &me->super.param.discipline);
 
-  resH[0] = ECHAM5  = modelDef(instID,  64, "ECHAM5.4");
-  resH[1] = modelDef(instID,  63, "ECHAM5.3");
-  resH[2] = modelDef(instID,  62, "ECHAM5.2");
-  resH[3] = modelDef(instID,  61, "ECHAM5.1");
+  //Fetch the current level and subtype counts.
+  me->curLevelCount = zaxisInqSize(vlistInqVarZaxis(me->vlistId, me->curVariable));
+  me->subtypeId = vlistInqVarSubtype(me->vlistId, me->curVariable);
+  me->curSubtypeCount = (me->subtypeId == CDI_UNDEFID) ? 1 : subtypeInqSize(me->subtypeId);
+}
 
-  instID  = institutInq( 98, 255, "MPIMET", NULL);
-  resH[4] = modelDef(instID,  60, "ECHAM5.0");
-  resH[5] = ECHAM4  = modelDef(instID,  50, "ECHAM4");
-  resH[6] = modelDef(instID, 110, "MPIOM1");
+CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
 
-  instID  = institutInq(  0,   0, "DWD", NULL);
-  resH[7] = modelDef(instID, 149, "GME");
+  //Make another stream for this file. This yields an unadvanced iterator.
+  CdiFallbackIterator *clone = cdiFallbackIterator_condestruct(NULL, me->path, me->super.filetype);
+  if(!clone) return NULL;
 
-  instID  = institutInq(  0,   0, "MCH", NULL);
-  //(void)  = modelDef(instID, 137, "COSMO");
-  resH[8] = COSMO   = modelDef(instID, 255, "COSMO");
+  //Point the clone to the same position in the file.
+  clone->variableCount = me->variableCount;
+  clone->curVariable = me->curVariable;
+  clone->curLevelCount = me->curLevelCount;
+  clone->curLevel = me->curLevel;
+  clone->curSubtypeCount = me->curSubtypeCount;
+  clone->curSubtype = me->curSubtype;
+  clone->curTimestep = me->curTimestep;
 
-  instID  = institutInq(  0,   1, "NCEP", NULL);
-  resH[9] = modelDef(instID,  80, "T62L28MRF");
+  clone->super.isAdvanced = super->isAdvanced;
+  if(super->isAdvanced) fetchVariableInfo(clone);
 
-  /* pre-defined models are not synchronized */
-  for ( i = 0; i < nDefModels ; i++ )
-    reshSetStatus(resH[i], &modelOps, RESH_IN_USE);
+  return clone;
 }
 
-static
-void modelInit(void)
+char *cdiFallbackIterator_serialize(CdiIterator *super)
 {
-  static int modelInitialized = 0;
-
-  if (modelInitialized) return;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
 
-  modelInitialized = 1;
-  char *env = getenv("MODEL_DEBUG");
-  if ( env ) MODEL_Debug = atoi(env);
+  char *escapedPath = cdiEscapeSpaces(me->path);
+  char *result = (char *) Malloc(strlen(escapedPath)
+                         + 7 * (3 * sizeof (int) * CHAR_BIT / 8 + 1) + 1);
+  sprintf(result, "%s %d %d %d %d %d %d %d", escapedPath, me->variableCount, me->curVariable, me->curLevelCount, me->curLevel, me->curSubtypeCount, me->curSubtype, me->curTimestep);
+  Free(escapedPath);
+  return result;
 }
 
-struct modelLoc
+CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
 {
-  const char *name;
-  int instID, modelgribID, resID;
-};
+  CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
+  if(!me) goto fail;
 
-static enum cdiApplyRet
-findModelByID(int resID, void *res, void *data)
-{
-  model_t *modelptr = (model_t*) res;
-  struct modelLoc *ret = (struct modelLoc*) data;
-  int instID = ret->instID, modelgribID = ret->modelgribID;
-  if (modelptr->used
-      && modelptr->instID == instID
-      && modelptr->modelgribID == modelgribID)
-    {
-      ret->resID = resID;
-      return CDI_APPLY_STOP;
-    }
-  else
-    return CDI_APPLY_GO_ON;
+  description = baseIter_constructFromString(&me->super, description);
+
+  while(*description == ' ') description++;
+  me->path = cdiUnescapeSpaces(description, &description);
+  if(!me->path) goto destructSuper;
+
+  me->streamId = streamOpenRead(me->path);
+  if(me->streamId == CDI_UNDEFID) goto freePath;
+  me->vlistId = streamInqVlist(me->streamId);
+  if(me->vlistId == CDI_UNDEFID) goto closeStream;
+
+  //This reads one variable from the description string, does error checking, and advances the given string pointer.
+#define decodeValue(variable, description) do \
+    { \
+      const char *savedStart = description; \
+      long long decodedValue = strtoll(description, (char**)&description, 0);   /*The cast is a workaround for the wrong signature of strtoll().*/ \
+      variable = (int)decodedValue; \
+      if(savedStart == description) goto closeStream; \
+      if((long long)decodedValue != (long long)variable) goto closeStream; \
+    } while(0)
+  decodeValue(me->variableCount, description);
+  decodeValue(me->curVariable, description);
+  decodeValue(me->curLevelCount, description);
+  decodeValue(me->curLevel, description);
+  decodeValue(me->curSubtypeCount, description);
+  decodeValue(me->curSubtype, description);
+  decodeValue(me->curTimestep, description);
+#undef decodeValue
+
+  if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) goto closeStream;
+  if(me->super.isAdvanced) fetchVariableInfo(me);
+
+  return me;
+
+closeStream:
+  streamClose(me->streamId);
+freePath:
+  Free(me->path);
+destructSuper:
+  baseIterDestruct(&me->super);
+  Free(me);
+fail:
+  return NULL;
 }
 
-static enum cdiApplyRet
-findModelByName(int resID, void *res, void *data)
+static int advance(CdiFallbackIterator *me)
 {
-  model_t *modelptr = (model_t*) res;
-  struct modelLoc *ret = (struct modelLoc*) data;
-  int instID = ret->instID, modelgribID = ret->modelgribID;
-  const char *name = ret->name;
-  if (modelptr->used
-      && (instID == -1 || modelptr->instID == instID)
-      && (modelgribID == 0 || modelptr->modelgribID == modelgribID)
-      && modelptr->name)
+  me->curLevel++;
+  if(me->curLevel >= me->curLevelCount)
     {
-      const char *p = name, *q = modelptr->name;
-      while (*p != '\0' && *p == *q)
-        ++p, ++q;
-      if (*p == '\0' || *q == '\0')
+      me->curLevel = 0;
+      me->curSubtype++;
+      if(me->curSubtype >= me->curSubtypeCount)
         {
-          ret->resID = resID;
-          return CDI_APPLY_STOP;
+          me->curSubtype = 0;
+          me->curVariable++;
+          if(me->curVariable >= me->variableCount)
+            {
+              me->curVariable = 0;
+              me->curTimestep++;
+              if(streamInqTimestep(me->streamId, me->curTimestep) <= 0) return CDI_EEOF;
+            }
         }
     }
-  return CDI_APPLY_GO_ON;
+  return CDI_NOERR;
 }
 
-int modelInq(int instID, int modelgribID, const char *name)
+int cdiFallbackIterator_nextField(CdiIterator *super)
 {
-  modelInit ();
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  int result = advance(me);
+  if(result) return result;
 
-  struct modelLoc searchState = { .name = name, .instID = instID,
-                                  .modelgribID = modelgribID,
-                                  .resID = UNDEFID };
-  if (name && *name)
-    cdiResHFilterApply(&modelOps, findModelByName, &searchState);
-  else
-    cdiResHFilterApply(&modelOps, findModelByID, &searchState);
-  return searchState.resID;
+  if(!me->curLevel && !me->curSubtype) fetchVariableInfo(me);   //Check whether we are processing a new variable/timestep and fetch the information that may have changed in this case.
+  return CDI_NOERR;
 }
 
-
-int modelDef(int instID, int modelgribID, const char *name)
+char *cdiFallbackIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
 {
-  model_t *modelptr;
-
-  modelInit ();
-
-  modelptr = modelNewEntry(CDI_UNDEFID, instID, modelgribID, name);
-
-  return modelptr->self;
-}
+  CdiFallbackIterator *me = (CdiFallbackIterator *)(void *)super;
 
+  //retrieve the time information
+  int taxisId = vlistInqTaxis(me->vlistId);
+  int date = 0, time = 0;
+  switch(timeType)
+    {
+      case kCdiTimeType_referenceTime:
+        date = taxisInqRdate(taxisId);
+        time = taxisInqRtime(taxisId);
+        break;
 
-int modelInqInstitut(int modelID)
-{
-  model_t *modelptr = NULL;
+      case kCdiTimeType_startTime:
+        date = taxisInqVdate(taxisId);
+        time = taxisInqVtime(taxisId);
+        break;
 
-  modelInit ();
+      case kCdiTimeType_endTime:
+        return NULL;   //The stream interface does not export the start/end times of statistical fields, so we treat all data as point of time data, returning the validity time as the start time.
 
-  if ( modelID != UNDEFID )
-    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
+      default:
+        assert(0 && "internal error, please report this bug");
+    }
 
-  return modelptr ? modelptr->instID : UNDEFID;
+  //decode the time information and reencode it into an ISO-compliant string
+  int year, month, day, hour, minute, second;
+  cdiDecodeDate(date, &year, &month, &day);
+  cdiDecodeTime(time, &hour, &minute, &second);
+  char *result
+    = (char *) Malloc(   4+1 +2+1 +2+1 +2+1 +2+1 +2+4+1);
+  sprintf(result,     "%04d-%02d-%02dT%02d:%02d:%02d.000", year, month, day, hour, minute, second);
+  return result;
 }
 
-
-int modelInqGribID(int modelID)
+int cdiFallbackIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
 {
-  model_t *modelptr = NULL;
-
-  modelInit ();
-
-  if ( modelID != UNDEFID )
-    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
-
-  return modelptr ? modelptr->modelgribID : UNDEFID;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
+  (void)levelSelector;
+#define copyString(outPointer, function) do \
+    { \
+      if(outPointer) \
+        { \
+          char tempBuffer[CDI_MAX_NAME]; \
+          function(zaxisId, tempBuffer); \
+          *outPointer = strdup(tempBuffer); \
+        } \
+    } \
+  while(0)
+  copyString(outName, zaxisInqName);    //FIXME: zaxisInqName is unsafe.
+  copyString(outLongName, zaxisInqLongname);    //FIXME: zaxisInqLongname is unsafe.
+  copyString(outStdName, zaxisInqStdname);    //FIXME: zaxisInqStdname is unsafe.
+  copyString(outUnit, zaxisInqUnits);    //FIXME: zaxisInqUnits is unsafe.
+#undef copyString
+  return zaxisInqLtype(zaxisId);
 }
 
-
-const char *modelInqNamePtr(int modelID)
+int cdiFallbackIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
 {
-  model_t *modelptr = NULL;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
 
-  modelInit ();
+  //handle NULL pointers once and for all
+  double trash;
+  if(!outValue1) outValue1 = &trash;
+  if(!outValue2) outValue2 = &trash;
 
-  if ( modelID != UNDEFID )
-    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
+  //get the level value
+  if(levelSelector)
+    {
+      *outValue1 = (zaxisInqLbounds(zaxisId, NULL))
+                 ? zaxisInqLbound(zaxisId, me->curLevel)
+                 : zaxisInqLevel(zaxisId, me->curLevel);
+    }
+  else
+    {
+      *outValue1 = (zaxisInqUbounds(zaxisId, NULL))
+                 ? zaxisInqUbound(zaxisId, me->curLevel)
+                 : zaxisInqLevel(zaxisId, me->curLevel);
+    }
+  *outValue2 = 0.0;
 
-  return modelptr ? modelptr->name : NULL;
+  //if this is a hybrid zaxis, lookup the coordinates in the vertical coordinate table
+  ssize_t intLevel = (ssize_t)(2**outValue1);
+  if(0 <= intLevel && intLevel < zaxisInqVctSize(zaxisId) - 1)
+    {
+      const double *coordinateTable = zaxisInqVctPtr(zaxisId);
+      *outValue1 = coordinateTable[intLevel];
+      *outValue2 = coordinateTable[intLevel + 1];
+    }
+  return CDI_NOERR;
 }
 
-
-static int
-modelCompareP(void *modelptr1, void *modelptr2)
+int cdiFallbackIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
 {
-  model_t *model1 = (model_t *)modelptr1, *model2 = (model_t *)modelptr2;
-  int diff = (namespaceResHDecode(model1->instID).idx
-              != namespaceResHDecode(model2->instID).idx)
-    | (model1->modelgribID != model2->modelgribID)
-    | (strcmp(model1->name, model2->name) != 0);
-  return diff;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  int zaxisId = vlistInqVarZaxis(me->vlistId, me->curVariable);
+  if(zaxisInqLtype(zaxisId) != ZAXIS_HYBRID) return CDI_EINVAL;
+  if(outVgridNumber) *outVgridNumber = zaxisInqNumber(zaxisId);
+  if(outLevelCount) *outLevelCount = zaxisInqNlevRef(zaxisId);
+  if(outUuid) zaxisInqUUID(zaxisId, outUuid);
+  return CDI_NOERR;
 }
 
-
-void modelDestroyP ( void * modelptr )
+int cdiFallbackIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
 {
-  model_t *mp = (model_t*) modelptr;
-  if (mp->name)
-    Free(mp->name);
-  Free(mp);
-}
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileIndex) outTileIndex = &(int){0};
+  if(!outTileAttribute) outTileAttribute = &(int){0};
+#else
+  int dummy = 0;
+  if(!outTileIndex) outTileIndex = &dummy;
+  if(!outTileAttribute) outTileAttribute = &dummy;
+#endif
 
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileIndex", outTileIndex)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "tileAttribute", outTileAttribute)) error = CDI_EINVAL;
+    }
+  if(error) *outTileIndex = *outTileAttribute = -1; //Guarantee defined values in case of an error.
+  return error;
+}
 
-void modelPrintP   ( void * modelptr, FILE * fp )
+int cdiFallbackIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
 {
-  model_t *mp = (model_t*) modelptr;
-
-  if ( !mp ) return;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+#ifndef __cplusplus
+  if(!outTileCount) outTileCount = &(int){0};
+  if(!outTileAttributeCount) outTileAttributeCount = &(int){0};
+#else
+  int temp = 0;
+  if(!outTileCount) outTileCount = &temp;
+  if(!outTileAttributeCount) outTileAttributeCount = &temp;
+#endif
 
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "# modelID %d\n", mp->self);
-  fprintf ( fp, "#\n");
-  fprintf ( fp, "self          = %d\n", mp->self );
-  fprintf ( fp, "used          = %d\n", mp->used );
-  fprintf ( fp, "instID        = %d\n", mp->instID );
-  fprintf ( fp, "modelgribID   = %d\n", mp->modelgribID );
-  fprintf ( fp, "name          = %s\n", mp->name ? mp->name : "NN" );
+  int error = CDI_NOERR;
+  if(me->subtypeId == CDI_UNDEFID)	//must not call subtypeInqAttribute() with an invalid subtype ID, because it would abort the program instead of returning an error
+    {
+      error = CDI_EINVAL;
+    }
+  else
+    {
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTiles", outTileCount)) error = CDI_EINVAL;
+      if(subtypeInqAttribute(me->subtypeId, me->curSubtype, "numberOfTileAttributes", outTileAttributeCount)) error = CDI_EINVAL;
+    }
+  if(error) *outTileCount = *outTileAttributeCount = -1; //Guarantee defined values in case of an error.
+  return CDI_NOERR;
 }
 
-
-static int
-modelTxCode ( void )
+char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
 {
-  return MODEL;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  return vlistCopyVarName(me->vlistId, me->curVariable);
 }
 
-enum {
-  model_nints = 4,
-};
-
-
-static int modelGetSizeP(void * modelptr, void *context)
+void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
 {
-  model_t *p = (model_t*)modelptr;
-  size_t txsize = (size_t)serializeGetSize(model_nints, DATATYPE_INT, context)
-    + (size_t)serializeGetSize(p->name?(int)strlen(p->name) + 1:0, DATATYPE_TXT, context);
-  xassert(txsize <= INT_MAX);
-  return (int)txsize;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  size_t missingValues = 0;
+  streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
+  if(nmiss) *nmiss = (size_t)missingValues;
 }
 
-
-static void modelPackP(void * modelptr, void * buf, int size, int *position, void *context)
+void cdiFallbackIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
 {
-  model_t *p = (model_t*) modelptr;
-  int tempbuf[model_nints];
-  tempbuf[0] = p->self;
-  tempbuf[1] = p->instID;
-  tempbuf[2] = p->modelgribID;
-  tempbuf[3] = p->name ? (int)strlen(p->name) + 1 : 0;
-  serializePack(tempbuf, model_nints, DATATYPE_INT, buf, size, position, context);
-  if (p->name)
-    serializePack(p->name, tempbuf[3], DATATYPE_TXT, buf, size, position, context);
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  size_t missingValues = 0;
+  streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
+  if(nmiss) *nmiss = (size_t)missingValues;
 }
 
-int
-modelUnpack(void *buf, int size, int *position, int originNamespace, void *context,
-            int force_id)
+void cdiFallbackIterator_delete(CdiIterator *super)
 {
-  int tempbuf[model_nints];
-  char *name;
-  serializeUnpack(buf, size, position, tempbuf, model_nints, DATATYPE_INT, context);
-  if (tempbuf[3] != 0)
-    {
-      name = (char *) Malloc((size_t)tempbuf[3]);
-      serializeUnpack(buf, size, position,
-                      name, tempbuf[3], DATATYPE_TXT, context);
-    }
-  else
-    {
-      name = (char*)"";
-    }
-  int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
-  model_t *mp = modelNewEntry(force_id?targetID:CDI_UNDEFID,
-                              namespaceAdaptKey(tempbuf[1], originNamespace),
-                              tempbuf[2], name);
-  if (tempbuf[3] != 0)
-    Free(name);
-  xassert(!force_id
-          || (mp->self == namespaceAdaptKey(tempbuf[0], originNamespace)));
-  reshSetStatus(mp->self, &modelOps,
-                reshGetStatus(mp->self, &modelOps) & ~RESH_SYNC_BIT);
-  return mp->self;
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
+  cdiFallbackIterator_condestruct(me, NULL, 0);
 }
 
 /*
@@ -33330,1248 +32463,1499 @@ modelUnpack(void *buf, int size, int *position, int originNamespace, void *conte
  * require-trailing-newline: t
  * End:
  */
-#if defined (HAVE_CONFIG_H)
-#endif
+#ifndef _STREAM_GRB_H
+#define _STREAM_GRB_H
 
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
-#endif
+static inline bool gribbyte_get_bit(int number, int bit) { return (bool)((number >> (8-bit)) & 1); }
+static inline void gribbyte_set_bit(int *number, int bit) { *number |= 1 << (8-bit); }
+static inline void gribbyte_clear_bit(int *number, int bit) { *number &= ~(1 << (8-bit)); }
 
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.h>
+int   grbBitsPerValue(int datatype);
 
+int   grbInqContents(stream_t *streamptr);
+int   grbInqTimestep(stream_t *streamptr, int tsID);
 
-static unsigned nNamespaces = 1;
-static int activeNamespace = 0;
+int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void  grbDefRecord(stream_t *streamptr);
+void  grb_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
+void  grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
+void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-#ifdef HAVE_LIBNETCDF
-#define CDI_NETCDF_SWITCHES                     \
-  { .func = (void (*)()) nc__create },          \
-  { .func = (void (*)()) cdf_def_var_serial },  \
-  { .func = (void (*)()) cdfDefTimestep },      \
-  { .func = (void (*)()) cdfDefVars }
+void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
+void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
 
-#else
-#define CDI_NETCDF_SWITCHES
-#endif
+void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
+void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
 
-#define defaultSwitches {                                   \
-    { .func = (void (*)()) cdiAbortC_serial },              \
-    { .func = (void (*)()) cdiWarning },                    \
-    { .func = (void (*)()) serializeGetSizeInCore },        \
-    { .func = (void (*)()) serializePackInCore },           \
-    { .func = (void (*)()) serializeUnpackInCore },         \
-    { .func = (void (*)()) fileOpen_serial },               \
-    { .func = (void (*)()) fileWrite },                     \
-    { .func = (void (*)()) fileClose_serial },              \
-    { .func = (void (*)()) cdiStreamOpenDefaultDelegate },  \
-    { .func = (void (*)()) cdiStreamDefVlist_ },            \
-    { .func = (void (*)()) cdiStreamSetupVlist_ },          \
-    { .func = (void (*)()) cdiStreamWriteVar_ },            \
-    { .func = (void (*)()) cdiStreamWriteVarChunk_ },       \
-    { .func = (void (*)()) 0 },                             \
-    { .func = (void (*)()) 0 },                             \
-    { .func = (void (*)()) cdiStreamCloseDefaultDelegate }, \
-    { .func = (void (*)()) cdiStreamDefTimestep_ }, \
-    { .func = (void (*)()) cdiStreamSync_ },                \
-    CDI_NETCDF_SWITCHES                        \
-    }
+int   grib1ltypeToZaxisType(int grib_ltype);
+int   grib2ltypeToZaxisType(int grib_ltype);
 
-#if defined (SX) || defined (__cplusplus)
-static const union namespaceSwitchValue
-  defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
-#endif
+int   zaxisTypeToGrib1ltype(int zaxistype);
+int   zaxisTypeToGrib2ltype(int zaxistype);
 
-enum namespaceStatus {
-  NAMESPACE_STATUS_INUSE,
-  NAMESPACE_STATUS_UNUSED,
+struct cdiGribParamChange
+{
+  int code, ltype, lev;
+  bool active;
 };
 
-static struct Namespace
+struct cdiGribModeChange
 {
-  enum namespaceStatus resStage;
-  union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
-} initialNamespace = {
-  .resStage = NAMESPACE_STATUS_INUSE,
-  .switches = defaultSwitches
+  bool mode;
+  bool active;
+};
+
+struct cdiGribScanModeChange
+{
+  int value;
+  bool active;
 };
 
-static struct Namespace *namespaces = &initialNamespace;
+extern struct cdiGribParamChange cdiGribChangeParameterID;
+extern struct cdiGribModeChange cdiGribChangeModeUvRelativeToGrid;
+extern struct cdiGribScanModeChange cdiGribDataScanningMode;
+
+// Used in CDO
+void streamGrbChangeParameterIdentification(int code, int ltype, int lev);
+void streamGrbChangeModeUvRelativeToGrid(int mode);
+void streamGrbDefDataScanningMode(int scanmode);
+int  streamGrbInqDataScanningMode(void);
+
+#endif  /* _STREAM_GRB_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _ZAXIS_H
+#define _ZAXIS_H
+
+
+typedef struct {
+  double value;
+  bool defined;
+}
+zkey_double_t;
+
+typedef struct {
+  char     dimname[CDI_MAX_NAME];
+  char     vdimname[CDI_MAX_NAME];
+  char     name[CDI_MAX_NAME];
+  char     longname[CDI_MAX_NAME];
+  char     stdname[CDI_MAX_NAME];
+  char     units[CDI_MAX_NAME];
+  char     psname[CDI_MAX_NAME];
+  char     p0name[CDI_MAX_NAME];
+  zkey_double_t p0value;
+  double  *vals;
+  char   **cvals;
+  int      clength;
+  double  *lbounds;
+  double  *ubounds;
+  double  *weights;
+  int      self;
+  int      datatype;
+  int      scalar;
+  int      type;
+  int      ltype;    /* GRIB level type */
+  int      ltype2;
+  int      size;
+  int      direction;
+  int      vctsize;
+  unsigned positive;
+  double  *vct;
+  int      number;   /* Reference number to a generalized Z-axis */
+  int      nhlev;
+  unsigned char uuid[CDI_UUID_SIZE];
+  cdi_atts_t atts;
+}
+zaxis_t;
+
 
-static unsigned namespacesSize = 1;
+void zaxisGetTypeDescription(int zaxisType, int* outPositive, const char** outName, const char** outLongName, const char** outStdName, const char** outUnit);  //The returned const char* point to static storage. Don't free or modify them.
 
-#if  defined  (HAVE_LIBPTHREAD)
-#  include <pthread.h>
+unsigned cdiZaxisCount(void);
 
-static pthread_once_t  namespaceOnce = PTHREAD_ONCE_INIT;
-static pthread_mutex_t namespaceMutex;
+zaxis_t *zaxis_to_pointer(int zaxisID);
 
-static void
-namespaceInitialize(void)
-{
-  pthread_mutexattr_t ma;
-  pthread_mutexattr_init(&ma);
-  pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
-  pthread_mutex_init(&namespaceMutex, &ma);
-  pthread_mutexattr_destroy(&ma);
-}
+void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
 
-#  define NAMESPACE_LOCK()         pthread_mutex_lock(&namespaceMutex)
-#  define NAMESPACE_UNLOCK()       pthread_mutex_unlock(&namespaceMutex)
-#  define NAMESPACE_INIT()         pthread_once(&namespaceOnce, \
-                                                namespaceInitialize)
+void
+zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
+            int * unpackBufferPos, int originNamespace, void *context,
+            int force_id);
 
+void zaxisDefLtype2(int zaxisID, int ltype2);
 
-#else
+const resOps *getZaxisOps(void);
 
-#  define NAMESPACE_INIT() do { } while (0)
-#  define NAMESPACE_LOCK()
-#  define NAMESPACE_UNLOCK()
+const char *zaxisInqNamePtr(int zaxisID);
+
+const double *zaxisInqLevelsPtr(int zaxisID);
+char **zaxisInqCValsPtr(int zaxisID);
+
+void zaxisResize(int zaxisID, int size);
 
 #endif
 
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-enum {
-  intbits = sizeof(int) * CHAR_BIT,
-  nspbits = 4,
-  idxbits = intbits - nspbits,
-  nspmask = (int)((( (unsigned)1 << nspbits ) - 1) << idxbits),
-  idxmask = ( 1 << idxbits ) - 1,
-};
 
-enum {
-  NUM_NAMESPACES = 1 << nspbits,
-  NUM_IDX = 1 << idxbits,
-};
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
 
 
-int namespaceIdxEncode ( namespaceTuple_t tin )
+#ifdef HAVE_LIBGRIB_API
+
+struct CdiGribIterator {
+  CdiIterator super;
+
+  CdiInputFile *file;
+  off_t fileOffset;
+  unsigned char *gribBuffer;
+  size_t bufferSize, curRecordSize;
+  grib_handle *gribHandle;
+};
+
+CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
 {
-  xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
-  return ( tin.nsp << idxbits ) + tin.idx;
+  return &me->super;
 }
 
-int namespaceIdxEncode2 ( int nsp, int idx )
+//Since the error handling in constructors is usually very closely related to the workings of a destructor,
+//this function combines both functions in one, using a centralized exit.
+//The mode of operation depends on whether me is a NULL pointer on entry:
+//If it is NULL, a new object is allocated and constructed, which is returned if construction is successful.
+//If a non-NULL pointer is passed in, the object is destructed and NULL is returned. In this case, the other arguments are ignored.
+static CdiGribIterator *cdiGribIterator_condestruct(CdiGribIterator *me, const char *path, int filetype)
 {
-  xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
-  return ( nsp << idxbits ) + idx;
-}
+#define super() (&me->super)
+  if(me) goto destruct;
+  me = (CdiGribIterator *) Malloc(sizeof(*me));
+  baseIterConstruct(super(), filetype);
+
+  me->file = cdiInputFile_make(path);
+  if(!me->file) goto destructSuper;
+  me->fileOffset = 0;
+  me->gribHandle = NULL;
+  me->gribBuffer = NULL;
+  me->bufferSize = me->curRecordSize = 0;
+  me->super.gridId = CDI_UNDEFID;
 
+  goto success;
 
-namespaceTuple_t namespaceResHDecode ( int resH )
-{
-  namespaceTuple_t tin;
+// ^        constructor code        ^
+// |                                |
+// v destructor/error-cleanup code  v
 
-  tin.idx = resH & idxmask;
-  tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
+destruct:
+  if(me->super.gridId != CDI_UNDEFID) gridDestroy(me->super.gridId);
+  if(me->gribHandle) grib_handle_delete((struct grib_handle *)me->gribHandle);
+  Free(me->gribBuffer);
+  cdiRefObject_release(&me->file->super);
+destructSuper:
+  baseIterDestruct(super());
+  Free(me);
+  me = NULL;
 
-  return tin;
+success:
+  return me;
+#undef super
 }
 
-int
-namespaceNew()
+CdiIterator *cdiGribIterator_new(const char *path, int filetype)
 {
-  int newNamespaceID = -1;
-  NAMESPACE_INIT();
-  NAMESPACE_LOCK();
-  if (namespacesSize > nNamespaces)
-    {
-      /* namespace is already available and only needs reinitialization */
-      for (unsigned i = 0; i < namespacesSize; ++i)
-        if (namespaces[i].resStage == NAMESPACE_STATUS_UNUSED)
-          {
-            newNamespaceID = (int)i;
-            break;
-          }
-    }
-  else if (namespacesSize == 1)
+  return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
+}
+
+CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
+{
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+
+  //Allocate memory and copy data. (operations that may fail)
+  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
+  if(!result) goto fail;
+
+  result->file = me->file;
+  result->fileOffset = me->fileOffset;
+  result->gribBuffer = NULL;
+  result->bufferSize = me->bufferSize;
+  result->curRecordSize = me->curRecordSize;
+  result->gribHandle = NULL;
+
+  if(me->gribBuffer)
     {
-      /* make room for additional namespace */
-      struct Namespace *newNameSpaces
-        = (struct Namespace *) Malloc(((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
-      memcpy(newNameSpaces, namespaces, sizeof (namespaces[0]));
-      namespaces = newNameSpaces;
-      ++namespacesSize;
-      newNamespaceID = 1;
+      result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
+      if(!result->gribBuffer) goto freeResult;
+      memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
     }
-  else if (namespacesSize < NUM_NAMESPACES)
+  if(me->gribHandle)
     {
-      /* make room for additional namespace */
-      newNamespaceID = (int)namespacesSize;
-      namespaces
-        = (struct Namespace *) Realloc(namespaces, ((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
-      ++namespacesSize;
+      result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
+      if(!result->gribHandle) goto freeBuffer;
     }
-  else /* implicit: namespacesSize >= NUM_NAMESPACES */
+  if(super->gridId != CDI_UNDEFID)
     {
-      NAMESPACE_UNLOCK();
-      return -1;
+      result->super.gridId = gridDuplicate(super->gridId);
+      if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
     }
-  xassert(newNamespaceID >= 0 && newNamespaceID < NUM_NAMESPACES);
-  ++nNamespaces;
-  namespaces[newNamespaceID].resStage = NAMESPACE_STATUS_INUSE;
-#if defined (SX) || defined (__cplusplus)
-  memcpy(namespaces[newNamespaceID].switches,
-         defaultSwitches_,
-         sizeof (namespaces[newNamespaceID].switches));
-#else
-    memcpy(namespaces[newNamespaceID].switches,
-           (union namespaceSwitchValue[NUM_NAMESPACE_SWITCH])defaultSwitches,
-           sizeof (namespaces[newNamespaceID].switches));
-#endif
-  reshListCreate(newNamespaceID);
-  NAMESPACE_UNLOCK();
-  return newNamespaceID;
-}
-
-void
-namespaceDelete(int namespaceID)
-{
-  NAMESPACE_INIT();
-  NAMESPACE_LOCK();
-  xassert(namespaceID >= 0 && (unsigned)namespaceID < namespacesSize
-          && nNamespaces);
-  reshListDestruct(namespaceID);
-  namespaces[namespaceID].resStage = NAMESPACE_STATUS_UNUSED;
-  --nNamespaces;
-  NAMESPACE_UNLOCK();
-}
-
-int namespaceGetNumber ()
-{
-  return (int)nNamespaces;
-}
 
+  //Finish construction. (operations that cannot fail)
+  baseIterConstruct(&result->super, super->filetype);
+  result->super.datatype = super->datatype;
+  result->super.timesteptype = super->timesteptype;
+  result->super.param = super->param;
+  cdiRefObject_retain(&result->file->super);
 
-void namespaceSetActive ( int nId )
-{
-  xassert((unsigned)nId < namespacesSize
-          && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
-  activeNamespace = nId;
-}
-
+  return result;
 
-int namespaceGetActive ()
-{
-  return activeNamespace;
+  //Error handling.
+deleteGribHandle:
+  if(result->gribHandle) grib_handle_delete(result->gribHandle);
+freeBuffer:
+  Free(result->gribBuffer);
+freeResult:
+  Free(result);
+fail:
+  return NULL;
 }
 
-int namespaceAdaptKey ( int originResH, int originNamespace )
+char *cdiGribIterator_serialize(CdiIterator *super)
 {
-  namespaceTuple_t tin;
-  int nsp;
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
 
-  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
+  const char *path = cdiInputFile_getPath(me->file);
+  char *escapedPath = cdiEscapeSpaces(path);
+  char *result = (char *) Malloc(strlen(escapedPath) + 3 * sizeof(int) * CHAR_BIT/8);
+  sprintf(result, "%s %zu", escapedPath, (size_t)me->fileOffset);
+  Free(escapedPath);
+  return result;
+}
 
-  tin.idx = originResH & idxmask;
-  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
 
-  xassert ( tin.nsp == originNamespace );
+CdiGribIterator *cdiGribIterator_deserialize(const char *description)
+{
+  char *path;
+  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
+  if(!me) goto fail;
 
-  nsp = namespaceGetActive ();
+  description = baseIter_constructFromString(&me->super, description);
 
-  return namespaceIdxEncode2 ( nsp, tin.idx );
-}
+  while(*description == ' ') description++;
+  path = cdiUnescapeSpaces(description, &description);
+  if(!path) goto destructSuper;
 
+  me->file = cdiInputFile_make(path);
+  Free(path);
+  if(!me->file) goto destructSuper;
 
-int namespaceAdaptKey2 ( int originResH )
-{
-  namespaceTuple_t tin;
-  int nsp;
+  {
+    const char *savedStart = description;
+    char *description_ = (char *)description;
+    long long decodedOffset = strtoll(description, &description_, 0);
+    description = description_;
+    me->fileOffset = (off_t)decodedOffset;
+    if(savedStart == description) goto closeFile;
+    if((unsigned long long)decodedOffset > (unsigned long long)me->fileOffset) goto closeFile;
+  }
 
-  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
+  me->gribBuffer = NULL;
+  me->bufferSize = me->curRecordSize = 0;
+  me->gribHandle = NULL;
+  me->super.gridId = CDI_UNDEFID;
+  if(me->super.isAdvanced && cdiGribIterator_nextField(&me->super)) goto closeFile;
 
-  tin.idx = originResH & idxmask;
-  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
+  return me;
 
-  nsp = namespaceGetActive ();
 
-  return namespaceIdxEncode2 ( nsp, tin.idx );
+closeFile:
+  cdiRefObject_release(&me->file->super);
+destructSuper:
+  baseIterDestruct(&me->super);
+  Free(me);
+fail:
+  return NULL;
 }
 
-void namespaceSwitchSet(enum namespaceSwitch sw, union namespaceSwitchValue value)
+static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
 {
-  xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
-  int nsp = namespaceGetActive();
-  namespaces[nsp].switches[sw] = value;
+  if(me->bufferSize < requiredSize)
+    {
+      me->bufferSize *= 2;
+      if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
+      me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
+    }
 }
 
-union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw)
+static bool isGrib1DualLevel(int levelType)
 {
-  xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
-  int nsp = namespaceGetActive();
-  return namespaces[nsp].switches[sw];
+  switch(levelType)
+    {
+      case 101: case 104: case 106: case 108: case 110: case 112:
+      case 114: case 116: case 120: case 121: case 128: case 141:   //This is the complete list after grib_api-1.12.3/definitions/grib1/sections.1.def:106-117:, the code in cdi/src/stream_gribapi.c:grib1GetLevel() seems to be incomplete.
+        return true;
+      default:
+        return false;
+    }
 }
 
-void cdiReset(void)
+static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
 {
-  NAMESPACE_INIT();
-  NAMESPACE_LOCK();
-  for (unsigned namespaceID = 0; namespaceID < namespacesSize; ++namespaceID)
-    if (namespaces[namespaceID].resStage != NAMESPACE_STATUS_UNUSED)
-      namespaceDelete((int)namespaceID);
-  if (namespaces != &initialNamespace)
+  for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
     {
-      Free(namespaces);
-      namespaces = &initialNamespace;
-      namespaces[0].resStage = NAMESPACE_STATUS_UNUSED;
+      currentPosition = (unsigned char *)memchr(currentPosition, 'G', size - (size_t)(currentPosition - data) - 3);      //-3 to ensure that we don't overrun the buffer during the strncmp() call.
+      if(!currentPosition) return NULL;
+      if(!strncmp((const char*)currentPosition, "GRIB", 4)) return currentPosition;
     }
-  namespacesSize = 1;
-  nNamespaces = 0;
-  NAMESPACE_UNLOCK();
+  return NULL;
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-
-
-void cdiRefObject_construct(CdiReferencedObject* me)
+//This clobbers the contents of the gribBuffer!
+//Returns the file offset of the next 'GRIB' marker.
+static ssize_t scanToGribMarker(CdiGribIterator *me)
 {
-  me->destructor = cdiRefObject_destruct;
-  me->refCount = 1;
-}
+  cdiGribIterator_ensureBuffer(me, 8*1024);
+  const size_t kMaxScanSize = 16*1024*1024;
+  for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
+    {
+      //Load a chunk of data into our buffer.
+      scanSize = me->bufferSize;
+      if(scannedBytes + scanSize > kMaxScanSize) scanSize = kMaxScanSize - scannedBytes;
+      assert(scanSize <= me->bufferSize);
+      int status = cdiInputFile_read(me->file, me->fileOffset + (off_t)scannedBytes, scanSize, &scanSize, me->gribBuffer);
+      if(status != CDI_NOERR && status != CDI_EEOF) return -1;
 
-void cdiRefObject_retain(CdiReferencedObject* me)
-{
-  size_t oldCount = me->refCount++;
-  xassert(oldCount && "A reference counted object was used after it was destructed.");
-}
+      const unsigned char *startPosition = positionOfGribMarker(me->gribBuffer, scanSize);
+      if(startPosition)
+        {
+          return (ssize_t)(me->fileOffset + (off_t)scannedBytes + (off_t)(startPosition - me->gribBuffer));
+        }
 
-void cdiRefObject_release(CdiReferencedObject* me)
-{
-  size_t oldCount = me->refCount--;
-  xassert(oldCount && "A reference counted object was released too often.");
-  if(oldCount == 1)
-    {
-      me->destructor(me);
-      Free(me);
+      //Get the offset for the next iteration if there is a next iteration.
+      scanSize -= 3;        //so that we won't miss a 'GRIB' sequence that happens to be cut off
+      scanSize &= ~(size_t)0xf; //make 16 bytes aligned
+      if((ssize_t)scanSize <= 0) return -1; //ensure that we make progress
     }
+  return -1;
 }
 
-void cdiRefObject_destruct(CdiReferencedObject* me)
+static unsigned decode24(void *beData)
 {
-  (void)me;
-  /* Empty for now, but that's no reason not to call it! */
+  unsigned char *bytes = (unsigned char *)beData;
+  return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <assert.h>
-
-#if defined (HAVE_EXECINFO_H)
-#include <execinfo.h>
-#endif
-
-static
-void show_stackframe()
+static uint64_t decode64(void *beData)
 {
-#if defined HAVE_EXECINFO_H && defined backtrace_size_t && defined HAVE_BACKTRACE
-  void *trace[16];
-  backtrace_size_t trace_size = backtrace(trace, 16);
-  char **messages = backtrace_symbols(trace, trace_size);
-
-  fprintf(stderr, "[bt] Execution path:\n");
-  if ( messages ) {
-    for ( backtrace_size_t i = 0; i < trace_size; ++i )
-      fprintf(stderr, "[bt] %s\n", messages[i]);
-    free(messages);
-  }
-#endif
+  unsigned char *bytes = (unsigned char *)beData;
+  uint64_t result = 0;
+  for(size_t i = 0; i < 8; i++) result = (result << 8) + bytes[i];
+  return result;
 }
 
+//Determine the size of the GRIB record that begins at the given file offset.
+static int getRecordSize(CdiGribIterator *me, off_t gribFileOffset, size_t *outRecordSize)
+{
+  char buffer[16];
+  size_t readSize;
+  int status = cdiInputFile_read(me->file, gribFileOffset, sizeof(buffer), &readSize, buffer);
+  if(status != CDI_NOERR && status != CDI_EEOF) return status;
+  if(readSize < sizeof(buffer)) return CDI_EEOF;
+  *outRecordSize = 0;
+  switch(buffer[7])
+    {
+      case 1:
+        *outRecordSize = decode24(&buffer[4]);
+        if(*outRecordSize & (1 << 23))
+          {
+            *outRecordSize = 120*(*outRecordSize & ((1 << 23) - 1));    //Rescaling for long records.
+            //The corresponding code in cgribexlib.c:4532-4570: is much more complicated
+            //due to the fact that it subtracts the padding bytes that are inserted after section 4.
+            //However, we are only interested in the total size of data we need to read here,
+            //so we can ignore the presence of some padding bytes.
+          }
+        return CDI_NOERR;
 
-enum { MIN_LIST_SIZE = 128 };
-
-static void listInitialize(void);
+      case 2:
+        *outRecordSize =  decode64(&buffer[8]);
+        return CDI_NOERR;
 
-typedef struct listElem {
-  union
-  {
-    /* free-list management data */
-    struct
-    {
-      int next, prev;
-    } free;
-    /* holding an actual value */
-    struct
-    {
-      const resOps *ops;
-      void         *val;//ptr
-    } v;
-  } res;
-  int           status;
-} listElem_t;
+      default:
+        return CDI_EUFTYPE;
+    }
+}
 
-struct resHList_t
+#if 0
+static void hexdump(void *data, size_t size)
 {
-  int size, freeHead, hasDefaultRes;
-  listElem_t *resources;
-};
-
-static struct resHList_t *resHList;
+  unsigned char *charData = data;
+  for(size_t offset = 0; offset < size; )
+    {
+      printf("%016zx:", offset);
+      for(size_t i = 0; i < 64 && offset < size; i++, offset++)
+        {
+          if((i & 63) && !(i & 15)) printf(" |");
+          if((i & 15) && !(i & 3)) printf("  ");
+          printf(" %02x", charData[offset]);
+        }
+      printf("\n");
+    }
+}
+#endif
 
-static int resHListSize = 0;
+//Read a record into memory and wrap it in a grib_handle.
+//XXX: I have omitted checking for szip compression as it is done in grbReadVarDP() & friends since that appears to be a non-standard extension of the GRIB1 standard: bit 1 in octet 14 of the binary data section which is used to signal szip compressio is defined to be reserved in the standard. As such, it seems prudent not to support this and to encourage people with such szip compressed files to switch to the GRIB2/JPEG2000 format. However, in the case that this reasoning is wrong, this [...]
+static int readMessage(CdiGribIterator *me)
+{
+  //Destroy the old grib_handle.
+  if(me->gribHandle) grib_handle_delete(me->gribHandle), me->gribHandle = NULL;
+  me->fileOffset += (off_t)me->curRecordSize;
 
-#if  defined  (HAVE_LIBPTHREAD)
-#  include <pthread.h>
+  //Find the next record and determine its size.
+  ssize_t gribFileOffset = scanToGribMarker(me);
+  int result = CDI_EEOF;
+  if(gribFileOffset < 0) goto fail;
+  result = getRecordSize(me, gribFileOffset, &me->curRecordSize);
+  if(result) goto fail;
 
-static pthread_once_t  listInitThread = PTHREAD_ONCE_INIT;
-static pthread_mutex_t listMutex;
+  //Load the whole record into our buffer and create a grib_handle for it.
+  cdiGribIterator_ensureBuffer(me, me->curRecordSize);
+  result = cdiInputFile_read(me->file, gribFileOffset, me->curRecordSize, NULL, me->gribBuffer);
+  if(result) goto fail;
+  me->gribHandle = grib_handle_new_from_message(NULL, me->gribBuffer, me->curRecordSize);
+  result = CDI_EUFSTRUCT;
+  if(!me->gribHandle) goto fail;
 
-#  define LIST_LOCK()         pthread_mutex_lock(&listMutex)
-#  define LIST_UNLOCK()       pthread_mutex_unlock(&listMutex)
-#  define LIST_INIT(init0)         do {                         \
-    pthread_once(&listInitThread, listInitialize);              \
-    pthread_mutex_lock(&listMutex);                             \
-    if ((init0) && (!resHList || !resHList[0].resources))       \
-      reshListCreate(0);                                        \
-    pthread_mutex_unlock(&listMutex);                           \
-  } while (0)
+  return CDI_NOERR;
 
+fail:
+  me->curRecordSize = 0;        //This ensures that we won't jump to an uncontrolled file position if cdiGribIterator_nextField() is called another time after it has returned an error.
+  return result;
+}
 
+int cdiGribIterator_nextField(CdiIterator *super)
+{
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
 
-#else
+  if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;
 
-static int listInit = 0;
+  //Get the next GRIB message into our buffer.
+  int result = readMessage(me);
+  if(result) return result;
 
-#  define LIST_LOCK()
-#  define LIST_UNLOCK()
-#  define LIST_INIT(init0)        do {                          \
-  if ( !listInit )                                              \
-    {                                                           \
-      listInitialize();                                         \
-      if ((init0) && (!resHList || !resHList[0].resources))     \
-        reshListCreate(0);                                      \
-      listInit = 1;                                             \
-    }                                                           \
-  } while(0)
+  //Get the metadata that's published as variables in the base class.
+  super->datatype = gribGetDatatype(me->gribHandle);
+  super->timesteptype = gribapiGetTsteptype(me->gribHandle);
+  cdiDecodeParam(gribapiGetParam(me->gribHandle), &super->param.number, &super->param.category, &super->param.discipline);
+  grid_t grid;
+  gribapiGetGrid(me->gribHandle, &grid);
+  super->gridId = gridGenerate(&grid);
 
-#endif
+  return CDI_NOERR;
+}
 
-/**************************************************************/
+char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
+{
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+  return gribMakeTimeString(me->gribHandle, timeType);
+}
 
-static void
-listInitResources(int nsp)
+int cdiGribIterator_levelType(CdiIterator *super, int levelSelector, char **outName, char **outLongName, char **outStdName, char **outUnit)
 {
-  xassert(nsp < resHListSize && nsp >= 0);
-  int size = resHList[nsp].size = MIN_LIST_SIZE;
-  xassert(resHList[nsp].resources == NULL);
-  resHList[nsp].resources = (listElem_t*) Calloc(MIN_LIST_SIZE, sizeof(listElem_t));
-  listElem_t *p = resHList[nsp].resources;
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
 
-  for (int i = 0; i < size; i++ )
+  //First determine the zaxis type corresponding to the given level.
+  int zaxisType = ZAXIS_GENERIC;
+  if(gribEditionNumber(me->gribHandle) <= 1)
     {
-      p[i].res.free.next = i + 1;
-      p[i].res.free.prev = i - 1;
-      p[i].status = RESH_UNUSED;
+      int levelType = (int)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", 255);
+      if(levelSelector && !isGrib1DualLevel(levelType)) levelType = 255;
+      zaxisType = grib1ltypeToZaxisType(levelType);
+    }
+  else
+    {
+      int levelType = (int)gribGetLongDefault(me->gribHandle, levelSelector ? "typeOfSecondFixedSurface" : "typeOfFirstFixedSurface", 255);
+      zaxisType = grib2ltypeToZaxisType(levelType);
     }
 
-  p[size-1].res.free.next = -1;
-  resHList[nsp].freeHead = 0;
-  int oldNsp = namespaceGetActive();
-  namespaceSetActive(nsp);
-  instituteDefaultEntries();
-  modelDefaultEntries();
-  namespaceSetActive(oldNsp);
-}
+  //Then lookup the requested names.
+  const char *name, *longName, *stdName, *unit;
+  zaxisGetTypeDescription(zaxisType, NULL, &name, &longName, &stdName, &unit);
+  if(outName) *outName = strdup(name);
+  if(outLongName) *outLongName = strdup(longName);
+  if(outStdName) *outStdName = strdup(stdName);
+  if(outUnit) *outUnit = strdup(unit);
 
-static inline void
-reshListClearEntry(int i)
-{
-  resHList[i].size = 0;
-  resHList[i].resources = NULL;
-  resHList[i].freeHead = -1;
+  return zaxisType;
 }
 
-void
-reshListCreate(int namespaceID)
+static double logicalLevelValue2(long gribType, long storedValue, long power)
 {
-  LIST_INIT(namespaceID != 0);
-  LIST_LOCK();
-  if (resHListSize <= namespaceID)
+  double factor = 1;
+  assert(power >= 0);
+  while(power--) factor *= 10;      //this is precise up to factor == 22.
+  switch(gribType)
     {
-      resHList = (struct resHList_t *) Realloc(resHList, (size_t)(namespaceID + 1) * sizeof (resHList[0]));
-      for (int i = resHListSize; i <= namespaceID; ++i)
-        reshListClearEntry(i);
-      resHListSize = namespaceID + 1;
-    }
-  listInitResources(namespaceID);
-  LIST_UNLOCK();
-}
+      case GRIB2_LTYPE_LANDDEPTH:
+      case GRIB2_LTYPE_ISOBARIC:
+      case GRIB2_LTYPE_SIGMA:
+        return (double)storedValue * (1000.0/factor);      //The evaluation order allows the factors of ten to cancel out before rounding.
 
+      case 255:
+        return 0;
 
-/**************************************************************/
+      default:
+        return (double)storedValue/factor;
+    }
+}
 
-void
-reshListDestruct(int namespaceID)
+//The output values must be preinitialized, this function does not always write them.
+static int readLevel2(grib_handle *gribHandle, const char *levelTypeKey, const char *powerKey, const char *valueKey, double *outValue1, double *outValue2)
 {
-  LIST_LOCK();
-  xassert(resHList && namespaceID >= 0 && namespaceID < resHListSize);
-  int callerNamespaceID = namespaceGetActive();
-  namespaceSetActive(namespaceID);
-  if (resHList[namespaceID].resources)
+  assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);
+
+  long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
+  switch(levelType)
     {
-      for ( int j = 0; j < resHList[namespaceID].size; j++ )
+      case 255: break;
+
+      case 105: case 113:
         {
-          listElem_t *listElem = resHList[namespaceID].resources + j;
-          if (listElem->status & RESH_IN_USE_BIT)
-            listElem->res.v.ops->valDestroy(listElem->res.v.val);
+          unsigned long value = (unsigned long)gribGetLongDefault(gribHandle, valueKey, 0);
+          unsigned long coordinateCount = (unsigned long)gribGetLongDefault(gribHandle, "numberOfCoordinatesValues", 0);
+          if(value >= coordinateCount/2)
+            {
+              Error("Invalid level coordinate: Level has the hybrid coordinate index %lu, but only %lu coordinate pairs are present.", value, coordinateCount/2);
+              return CDI_EUFSTRUCT;
+            }
+          int status;
+          //XXX: I'm not 100% sure about how the coordinate pairs are stored in the file.
+          //     I'm assuming an array of pairs due to the example code in grib_api-1.12.3/examples/F90/set_pv.f90, but that may be wrong.
+          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2    , outValue1))) return status;
+          if((status = grib_get_double_element(gribHandle, "pv", (int)value*2 + 1, outValue2))) return status;
+          break;
+        }
+
+      default:
+        {
+          long power = 255 & gribGetLongDefault(gribHandle, powerKey, 0);  //1 byte
+          if(power == 255) power = 0;
+          long value = gribGetLongDefault(gribHandle, valueKey, 0);   //4 bytes
+          *outValue1 = logicalLevelValue2(levelType, value, power);
         }
-      Free(resHList[namespaceID].resources);
-      resHList[namespaceID].resources = NULL;
-      reshListClearEntry(namespaceID);
     }
-  if (resHList[callerNamespaceID].resources)
-    namespaceSetActive(callerNamespaceID);
-  LIST_UNLOCK();
+  return CDI_NOERR;
 }
 
-
-static void listDestroy ( void )
+int cdiGribIterator_level(CdiIterator *super, int levelSelector, double *outValue1, double *outValue2)
 {
-  LIST_LOCK();
-  for (int i = resHListSize; i > 0; --i)
-    if (resHList[i-1].resources)
-      namespaceDelete(i-1);
-  resHListSize = 0;
-  Free(resHList);
-  resHList = NULL;
-  cdiReset();
-  LIST_UNLOCK();
-}
-
-/**************************************************************/
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+  double trash;
+  if(!outValue1) outValue1 = &trash;
+  if(!outValue2) outValue2 = &trash;
+  *outValue1 = *outValue2 = 0;
 
-static
-void listInitialize ( void )
-{
-#if  defined  (HAVE_LIBPTHREAD)
-  pthread_mutexattr_t ma;
-  pthread_mutexattr_init(&ma);
-  pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
-  /* initialize global API mutex lock */
-  pthread_mutex_init ( &listMutex, &ma);
-  pthread_mutexattr_destroy(&ma);
-#endif
-  /* file is special and has its own table, which needs to be
-   * created, before we register the listDestroy exit handler */
-  {
-    int null_id;
-    null_id = fileOpen_serial("/dev/null", "r");
-    if (null_id != -1)
-      fileClose_serial(null_id);
-  }
-  atexit ( listDestroy );
+  if(gribEditionNumber(me->gribHandle) > 1)
+    {
+      if(levelSelector)
+        {
+          return readLevel2(me->gribHandle, "typeOfFirstFixedSurface", "scaleFactorOfFirstFixedSurface", "scaledValueOfFirstFixedSurface", outValue1, outValue2);
+        }
+      else
+        {
+          return readLevel2(me->gribHandle, "typeOfSecondFixedSurface", "scaleFactorOfSecondFixedSurface", "scaledValueOfSecondFixedSurface", outValue1, outValue2);
+        }
+    }
+  else
+    {
+      long levelType = (uint8_t)gribGetLongDefault(me->gribHandle, "indicatorOfTypeOfLevel", -1);    //1 byte
+      if(levelType == 255)
+        {}
+      else if(isGrib1DualLevel((int)levelType))
+        {
+          *outValue1 = (double)(gribGetLongDefault(me->gribHandle, (levelSelector ? "bottomLevel" : "topLevel"), 0));
+        }
+      else if(levelType == 100)
+        {
+          *outValue1 = 100 * (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
+        }
+      else
+        {
+          *outValue1 = (double)(gribGetLongDefault(me->gribHandle, "level", 0));        //2 bytes
+        }
+    }
+  return CDI_NOERR;
 }
 
-/**************************************************************/
-
-static
-void listSizeExtend()
+int cdiGribIterator_zaxisUuid(CdiIterator *super, int *outVgridNumber, int *outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
 {
-  int nsp = namespaceGetActive ();
-  int oldSize = resHList[nsp].size;
-  size_t newListSize = (size_t)oldSize + MIN_LIST_SIZE;
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
 
-  resHList[nsp].resources = (listElem_t*) Realloc(resHList[nsp].resources,
-                                                   newListSize * sizeof(listElem_t));
-
-  listElem_t *r = resHList[nsp].resources;
-  for (size_t i = (size_t)oldSize; i < newListSize; ++i)
+  if(outVgridNumber)
     {
-      r[i].res.free.next = (int)i + 1;
-      r[i].res.free.prev = (int)i - 1;
-      r[i].status = RESH_UNUSED;
+      long temp;
+      if(grib_get_long(me->gribHandle, "numberOfVGridUsed", &temp)) return CDI_EINVAL;
+      *outVgridNumber = (int)temp;
+    }
+  if(outLevelCount)
+    {
+      long temp;
+      if(grib_get_long(me->gribHandle, "nlev", &temp)) return CDI_EINVAL;
+      *outLevelCount = (int)temp;
+    }
+  if(outUuid)
+    {
+      size_t size = CDI_UUID_SIZE;
+      if(grib_get_bytes(me->gribHandle, "uuidOfVGrid", outUuid, &size)) return CDI_EINVAL;
+      if(size != CDI_UUID_SIZE) return CDI_EUFSTRUCT;
     }
 
-  if (resHList[nsp].freeHead != -1)
-    r[resHList[nsp].freeHead].res.free.prev = (int)newListSize - 1;
-  r[newListSize-1].res.free.next = resHList[nsp].freeHead;
-  r[oldSize].res.free.prev = -1;
-  resHList[nsp].freeHead = oldSize;
-  resHList[nsp].size = (int)newListSize;
+  return CDI_NOERR;
 }
 
-/**************************************************************/
-
-static void
-reshPut_(int nsp, int entry, void *p, const resOps *ops)
+int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
 {
-  listElem_t *newListElem = resHList[nsp].resources + entry;
-  int next = newListElem->res.free.next,
-    prev = newListElem->res.free.prev;
-  if (next != -1)
-    resHList[nsp].resources[next].res.free.prev = prev;
-  if (prev != -1)
-    resHList[nsp].resources[prev].res.free.next = next;
-  else
-    resHList[nsp].freeHead = next;
-  newListElem->res.v.val = p;
-  newListElem->res.v.ops = ops;
-  newListElem->status = RESH_DESYNC_IN_USE;
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+  int trash;
+  if(!outTileIndex) outTileIndex = &trash;
+  if(!outTileAttribute) outTileAttribute = &trash;
+
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "tileIndex", &value)) error = CDI_EINVAL;
+  *outTileIndex = (int)value;
+  if(grib_get_long(me->gribHandle, "tileAttribute", &value)) error = CDI_EINVAL;
+  *outTileAttribute = (int)value;
+
+  //Ensure defined return values in case of failure.
+  if(error) *outTileIndex = *outTileAttribute = -1;
+  return error;
 }
 
-int reshPut ( void *p, const resOps *ops )
+int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
 {
-  xassert ( p && ops );
-
-  LIST_INIT(1);
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+  int trash;
+  if(!outTileCount) outTileCount = &trash;
+  if(!outTileAttributeCount) outTileAttributeCount = &trash;
 
-  LIST_LOCK();
+  //Get the values if possible.
+  int error = CDI_NOERR;
+  long value;
+  if(grib_get_long(me->gribHandle, "numberOfTiles", &value)) error = CDI_EINVAL;
+  *outTileCount = (int)value;
+  if(grib_get_long(me->gribHandle, "numberOfTileAttributes", &value)) error = CDI_EINVAL;
+  *outTileAttributeCount = (int)value;
 
-  int nsp = namespaceGetActive ();
+  //Ensure defined return values in case of failure.
+  if(error) *outTileCount = *outTileAttributeCount = 0;
+  return error;
+}
 
-  if ( resHList[nsp].freeHead == -1) listSizeExtend();
-  int entry = resHList[nsp].freeHead;
-  cdiResH resH = namespaceIdxEncode2(nsp, entry);
-  reshPut_(nsp, entry, p, ops);
+char *cdiGribIterator_copyVariableName(CdiIterator *super)
+{
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+  return gribCopyString(me->gribHandle, "shortName");
+}
 
-  LIST_UNLOCK();
+void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
+{
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
 
-  return resH;
+  GRIB_CHECK(my_grib_set_double(me->gribHandle, "missingValue", cdiDefaultMissval), 0);
+  gribGetDoubleArray(me->gribHandle, "values", buffer);
+  long gridType = gribGetLong(me->gribHandle, "gridDefinitionTemplateNumber");
+  if(nmiss)
+    {
+      *nmiss = (gridType >= 50 && gridType <= 53) ? (size_t)0 : (size_t)gribGetLong(me->gribHandle, "numberOfMissing");        //The condition excludes harmonic data.
+    }
 }
 
-/**************************************************************/
-
-static void
-reshRemove_(int nsp, int idx)
+void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
 {
-  int curFree = resHList[nsp].freeHead;
-  listElem_t *r = resHList[nsp].resources;
-  r[idx].res.free.next = curFree;
-  r[idx].res.free.prev = -1;
-  if (curFree != -1)
-    r[curFree].res.free.prev = idx;
-  r[idx].status = RESH_DESYNC_DELETED;
-  resHList[nsp].freeHead = idx;
+  CdiGribIterator *me = (CdiGribIterator*)(void *)super;
+
+  size_t valueCount = gribGetArraySize(me->gribHandle, "values");
+  double *temp = (double *) Malloc(valueCount*sizeof(*temp));
+  cdiGribIterator_readField(super, temp, nmiss);
+  for(size_t i = valueCount; i--; ) buffer[i] = (float)temp[i];
+  Free(temp);
 }
+#endif
 
-void reshDestroy(cdiResH resH)
+/*
+ at Function cdiGribIterator_delete
+ at Title Dispose off a CdiGribIterator instance.
+
+ at Prototype void cdiGribIterator_delete(CdiGribIterator *me)
+ at Parameter
+    @item me The iterator to delete.
+
+ at Description
+    Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
+*/
+void cdiGribIterator_delete(CdiGribIterator *me)
 {
-  int nsp;
-  namespaceTuple_t nspT;
+#ifdef HAVE_LIBGRIB_API
+  if(me) cdiGribIterator_condestruct(me, NULL, 0);
+#else
+  if (me)
+    xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+#endif
+}
 
-  LIST_LOCK();
 
-  nsp = namespaceGetActive ();
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// callthroughs to provide direct access to the grib keys //////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
 
-  nspT = namespaceResHDecode ( resH );
+/*
+ at Function cdiGribIterator_inqEdition
+ at Title Get the version of the GRIB standard that is used
 
-  xassert ( nspT.nsp == nsp
-            && nspT.idx >= 0
-            && nspT.idx < resHList[nsp].size
-            && resHList[nsp].resources[nspT.idx].res.v.ops);
+ at Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
+ at Parameter
+    @item me The iterator to operate on.
 
-  if (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
-    reshRemove_(nsp, nspT.idx);
+ at Result The GRIB version.
 
-  LIST_UNLOCK();
+ at Description
+    Returns the version of the file format.
+*/
+int cdiGribIterator_inqEdition(CdiGribIterator *me)
+{
+#ifdef HAVE_LIBGRIB_API
+  return (int)gribEditionNumber(me->gribHandle);
+#else
+  (void)me;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
-void reshRemove ( cdiResH resH, const resOps * ops )
+/*
+ at Function cdiGribIterator_getLong
+ at Title Access to grib_get_long()
+
+ at Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
+
+ at Result An error code.
+
+ at Description
+    Callthrough to grib_get_long().
+*/
+int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
 {
-  int nsp;
-  namespaceTuple_t nspT;
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_long(me->gribHandle, key, result);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  LIST_LOCK();
+/*
+ at Function cdiGribIterator_getLength
+ at Title Access to grib_get_length()
 
-  nsp = namespaceGetActive ();
+ at Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
-  nspT = namespaceResHDecode ( resH );
+ at Result An error code.
 
-  xassert ( nspT.nsp == nsp
-            && nspT.idx >= 0
-            && nspT.idx < resHList[nsp].size
-            && (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
-            && resHList[nsp].resources[nspT.idx].res.v.ops
-            && resHList[nsp].resources[nspT.idx].res.v.ops == ops );
+ at Description
+    Callthrough to grib_get_length().
+*/
+int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+{
+#ifdef HAVE_GRIB_GET_LENGTH
+  return grib_get_length(me->gribHandle, key, result);
+#elif defined(HAVE_LIBGRIB_API)
+  (void)me;
+  (void)key;
+  (void)result;
+  Error("grib_get_length() is not available, so cdiGribIterator_getLength() can't be used");
+  return -1;
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  reshRemove_(nsp, nspT.idx);
+/*
+ at Function cdiGribIterator_getString
+ at Title Access to grib_get_string()
 
-  LIST_UNLOCK();
-}
+ at Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
-/**************************************************************/
+ at Result An error code.
 
-void reshReplace(cdiResH resH, void *p, const resOps *ops)
+ at Description
+    Callthrough to grib_get_string().
+*/
+int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
 {
-  xassert(p && ops);
-  LIST_INIT(1);
-  LIST_LOCK();
-  int nsp = namespaceGetActive();
-  namespaceTuple_t nspT = namespaceResHDecode(resH);
-  while (resHList[nsp].size <= nspT.idx)
-    listSizeExtend();
-  listElem_t *q = resHList[nsp].resources + nspT.idx;
-  if (q->status & RESH_IN_USE_BIT)
-    {
-      q->res.v.ops->valDestroy(q->res.v.val);
-      reshRemove_(nsp, nspT.idx);
-    }
-  reshPut_(nsp, nspT.idx, p, ops);
-  LIST_UNLOCK();
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_string(me->gribHandle, key, result, length);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  (void)length;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
+/*
+ at Function cdiGribIterator_inqLongValue
+ at Title Get the value of a GRIB-API key as a long
 
-static listElem_t *
-reshGetElem(const char *caller, const char* expressionString, cdiResH resH, const resOps *ops)
-{
-  listElem_t *listElem;
-  int nsp;
-  namespaceTuple_t nspT;
-  xassert ( ops );
+ at Prototype long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
+ at Parameter
+    @item me The iterator to operate on.
+    @item key The GRIB-API key to retrieve.
 
-  LIST_INIT(1);
+ at Result The value of the key.
 
-  LIST_LOCK();
+ at Description
+    Use this to fetch a grib value if you are certain that the given key must be present.
+    This will abort the process if the key cannot be retrieved.
+*/
+long cdiGribIterator_inqLongValue(CdiGribIterator *me, const char *key)
+{
+#ifdef HAVE_LIBGRIB_API
+  return gribGetLong(me->gribHandle, key);
+#else
+  (void)me;
+  (void)key;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  nsp = namespaceGetActive ();
+/*
+ at Function cdiGribIterator_inqLongDefaultValue
+ at Title Get the value of a GRIB-API key as a long
 
-  nspT = namespaceResHDecode ( resH );
-  assert(nspT.idx >= 0);
+ at Prototype long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
+ at Parameter
+    @item me The iterator to operate on.
+    @item key The GRIB-API key to retrieve.
+    @item defaultValue The value to return if the key is not present.
 
-  if (nspT.nsp == nsp &&
-      nspT.idx < resHList[nsp].size)
-    {
-      listElem = resHList[nsp].resources + nspT.idx;
-      LIST_UNLOCK();
-    }
-  else
-    {
-      LIST_UNLOCK();
-      show_stackframe();
+ at Result The value of the key or the given default value.
 
-      if ( resH == CDI_UNDEFID )
-        {
-          xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is CDI_UNDEFID (= %d).\n\tThis is most likely the result of a failed earlier call. Please check the IDs returned by CDI.", expressionString, caller, resH);
-        }
-      else
-        {
-          xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is garbage (= %d, which resolves to namespace = %d, index = %d).\n\tThis is either the result of using an uninitialized variable,\n\tof using a value as an ID that is not an ID,\n\tor of using an ID after it has been invalidated.", expressionString, caller, resH, nspT.nsp, nspT.idx);
-        }
-    }
+ at Description
+    Use this if you can handle failure to fetch the key by supplying a default value.
+    This function cannot fail.
+*/
+long cdiGribIterator_inqLongDefaultValue(CdiGribIterator *me, const char *key, long defaultValue)
+{
+#ifdef HAVE_LIBGRIB_API
+  return gribGetLongDefault(me->gribHandle, key, defaultValue);
+#else
+  (void)me;
+  (void)key;
+  (void)defaultValue;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  if ( !(listElem && listElem->res.v.ops == ops) )
-    {
-      show_stackframe();
+/*
+ at Function cdiGribIterator_inqStringValue
+ at Title Safely retrieve a GRIB-API key with a string value
 
-      xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: list element not found. The failed ID is %d", expressionString, caller, (int)resH);
-    }
+ at Prototype char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
+ at Parameter
+    @item me The iterator to operate on.
+    @item key The GRIB-API key to retrieve.
 
-  return listElem;
-}
+ at Result A malloc'ed string or NULL.
 
-void *reshGetValue(const char * caller, const char* expressionString, cdiResH resH, const resOps * ops)
+ at Description
+    This will first call grib_get_length() to inquire the actual size of the string,
+    allocate memory accordingly, call grib_get_string(), and return the pointer to the new string.
+    Returns NULL on failure.
+*/
+char *cdiGribIterator_inqStringValue(CdiGribIterator *me, const char *key)
 {
-  return reshGetElem(caller, expressionString, resH, ops)->res.v.val;
+#ifdef HAVE_LIBGRIB_API
+  return gribCopyString(me->gribHandle, key);
+#else
+  (void)me;
+  (void)key;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return NULL;
+#endif
 }
 
-/**************************************************************/
-
-void reshGetResHListOfType(unsigned numIDs, int resHs[], const resOps *ops)
-{
-  xassert ( resHs && ops );
-
-  LIST_INIT(1);
+/*
+ at Function cdiGribIterator_getDouble
+ at Title Access to grib_get_double()
 
-  LIST_LOCK();
+ at Prototype int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
-  int nsp = namespaceGetActive();
-  unsigned j = 0;
-  for (int i = 0; i < resHList[nsp].size && j < numIDs; i++ )
-    if ((resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
-        && resHList[nsp].resources[i].res.v.ops == ops)
-      resHs[j++] = namespaceIdxEncode2(nsp, i);
+ at Result An error code.
 
-  LIST_UNLOCK();
+ at Description
+    Callthrough to grib_get_double().
+*/
+int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
+{
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_double(me->gribHandle, key, result);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
-enum cdiApplyRet
-cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
-                                      void *data), void *data)
-{
-  xassert(func);
+/*
+ at Function cdiGribIterator_getSize
+ at Title Access to grib_get_size()
 
-  LIST_INIT(1);
+ at Prototype int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
-  LIST_LOCK();
+ at Result An error code.
 
-  int nsp = namespaceGetActive ();
-  enum cdiApplyRet ret = CDI_APPLY_GO_ON;
-  for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
-    if (resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
-      ret = func(namespaceIdxEncode2(nsp, i),
-                 resHList[nsp].resources[i].res.v.val,
-                 resHList[nsp].resources[i].res.v.ops, data);
-  LIST_UNLOCK();
-  return ret;
+ at Description
+    Callthrough to grib_get_size().
+*/
+int cdiGribIterator_getSize(CdiGribIterator *me, const char *key, size_t *result)
+{
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_size(me->gribHandle, key, result);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
+/*
+ at Function cdiGribIterator_getLongArray
+ at Title Access to grib_get_long_array()
 
-enum cdiApplyRet
-cdiResHFilterApply(const resOps *p,
-                   enum cdiApplyRet (*func)(int id, void *res, void *data),
-                   void *data)
-{
-  xassert(p && func);
-
-  LIST_INIT(1);
+ at Prototype int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
-  LIST_LOCK();
+ at Result An error code.
 
-  int nsp = namespaceGetActive ();
-  enum cdiApplyRet ret = CDI_APPLY_GO_ON;
-  listElem_t *r = resHList[nsp].resources;
-  for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
-    if ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == p)
-      ret = func(namespaceIdxEncode2(nsp, i), r[i].res.v.val,
-                 data);
-  LIST_UNLOCK();
-  return ret;
+ at Description
+    Callthrough to grib_get_long_array().
+*/
+int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
+{
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_long_array(me->gribHandle, key, result, size);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  (void)size;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
+/*
+ at Function cdiGribIterator_getDoubleArray
+ at Title Access to grib_get_double_array()
 
+ at Prototype int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
+ at Parameter
+    @item me The iterator to operate on.
+    @item ... The arguments to the underlying GRIB-API function.
 
+ at Result An error code.
 
-/**************************************************************/
-
-unsigned reshCountType(const resOps *ops)
+ at Description
+    Callthrough to grib_get_double_array().
+*/
+int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
 {
-  unsigned countType = 0;
-
-  xassert(ops);
+#ifdef HAVE_LIBGRIB_API
+  return grib_get_double_array(me->gribHandle, key, result, size);
+#else
+  (void)me;
+  (void)key;
+  (void)result;
+  (void)size;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  LIST_INIT(1);
+/*
+ at Function cdiGribIterator_inqDoubleValue
+ at Title Get the value of a GRIB-API key as a double
 
-  LIST_LOCK();
+ at Prototype double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
+ at Parameter
+    @item me The iterator to operate on.
+    @item key The GRIB-API key to retrieve.
 
-  int nsp = namespaceGetActive ();
+ at Result The value of the key.
 
-  listElem_t *r = resHList[nsp].resources;
-  size_t len = (size_t)resHList[nsp].size;
-  for (size_t i = 0; i < len; i++ )
-    countType += ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == ops);
+ at Description
+    Use this to fetch a grib value if you are certain that the given key must be present.
+    This will abort the process if the key cannot be retrieved.
+*/
+double cdiGribIterator_inqDoubleValue(CdiGribIterator *me, const char *key)
+{
+#ifdef HAVE_LIBGRIB_API
+  return gribGetDouble(me->gribHandle, key);
+#else
+  (void)me;
+  (void)key;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
+}
 
-  LIST_UNLOCK();
+/*
+ at Function cdiGribIterator_inqDoubleDefaultValue
+ at Title Get the value of a GRIB-API key as a double
 
-  return countType;
-}
+ at Prototype double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
+ at Parameter
+    @item me The iterator to operate on.
+    @item key The GRIB-API key to retrieve.
+    @item defaultValue The value to return if the key is not present.
 
-/**************************************************************/
+ at Result The value of the key or the given default value.
 
-int
-reshResourceGetPackSize_intern(int resH, const resOps *ops, void *context, const char* caller, const char* expressionString)
+ at Description
+    Use this if you can handle failure to fetch the key by supplying a default value.
+    This function cannot fail.
+*/
+double cdiGribIterator_inqDoubleDefaultValue(CdiGribIterator *me, const char *key, double defaultValue)
 {
-  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
-  return curr->res.v.ops->valGetPackSize(curr->res.v.val, context);
+#ifdef HAVE_LIBGRIB_API
+  return gribGetDoubleDefault(me->gribHandle, key, defaultValue);
+#else
+  (void)me;
+  (void)key;
+  (void)defaultValue;
+  xabort("CDI was compiled without GribAPI support, so you can't possibly have a valid CdiGribIterator* to call this function with");
+  return -4;
+#endif
 }
 
-void
-reshPackResource_intern(int resH, const resOps *ops, void *buf, int buf_size, int *position, void *context,
-                        const char* caller, const char* expressionString)
-{
-  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
-  curr->res.v.ops->valPack(curr->res.v.val, buf, buf_size, position, context);
-}
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef MODEL_H
+#define MODEL_H
 
-enum {
-  resHPackHeaderNInt = 2,
-  resHDeleteNInt = 2,
-};
+int
+modelUnpack(void *buf, int size, int *position,
+            int originNamespace, void *context, int force_id);
 
-static int getPackBufferSize(void *context)
-{
-  int intpacksize, packBufferSize = 0;
+void modelDefaultEntries(void);
 
-  int nsp = namespaceGetActive ();
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  /* pack start marker, namespace and sererator marker */
-  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, DATATYPE_INT, context));
+#include <limits.h>
 
-  /* pack resources, type marker and seperator marker */
-  listElem_t *r = resHList[nsp].resources;
-  for ( int i = 0; i < resHList[nsp].size; i++)
-    if (r[i].status & RESH_SYNC_BIT)
-      {
-        if (r[i].status == RESH_DESYNC_DELETED)
-          {
-            packBufferSize += resHDeleteNInt * intpacksize;
-          }
-        else if (r[i].status == RESH_DESYNC_IN_USE)
-          {
-            xassert ( r[i].res.v.ops );
-            /* packed resource plus 1 int for type */
-            packBufferSize +=
-              r[i].res.v.ops->valGetPackSize(r[i].res.v.val, context)
-              + intpacksize;
-          }
-      }
-  /* end marker */
-  packBufferSize += intpacksize;
 
-  return packBufferSize;
-}
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
-/**************************************************************/
+static int ECHAM4 = CDI_UNDEFID,
+  ECHAM5 = CDI_UNDEFID,
+  COSMO  = CDI_UNDEFID;
 
-void reshPackBufferDestroy ( char ** buffer )
+typedef struct
 {
-  if ( buffer ) free ( *buffer );
+  int      self;
+  int      used;
+  int      instID;
+  int      modelgribID;
+  char    *name;
 }
+model_t;
 
-/**************************************************************/
 
-int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
-{
-  int i, packBufferPos = 0;
-  int end = END;
+static int  MODEL_Debug = 0;   /* If set to 1, debugging */
 
-  xassert ( packBuffer );
+static void modelInit(void);
 
-  LIST_LOCK();
 
-  int nsp = namespaceGetActive ();
+static int modelCompareP(void *modelptr1, void *modelptr2);
+static void   modelDestroyP ( void * modelptr );
+static void   modelPrintP   ( void * modelptr, FILE * fp );
+static int    modelGetSizeP ( void * modelptr, void *context);
+static void   modelPackP    ( void * modelptr, void * buff, int size,
+                              int *position, void *context);
+static int    modelTxCode   ( void );
 
-  int pBSize = *packBufferSize = getPackBufferSize(context);
-  char *pB = *packBuffer = (char *) Malloc((size_t)pBSize);
+static const resOps modelOps = {
+  modelCompareP,
+  modelDestroyP,
+  modelPrintP,
+  modelGetSizeP,
+  modelPackP,
+  modelTxCode
+};
 
-  {
-    int header[resHPackHeaderNInt] = { START, nsp };
-    serializePack(header, resHPackHeaderNInt,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
-  }
+static
+void modelDefaultValue ( model_t *modelptr )
+{
+  modelptr->self        = CDI_UNDEFID;
+  modelptr->used        = 0;
+  modelptr->instID      = CDI_UNDEFID;
+  modelptr->modelgribID = CDI_UNDEFID;
+  modelptr->name        = NULL;
+}
 
-  listElem_t *r = resHList[nsp].resources;
-  for ( i = 0; i < resHList[nsp].size; i++ )
-    if (r[i].status & RESH_SYNC_BIT)
-      {
-        if (r[i].status == RESH_DESYNC_DELETED)
-          {
-            int temp[resHDeleteNInt]
-              = { RESH_DELETE, namespaceIdxEncode2(nsp, i) };
-            serializePack(temp, resHDeleteNInt, DATATYPE_INT,
-                          pB, pBSize, &packBufferPos, context);
-          }
-        else
-          {
-            listElem_t * curr = r + i;
-            xassert ( curr->res.v.ops );
-            int type = curr->res.v.ops->valTxCode();
-            if ( ! type ) continue;
-            serializePack(&type, 1, DATATYPE_INT, pB,
-                          pBSize, &packBufferPos, context);
-            curr->res.v.ops->valPack(curr->res.v.val,
-                                     pB, pBSize, &packBufferPos, context);
-          }
-        r[i].status &= ~RESH_SYNC_BIT;
-      }
+static model_t *
+modelNewEntry(cdiResH resH, int instID, int modelgribID, const char *name)
+{
+  model_t *modelptr;
 
-  LIST_UNLOCK();
+  modelptr = (model_t *) Malloc(sizeof(model_t));
+  modelDefaultValue ( modelptr );
+  if (resH == CDI_UNDEFID)
+    modelptr->self = reshPut(modelptr, &modelOps);
+  else
+    {
+      modelptr->self = resH;
+      reshReplace(resH, modelptr, &modelOps);
+    }
+  modelptr->used = 1;
+  modelptr->instID = instID;
+  modelptr->modelgribID = modelgribID;
+  if ( name && *name ) modelptr->name = strdupx(name);
 
-  serializePack(&end, 1,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
-  return packBufferPos;
+  return (modelptr);
 }
 
-/**************************************************************/
-
-/* for thread safety this feature would have to be integrated in reshPut */
-
-void reshSetStatus ( cdiResH resH, const resOps * ops, int status )
+void modelDefaultEntries ( void )
 {
-  int nsp;
-  namespaceTuple_t nspT;
-  listElem_t * listElem;
+  int instID, i;
+  enum { nDefModels = 10 };
+  cdiResH resH[nDefModels];
 
-  xassert((ops != NULL) ^ !(status & RESH_IN_USE_BIT));
+  instID  = institutInq(  0,   0, "ECMWF", NULL);
+  /* (void)    modelDef(instID, 131, "ERA15"); */
+  /* (void)    modelDef(instID, 199, "ERA40"); */
+  instID  = institutInq(  0,   0, "MPIMET", NULL);
 
-  LIST_INIT(1);
+  resH[0] = ECHAM5  = modelDef(instID,  64, "ECHAM5.4");
+  resH[1] = modelDef(instID,  63, "ECHAM5.3");
+  resH[2] = modelDef(instID,  62, "ECHAM5.2");
+  resH[3] = modelDef(instID,  61, "ECHAM5.1");
 
-  LIST_LOCK();
+  instID  = institutInq( 98, 255, "MPIMET", NULL);
+  resH[4] = modelDef(instID,  60, "ECHAM5.0");
+  resH[5] = ECHAM4  = modelDef(instID,  50, "ECHAM4");
+  resH[6] = modelDef(instID, 110, "MPIOM1");
 
-  nsp = namespaceGetActive ();
+  instID  = institutInq(  0,   0, "DWD", NULL);
+  resH[7] = modelDef(instID, 149, "GME");
 
-  nspT = namespaceResHDecode ( resH );
+  instID  = institutInq(  0,   0, "MCH", NULL);
+  //(void)  = modelDef(instID, 137, "COSMO");
+  resH[8] = COSMO   = modelDef(instID, 255, "COSMO");
 
-  xassert ( nspT.nsp == nsp &&
-            nspT.idx >= 0 &&
-            nspT.idx < resHList[nsp].size );
+  instID  = institutInq(  0,   1, "NCEP", NULL);
+  resH[9] = modelDef(instID,  80, "T62L28MRF");
 
-  xassert ( resHList[nsp].resources );
-  listElem = resHList[nsp].resources + nspT.idx;
+  /* pre-defined models are not synchronized */
+  for ( i = 0; i < nDefModels ; i++ )
+    reshSetStatus(resH[i], &modelOps, RESH_IN_USE);
+}
 
-  xassert((!ops || (listElem->res.v.ops == ops))
-          && (listElem->status & RESH_IN_USE_BIT) == (status & RESH_IN_USE_BIT));
+static
+void modelInit(void)
+{
+  static int modelInitialized = 0;
 
-  listElem->status = status;
+  if (modelInitialized) return;
 
-  LIST_UNLOCK();
+  modelInitialized = 1;
+  char *env = getenv("MODEL_DEBUG");
+  if ( env ) MODEL_Debug = atoi(env);
 }
 
-/**************************************************************/
-
-int reshGetStatus ( cdiResH resH, const resOps * ops )
+struct modelLoc
 {
-  int nsp;
-  namespaceTuple_t nspT;
-
-  LIST_INIT(1);
+  const char *name;
+  int instID, modelgribID, resID;
+};
 
-  LIST_LOCK();
+static enum cdiApplyRet
+findModelByID(int resID, void *res, void *data)
+{
+  model_t *modelptr = (model_t*) res;
+  struct modelLoc *ret = (struct modelLoc*) data;
+  int instID = ret->instID, modelgribID = ret->modelgribID;
+  if (modelptr->used
+      && modelptr->instID == instID
+      && modelptr->modelgribID == modelgribID)
+    {
+      ret->resID = resID;
+      return CDI_APPLY_STOP;
+    }
+  else
+    return CDI_APPLY_GO_ON;
+}
 
-  nsp = namespaceGetActive ();
+static enum cdiApplyRet
+findModelByName(int resID, void *res, void *data)
+{
+  model_t *modelptr = (model_t*) res;
+  struct modelLoc *ret = (struct modelLoc*) data;
+  int instID = ret->instID, modelgribID = ret->modelgribID;
+  const char *name = ret->name;
+  if (modelptr->used
+      && (instID == -1 || modelptr->instID == instID)
+      && (modelgribID == 0 || modelptr->modelgribID == modelgribID)
+      && modelptr->name)
+    {
+      const char *p = name, *q = modelptr->name;
+      while (*p != '\0' && *p == *q)
+        ++p, ++q;
+      if (*p == '\0' || *q == '\0')
+        {
+          ret->resID = resID;
+          return CDI_APPLY_STOP;
+        }
+    }
+  return CDI_APPLY_GO_ON;
+}
 
-  nspT = namespaceResHDecode ( resH );
+int modelInq(int instID, int modelgribID, const char *name)
+{
+  modelInit ();
 
-  xassert ( nspT.nsp == nsp &&
-            nspT.idx >= 0 &&
-            nspT.idx < resHList[nsp].size );
+  struct modelLoc searchState = { .name = name, .instID = instID,
+                                  .modelgribID = modelgribID,
+                                  .resID = CDI_UNDEFID };
+  if (name && *name)
+    cdiResHFilterApply(&modelOps, findModelByName, &searchState);
+  else
+    cdiResHFilterApply(&modelOps, findModelByID, &searchState);
+  return searchState.resID;
+}
 
-  listElem_t *listElem = resHList[nsp].resources + nspT.idx;
 
-  const resOps *elemOps = listElem->res.v.ops;
+int modelDef(int instID, int modelgribID, const char *name)
+{
+  model_t *modelptr;
 
-  LIST_UNLOCK();
+  modelInit ();
 
-  xassert(listElem && (!(listElem->status & RESH_IN_USE_BIT) || elemOps == ops));
+  modelptr = modelNewEntry(CDI_UNDEFID, instID, modelgribID, name);
 
-  return listElem->status;
+  return modelptr->self;
 }
 
-/**************************************************************/
 
-void reshLock ()
+int modelInqInstitut(int modelID)
 {
-  LIST_LOCK();
-}
+  model_t *modelptr = NULL;
 
-/**************************************************************/
+  modelInit ();
 
-void reshUnlock ()
-{
-  LIST_UNLOCK();
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
+
+  return modelptr ? modelptr->instID : CDI_UNDEFID;
 }
 
-/**************************************************************/
 
-int reshListCompare ( int nsp0, int nsp1 )
+int modelInqGribID(int modelID)
 {
-  LIST_INIT(1);
-  LIST_LOCK();
-
-  xassert(resHListSize > nsp0 && resHListSize > nsp1 &&
-          nsp0 >= 0 && nsp1 >= 0);
+  model_t *modelptr = NULL;
 
-  int valCompare = 0;
-  int i, listSizeMin = (resHList[nsp0].size <= resHList[nsp1].size)
-    ? resHList[nsp0].size : resHList[nsp1].size;
-  listElem_t *resources0 = resHList[nsp0].resources,
-    *resources1 = resHList[nsp1].resources;
-  for (i = 0; i < listSizeMin; i++)
-    {
-      int occupied0 = (resources0[i].status & RESH_IN_USE_BIT) != 0,
-        occupied1 = (resources1[i].status & RESH_IN_USE_BIT) != 0;
-      /* occupation mismatch ? */
-      int diff = occupied0 ^ occupied1;
-      valCompare |= (diff << cdiResHListOccupationMismatch);
-      if (!diff && occupied0)
-        {
-          /* both occupied, do resource types match? */
-          diff = (resources0[i].res.v.ops != resources1[i].res.v.ops
-                  || resources0[i].res.v.ops == NULL);
-          valCompare |= (diff << cdiResHListResourceTypeMismatch);
-          if (!diff)
-            {
-              /* types match, does content match also? */
-              diff
-                = resources0[i].res.v.ops->valCompare(resources0[i].res.v.val,
-                                                      resources1[i].res.v.val);
-              valCompare |= (diff << cdiResHListResourceContentMismatch);
-            }
-        }
-    }
-  /* find resources in nsp 0 beyond end of nsp 1 */
-  for (int j = listSizeMin; j < resHList[nsp0].size; ++j)
-    valCompare |= (((resources0[j].status & RESH_IN_USE_BIT) != 0)
-                   << cdiResHListOccupationMismatch);
-  /* find resources in nsp 1 beyond end of nsp 0 */
-  for (; i < resHList[nsp1].size; ++i)
-    valCompare |= (((resources1[i].status & RESH_IN_USE_BIT) != 0)
-                   << cdiResHListOccupationMismatch);
+  modelInit ();
 
-  LIST_UNLOCK();
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-  return valCompare;
+  return modelptr ? modelptr->modelgribID : CDI_UNDEFID;
 }
 
-/**************************************************************/
 
-void reshListPrint(FILE *fp)
+const char *modelInqNamePtr(int modelID)
 {
-  int i, j, temp;
-  listElem_t * curr;
-
-  LIST_INIT(1);
-
+  model_t *modelptr = NULL;
 
-  temp = namespaceGetActive ();
+  modelInit ();
 
-  fprintf ( fp, "\n\n##########################################\n#\n#  print " \
-            "global resource list \n#\n" );
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-  for ( i = 0; i < namespaceGetNumber (); i++ )
-    {
-      namespaceSetActive ( i );
+  return modelptr ? modelptr->name : NULL;
+}
 
-      fprintf ( fp, "\n" );
-      fprintf ( fp, "##################################\n" );
-      fprintf ( fp, "#\n" );
-      fprintf ( fp, "# namespace=%d\n", i );
-      fprintf ( fp, "#\n" );
-      fprintf ( fp, "##################################\n\n" );
 
-      fprintf ( fp, "resHList[%d].size=%d\n", i, resHList[i].size );
+static int
+modelCompareP(void *modelptr1, void *modelptr2)
+{
+  model_t *model1 = (model_t *)modelptr1, *model2 = (model_t *)modelptr2;
+  int diff = (namespaceResHDecode(model1->instID).idx
+              != namespaceResHDecode(model2->instID).idx)
+    | (model1->modelgribID != model2->modelgribID)
+    | (strcmp(model1->name, model2->name) != 0);
+  return diff;
+}
 
-      for ( j = 0; j < resHList[i].size; j++ )
-        {
-          curr = resHList[i].resources + j;
-          if (!(curr->status & RESH_IN_USE_BIT))
-            {
-              curr->res.v.ops->valPrint(curr->res.v.val, fp);
-              fprintf ( fp, "\n" );
-            }
-        }
-    }
-  fprintf ( fp, "#\n#  end global resource list" \
-            "\n#\n##########################################\n\n" );
 
-  namespaceSetActive ( temp );
+void modelDestroyP ( void * modelptr )
+{
+  model_t *mp = (model_t*) modelptr;
+  if (mp->name)
+    Free(mp->name);
+  Free(mp);
 }
 
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#include <inttypes.h>
-#include <limits.h>
-#include <string.h>
+void modelPrintP   ( void * modelptr, FILE * fp )
+{
+  model_t *mp = (model_t*) modelptr;
 
+  if ( !mp ) return;
 
-int
-serializeGetSize(int count, int datatype, void *context)
-{
-  int (*serialize_get_size_p)(int count, int datatype, void *context)
-    = (int (*)(int, int, void *))
-    namespaceSwitchGet(NSSWITCH_SERIALIZE_GET_SIZE).func;
-  return serialize_get_size_p(count, datatype, context);
+  fprintf ( fp, "#\n");
+  fprintf ( fp, "# modelID %d\n", mp->self);
+  fprintf ( fp, "#\n");
+  fprintf ( fp, "self          = %d\n", mp->self );
+  fprintf ( fp, "used          = %d\n", mp->used );
+  fprintf ( fp, "instID        = %d\n", mp->instID );
+  fprintf ( fp, "modelgribID   = %d\n", mp->modelgribID );
+  fprintf ( fp, "name          = %s\n", mp->name ? mp->name : "NN" );
 }
 
-void serializePack(const void *data, int count, int datatype,
-                   void *buf, int buf_size, int *position, void *context)
-{
-  void (*serialize_pack_p)(const void *data, int count, int datatype,
-                           void *buf, int buf_size, int *position, void *context)
-    = (void (*)(const void *, int, int, void *, int, int *, void *))
-    namespaceSwitchGet(NSSWITCH_SERIALIZE_PACK).func;
-  serialize_pack_p(data, count, datatype, buf, buf_size, position, context);
-}
 
-void serializeUnpack(const void *buf, int buf_size, int *position,
-                     void *data, int count, int datatype, void *context)
+static int
+modelTxCode ( void )
 {
-  void (*serialize_unpack_p)(const void *buf, int buf_size, int *position,
-                             void *data, int count, int datatype, void *context)
-    = (void (*)(const void *, int, int *, void *, int, int, void *))
-    namespaceSwitchGet(NSSWITCH_SERIALIZE_UNPACK).func;
-  serialize_unpack_p(buf, buf_size, position, data, count, datatype, context);
+  return MODEL;
 }
 
+enum {
+  model_nints = 4,
+};
 
 
-int
-serializeGetSizeInCore(int count, int datatype, void *context)
+static int modelGetSizeP(void * modelptr, void *context)
 {
-  int elemSize;
-  (void)context;
-  switch (datatype)
-  {
-  case DATATYPE_INT8:
-    elemSize = sizeof (int8_t);
-    break;
-  case DATATYPE_INT16:
-    elemSize = sizeof (int16_t);
-    break;
-  case DATATYPE_UINT32:
-    elemSize = sizeof (uint32_t);
-    break;
-  case DATATYPE_INT:
-    elemSize = sizeof (int);
-    break;
-  case DATATYPE_FLT:
-  case DATATYPE_FLT64:
-    elemSize = sizeof (double);
-    break;
-  case DATATYPE_TXT:
-  case DATATYPE_UCHAR:
-    elemSize = 1;
-    break;
-  case DATATYPE_LONG:
-    elemSize = sizeof (long);
-    break;
-  default:
-    xabort("Unexpected datatype");
-  }
-  return count * elemSize;
+  model_t *p = (model_t*)modelptr;
+  size_t txsize = (size_t)serializeGetSize(model_nints, CDI_DATATYPE_INT, context)
+    + (size_t)serializeGetSize(p->name?(int)strlen(p->name) + 1:0, CDI_DATATYPE_TXT, context);
+  xassert(txsize <= INT_MAX);
+  return (int)txsize;
 }
 
-void serializePackInCore(const void *data, int count, int datatype,
-                         void *buf, int buf_size, int *position, void *context)
+
+static void modelPackP(void * modelptr, void * buf, int size, int *position, void *context)
 {
-  int size = serializeGetSize(count, datatype, context);
-  int pos = *position;
-  xassert(INT_MAX - pos >= size && buf_size - pos >= size);
-  memcpy((unsigned char *)buf + pos, data, (size_t)size);
-  pos += size;
-  *position = pos;
+  model_t *p = (model_t*) modelptr;
+  int tempbuf[model_nints];
+  tempbuf[0] = p->self;
+  tempbuf[1] = p->instID;
+  tempbuf[2] = p->modelgribID;
+  tempbuf[3] = p->name ? (int)strlen(p->name) + 1 : 0;
+  serializePack(tempbuf, model_nints, CDI_DATATYPE_INT, buf, size, position, context);
+  if (p->name)
+    serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
 }
 
-void serializeUnpackInCore(const void *buf, int buf_size, int *position,
-                           void *data, int count, int datatype, void *context)
+int
+modelUnpack(void *buf, int size, int *position, int originNamespace, void *context,
+            int force_id)
 {
-  int size = serializeGetSize(count, datatype, context);
-  int pos = *position;
-  xassert(INT_MAX - pos >= size && buf_size - pos >= size);
-  memcpy(data, (unsigned char *)buf + pos, (size_t)size);
-  pos += size;
-  *position = pos;
+  int tempbuf[model_nints];
+  char *name;
+  serializeUnpack(buf, size, position, tempbuf, model_nints, CDI_DATATYPE_INT, context);
+  if (tempbuf[3] != 0)
+    {
+      name = (char *) Malloc((size_t)tempbuf[3]);
+      serializeUnpack(buf, size, position,
+                      name, tempbuf[3], CDI_DATATYPE_TXT, context);
+    }
+  else
+    {
+      name = (char*)"";
+    }
+  int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
+  model_t *mp = modelNewEntry(force_id?targetID:CDI_UNDEFID,
+                              namespaceAdaptKey(tempbuf[1], originNamespace),
+                              tempbuf[2], name);
+  if (tempbuf[3] != 0)
+    Free(name);
+  xassert(!force_id
+          || (mp->self == namespaceAdaptKey(tempbuf[0], originNamespace)));
+  reshSetStatus(mp->self, &modelOps,
+                reshGetStatus(mp->self, &modelOps) & ~RESH_SYNC_BIT);
+  return mp->self;
 }
 
 /*
@@ -34586,10460 +33970,11092 @@ void serializeUnpackInCore(const void *buf, int buf_size, int *position,
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-
-
-
-enum {
-  SRV_HEADER_LEN = 8,
-};
-
-
-static int initSrvLib      = 0;
-static int srvDefaultHprec = 0;
-static int srvDefaultDprec = 0;
-
-
-/*
- * A version string.
- */
-#undef  LIBVERSION
-#define LIBVERSION      1.4.0
-#define XSTRING(x)	#x
-#define STRING(x)	XSTRING(x)
-static const char srv_libvers[] = STRING(LIBVERSION) " of " __DATE__" " __TIME__;
-
-const char *srvLibraryVersion(void)
-{
-  return srv_libvers;
-}
-
-
-static int SRV_Debug = 0;    /* If set to 1, debugging */
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
+#endif
 
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
 
-void srvDebug(int debug)
-{
-  SRV_Debug = debug;
 
-  if ( SRV_Debug )
-    Message("debug level %d", debug);
-}
+static unsigned nNamespaces = 1;
+static int activeNamespace = 0;
 
-static
-void srvLibInit()
-{
-  const char *envName = "SRV_PRECISION";
+#ifdef HAVE_LIBNETCDF
+#define CDI_NETCDF_SWITCHES                     \
+  { .func = (void (*)()) nc__create },          \
+  { .func = (void (*)()) cdf_def_var_serial },  \
+  { .func = (void (*)()) cdfDefTimestep },      \
+  { .func = (void (*)()) cdfDefVars }
 
-  char *envString = getenv(envName);
-  if ( envString )
-    {
-      int nrun;
-      if ( strlen(envString) == 2 ) nrun = 1;
-      else                          nrun = 2;
+#else
+#define CDI_NETCDF_SWITCHES
+#endif
 
-      int pos = 0;
-      while ( nrun-- )
-	{
-	  switch ( tolower((int) envString[pos]) )
-	    {
-	    case 'i':
-	      {
-		switch ( (int) envString[pos+1] )
-		  {
-		  case '4': srvDefaultHprec = EXSE_SINGLE_PRECISION; break;
-		  case '8': srvDefaultHprec = EXSE_DOUBLE_PRECISION; break;
-		  default:
-		    Message("Invalid digit in %s: %s", envName, envString);
-		  }
-		break;
-	      }
-	    case 'r':
-	      {
-		switch ( (int) envString[pos+1] )
-		  {
-		  case '4': srvDefaultDprec = EXSE_SINGLE_PRECISION; break;
-		  case '8': srvDefaultDprec = EXSE_DOUBLE_PRECISION; break;
-		  default:
-		    Message("Invalid digit in %s: %s", envName, envString);
-		  }
-		break;
-	      }
-	    default:
-              {
-                Message("Invalid character in %s: %s", envName, envString);
-                break;
-              }
-            }
-	  pos += 2;
-	}
+#define defaultSwitches {                                   \
+    { .func = (void (*)()) cdiAbortC_serial },              \
+    { .func = (void (*)()) cdiWarning },                    \
+    { .func = (void (*)()) serializeGetSizeInCore },        \
+    { .func = (void (*)()) serializePackInCore },           \
+    { .func = (void (*)()) serializeUnpackInCore },         \
+    { .func = (void (*)()) fileOpen_serial },               \
+    { .func = (void (*)()) fileWrite },                     \
+    { .func = (void (*)()) fileClose_serial },              \
+    { .func = (void (*)()) cdiStreamOpenDefaultDelegate },  \
+    { .func = (void (*)()) cdiStreamDefVlist_ },            \
+    { .func = (void (*)()) cdiStreamSetupVlist_ },          \
+    { .func = (void (*)()) cdiStreamWriteVar_ },            \
+    { .func = (void (*)()) cdiStreamWriteVarChunk_ },       \
+    { .func = (void (*)()) 0 },                             \
+    { .func = (void (*)()) 0 },                             \
+    { .func = (void (*)()) cdiStreamCloseDefaultDelegate }, \
+    { .func = (void (*)()) cdiStreamDefTimestep_ }, \
+    { .func = (void (*)()) cdiStreamSync_ },                \
+    CDI_NETCDF_SWITCHES                        \
     }
 
-  initSrvLib = 1;
-}
-
-static
-void srvInit(srvrec_t *srvp)
-{
-  srvp->checked    = 0;
-  srvp->byteswap   = 0;
-  srvp->hprec      = 0;
-  srvp->dprec      = 0;
-  srvp->datasize   = 0;
-  srvp->buffersize = 0;
-  srvp->buffer     = NULL;
-}
-
+#if defined (SX) || defined (__cplusplus)
+static const union namespaceSwitchValue
+  defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
+#endif
 
-void *srvNew(void)
+enum namespaceStatus {
+  NAMESPACE_STATUS_INUSE,
+  NAMESPACE_STATUS_UNUSED,
+};
+
+static struct Namespace
 {
-  if ( ! initSrvLib ) srvLibInit();
+  enum namespaceStatus resStage;
+  union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
+} initialNamespace = {
+  .resStage = NAMESPACE_STATUS_INUSE,
+  .switches = defaultSwitches
+};
 
-  srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
+static struct Namespace *namespaces = &initialNamespace;
 
-  srvInit(srvp);
+static unsigned namespacesSize = 1;
 
-  return (void*)srvp;
-}
+#if  defined  (HAVE_LIBPTHREAD)
+#  include <pthread.h>
 
+static pthread_once_t  namespaceOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t namespaceMutex;
 
-void srvDelete(void *srv)
+static void
+namespaceInitialize(void)
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-
-  if ( srvp )
-    {
-      if ( srvp->buffer ) Free(srvp->buffer);
-      Free(srvp);
-    }
+  pthread_mutexattr_t ma;
+  pthread_mutexattr_init(&ma);
+  pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
+  pthread_mutex_init(&namespaceMutex, &ma);
+  pthread_mutexattr_destroy(&ma);
 }
 
+#  define NAMESPACE_LOCK()         pthread_mutex_lock(&namespaceMutex)
+#  define NAMESPACE_UNLOCK()       pthread_mutex_unlock(&namespaceMutex)
+#  define NAMESPACE_INIT()         pthread_once(&namespaceOnce, \
+                                                namespaceInitialize)
 
-int srvCheckFiletype(int fileID, int *swap)
-{
-  size_t data = 0;
-  size_t dimx = 0, dimy = 0;
-  size_t fact = 0;
-  int found = 0;
-  unsigned char buffer[72], *pbuf;
 
-  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
+#else
 
-  size_t blocklen  = (size_t) get_UINT32(buffer);
-  size_t sblocklen = (size_t) get_SUINT32(buffer);
+#  define NAMESPACE_INIT() do { } while (0)
+#  define NAMESPACE_LOCK()
+#  define NAMESPACE_UNLOCK()
 
-  if ( SRV_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+#endif
 
-  if ( blocklen == 32 )
-    {
-     *swap = 0;
-      fact = blocklen>>3;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
-      pbuf = buffer+4*fact;      dimx = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+5*fact;      dimy = (size_t) get_UINT32(pbuf);
-      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
-    }
-  else if ( blocklen == 64 )
-    {
-     *swap = 0;
-      fact = blocklen>>3;
-      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
-      pbuf = buffer+4*fact;      dimx = (size_t) get_UINT64(pbuf);
-      pbuf = buffer+5*fact;      dimy = (size_t) get_UINT64(pbuf);
-      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
-    }
-  else if ( sblocklen == 32 )
-    {
-     *swap = 1;
-      fact = sblocklen>>3;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
-      pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT32(pbuf);
-      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
-    }
-  else if ( sblocklen == 64 )
-    {
-     *swap = 1;
-      fact = sblocklen>>3;
-      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
-      pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT64(pbuf);
-      pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT64(pbuf);
-      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
-    }
 
-  fileRewind(fileID);
+enum {
+  intbits = sizeof(int) * CHAR_BIT,
+  nspbits = 4,
+  idxbits = intbits - nspbits,
+  nspmask = (int)((( (unsigned)1 << nspbits ) - 1) << idxbits),
+  idxmask = ( 1 << idxbits ) - 1,
+};
 
-  if      ( data && dimx*dimy*fact == data ) found = 1;
-  else if ( data && dimx*dimy*8    == data ) found = 1;
+enum {
+  NUM_NAMESPACES = 1 << nspbits,
+  NUM_IDX = 1 << idxbits,
+};
 
-  if ( SRV_Debug )
-    {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
-    }
 
-  return found;
+int namespaceIdxEncode ( namespaceTuple_t tin )
+{
+  xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
+  return ( tin.nsp << idxbits ) + tin.idx;
 }
 
-
-int srvInqHeader(void *srv, int *header)
+int namespaceIdxEncode2 ( int nsp, int idx )
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-
-  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
-    header[i] = srvp->header[i];
-
-  if ( SRV_Debug )
-    Message("datasize = %lu", srvp->datasize);
-
-  return 0;
+  xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
+  return ( nsp << idxbits ) + idx;
 }
 
 
-int srvDefHeader(void *srv, const int *header)
+namespaceTuple_t namespaceResHDecode ( int resH )
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-
-  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
-    srvp->header[i] = header[i];
-
-  srvp->datasize = (size_t)(header[4] * header[5]);
+  namespaceTuple_t tin;
 
-  if ( SRV_Debug )
-    Message("datasize = %lu", srvp->datasize);
+  tin.idx = resH & idxmask;
+  tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
 
-  return 0;
+  return tin;
 }
 
-static
-int srvInqData(srvrec_t *srvp, int prec, void *data)
+int
+namespaceNew()
 {
-  size_t i;
-  int ierr = 0;
-  int byteswap = srvp->byteswap;
-  size_t datasize = srvp->datasize;
-  void *buffer = srvp->buffer;
-  int dprec = srvp->dprec;
-
-  switch ( dprec )
+  int newNamespaceID = -1;
+  NAMESPACE_INIT();
+  NAMESPACE_LOCK();
+  if (namespacesSize > nNamespaces)
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( sizeof(FLT32) == 4 )
-	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
-
-	    if ( dprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT32));
-	    else
-	      for ( i = 0; i < datasize; i++ )
-		((double *) data)[i] = (double) ((float *) buffer)[i];
-	  }
-	else
-	  {
-	    Error("not implemented for %d byte float", sizeof(FLT32));
-	  }
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-	if ( sizeof(FLT64) == 8 )
-	  {
-	    if ( byteswap ) swap8byte(buffer, datasize);
-
-	    if ( dprec == prec )
-	      memcpy(data, buffer, datasize*sizeof(FLT64));
-	    else
-	      for ( i = 0; i < datasize; i++ )
-		((float *) data)[i] = (float) ((double *) buffer)[i];
-	  }
-	else
-	  {
-	    Error("not implemented for %d byte float", sizeof(FLT64));
-	  }
-	break;
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
+      /* namespace is already available and only needs reinitialization */
+      for (unsigned i = 0; i < namespacesSize; ++i)
+        if (namespaces[i].resStage == NAMESPACE_STATUS_UNUSED)
+          {
+            newNamespaceID = (int)i;
+            break;
+          }
     }
-
-  return ierr;
+  else if (namespacesSize == 1)
+    {
+      /* make room for additional namespace */
+      struct Namespace *newNameSpaces
+        = (struct Namespace *) Malloc(((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
+      memcpy(newNameSpaces, namespaces, sizeof (namespaces[0]));
+      namespaces = newNameSpaces;
+      ++namespacesSize;
+      newNamespaceID = 1;
+    }
+  else if (namespacesSize < NUM_NAMESPACES)
+    {
+      /* make room for additional namespace */
+      newNamespaceID = (int)namespacesSize;
+      namespaces
+        = (struct Namespace *) Realloc(namespaces, ((size_t)namespacesSize + 1) * sizeof (namespaces[0]));
+      ++namespacesSize;
+    }
+  else /* implicit: namespacesSize >= NUM_NAMESPACES */
+    {
+      NAMESPACE_UNLOCK();
+      return -1;
+    }
+  xassert(newNamespaceID >= 0 && newNamespaceID < NUM_NAMESPACES);
+  ++nNamespaces;
+  namespaces[newNamespaceID].resStage = NAMESPACE_STATUS_INUSE;
+#if defined (SX) || defined (__cplusplus)
+  memcpy(namespaces[newNamespaceID].switches,
+         defaultSwitches_,
+         sizeof (namespaces[newNamespaceID].switches));
+#else
+    memcpy(namespaces[newNamespaceID].switches,
+           (union namespaceSwitchValue[NUM_NAMESPACE_SWITCH])defaultSwitches,
+           sizeof (namespaces[newNamespaceID].switches));
+#endif
+  reshListCreate(newNamespaceID);
+  NAMESPACE_UNLOCK();
+  return newNamespaceID;
 }
 
-
-int srvInqDataSP(void *srv, float *data)
+void
+namespaceDelete(int namespaceID)
 {
-  return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
+  NAMESPACE_INIT();
+  NAMESPACE_LOCK();
+  xassert(namespaceID >= 0 && (unsigned)namespaceID < namespacesSize
+          && nNamespaces);
+  reshListDestruct(namespaceID);
+  namespaces[namespaceID].resStage = NAMESPACE_STATUS_UNUSED;
+  --nNamespaces;
+  NAMESPACE_UNLOCK();
 }
 
-
-int srvInqDataDP(void *srv, double *data)
+int namespaceGetNumber ()
 {
-  return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
+  return (int)nNamespaces;
 }
 
 
-static int
-srvDefData(void *srv, int prec, const void *data)
+void namespaceSetActive ( int nId )
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-  size_t i;
-  int dprec, hprec;
-  void *buffer;
+  xassert((unsigned)nId < namespacesSize
+          && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
+  activeNamespace = nId;
+}
 
-  if ( srvDefaultDprec ) dprec = srvDefaultDprec;
-  else                   dprec = srvp->dprec;
 
-  if ( ! dprec ) dprec = prec;
+int namespaceGetActive ()
+{
+  return activeNamespace;
+}
 
-  srvp->dprec = dprec;
+int namespaceAdaptKey ( int originResH, int originNamespace )
+{
+  namespaceTuple_t tin;
+  int nsp;
 
-  if ( srvDefaultHprec ) hprec = srvDefaultHprec;
-  else                   hprec = srvp->hprec;
+  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
 
-  if ( ! hprec ) hprec = dprec;
+  tin.idx = originResH & idxmask;
+  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
 
-  srvp->hprec = hprec;
+  xassert ( tin.nsp == originNamespace );
 
-  int *header = srvp->header;
+  nsp = namespaceGetActive ();
 
-  size_t datasize = (size_t)(header[4] * header[5]);
-  size_t blocklen = datasize * (size_t)dprec;
+  return namespaceIdxEncode2 ( nsp, tin.idx );
+}
 
-  srvp->datasize = datasize;
 
-  size_t buffersize = srvp->buffersize;
+int namespaceAdaptKey2 ( int originResH )
+{
+  namespaceTuple_t tin;
+  int nsp;
 
-  if ( buffersize != blocklen )
-    {
-      buffersize = blocklen;
-      buffer = srvp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      srvp->buffer = buffer;
-      srvp->buffersize = buffersize;
-    }
-  else
-    buffer = srvp->buffer;
+  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
 
-  switch ( dprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( dprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT32));
-	else
-	  for ( i = 0; i < datasize; i++ )
-	    ((float *) buffer)[i] = (float) ((double *) data)[i];
+  tin.idx = originResH & idxmask;
+  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	if ( dprec == prec )
-	  memcpy(buffer, data, datasize*sizeof(FLT64));
-	else
-	  for ( i = 0; i < datasize; i++ )
-	    ((double *) buffer)[i] = (double) ((float *) data)[i];
+  nsp = namespaceGetActive ();
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
-    }
+  return namespaceIdxEncode2 ( nsp, tin.idx );
+}
 
-  return 0;
+void namespaceSwitchSet(enum namespaceSwitch sw, union namespaceSwitchValue value)
+{
+  xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
+  int nsp = namespaceGetActive();
+  namespaces[nsp].switches[sw] = value;
 }
 
+union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw)
+{
+  xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
+  int nsp = namespaceGetActive();
+  return namespaces[nsp].switches[sw];
+}
 
-int srvDefDataSP(void *srv, const float *data)
+void cdiReset(void)
 {
-  return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
+  NAMESPACE_INIT();
+  NAMESPACE_LOCK();
+  for (unsigned namespaceID = 0; namespaceID < namespacesSize; ++namespaceID)
+    if (namespaces[namespaceID].resStage != NAMESPACE_STATUS_UNUSED)
+      namespaceDelete((int)namespaceID);
+  if (namespaces != &initialNamespace)
+    {
+      Free(namespaces);
+      namespaces = &initialNamespace;
+      namespaces[0].resStage = NAMESPACE_STATUS_UNUSED;
+    }
+  namespacesSize = 1;
+  nNamespaces = 0;
+  NAMESPACE_UNLOCK();
 }
 
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+
 
-int srvDefDataDP(void *srv, const double *data)
+void cdiRefObject_construct(CdiReferencedObject* me)
 {
-  return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
+  me->destructor = cdiRefObject_destruct;
+  me->refCount = 1;
 }
 
-
-int srvRead(int fileID, void *srv)
+void cdiRefObject_retain(CdiReferencedObject* me)
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-  size_t i;
-  union {
-    INT32 i32[SRV_HEADER_LEN];
-    INT64 i64[SRV_HEADER_LEN];
-  } tempheader;
-  void *buffer;
-  int status;
+  size_t oldCount = me->refCount++;
+  xassert(oldCount && "A reference counted object was used after it was destructed.");
+}
 
-  if ( ! srvp->checked )
+void cdiRefObject_release(CdiReferencedObject* me)
+{
+  size_t oldCount = me->refCount--;
+  xassert(oldCount && "A reference counted object was released too often.");
+  if(oldCount == 1)
     {
-      status = srvCheckFiletype(fileID, &srvp->byteswap);
-      if ( status == 0 ) Error("Not a SERVICE file!");
-      srvp->checked = 1;
+      me->destructor(me);
+      Free(me);
     }
+}
 
-  int byteswap = srvp->byteswap;
+void cdiRefObject_destruct(CdiReferencedObject* me)
+{
+  (void)me;
+  /* Empty for now, but that's no reason not to call it! */
+}
 
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  if ( fileEOF(fileID) ) return -1;
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
+#endif
 
-  if ( SRV_Debug )
-    Message("blocklen = %lu", blocklen);
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
 
-  size_t hprec = blocklen / SRV_HEADER_LEN;
+#if defined (HAVE_EXECINFO_H)
+#include <execinfo.h>
+#endif
 
-  srvp->hprec = (int)hprec;
+static
+void show_stackframe()
+{
+#if defined HAVE_EXECINFO_H && defined backtrace_size_t && defined HAVE_BACKTRACE
+  void *trace[16];
+  backtrace_size_t trace_size = backtrace(trace, 16);
+  char **messages = backtrace_symbols(trace, trace_size);
 
-  switch ( hprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+  fprintf(stderr, "[bt] Execution path:\n");
+  if ( messages ) {
+    for ( backtrace_size_t i = 0; i < trace_size; ++i )
+      fprintf(stderr, "[bt] %s\n", messages[i]);
+    free(messages);
+  }
+#endif
+}
 
-	for ( i = 0; i < SRV_HEADER_LEN; i++ )
-          srvp->header[i] = (int)tempheader.i32[i];
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	binReadInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
+enum { MIN_LIST_SIZE = 128 };
 
-	for ( i = 0; i < SRV_HEADER_LEN; i++ )
-          srvp->header[i] = (int)tempheader.i64[i];
+static void listInitialize(void);
 
-	break;
-      }
-    default:
-      {
-	Error("Unexpected header precision %d", hprec);
-        break;
-      }
-    }
+typedef struct listElem {
+  union
+  {
+    /* free-list management data */
+    struct
+    {
+      int next, prev;
+    } free;
+    /* holding an actual value */
+    struct
+    {
+      const resOps *ops;
+      void         *val;//ptr
+    } v;
+  } res;
+  int           status;
+} listElem_t;
 
-  size_t blocklen2 = binReadF77Block(fileID, byteswap);
+struct resHList_t
+{
+  int size, freeHead, hasDefaultRes;
+  listElem_t *resources;
+};
 
-  if ( blocklen2 != blocklen )
-    {
-      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
-    }
+static struct resHList_t *resHList;
 
-  srvp->datasize = (size_t)(srvp->header[4] * srvp->header[5]);
+static int resHListSize = 0;
 
-  if ( SRV_Debug )
-    Message("datasize = %lu", srvp->datasize);
+#if  defined  (HAVE_LIBPTHREAD)
+#  include <pthread.h>
 
-  blocklen = binReadF77Block(fileID, byteswap);
+static pthread_once_t  listInitThread = PTHREAD_ONCE_INIT;
+static pthread_mutex_t listMutex;
 
-  size_t buffersize = srvp->buffersize;
+#  define LIST_LOCK()         pthread_mutex_lock(&listMutex)
+#  define LIST_UNLOCK()       pthread_mutex_unlock(&listMutex)
+#  define LIST_INIT(init0)         do {                         \
+    pthread_once(&listInitThread, listInitialize);              \
+    pthread_mutex_lock(&listMutex);                             \
+    if ((init0) && (!resHList || !resHList[0].resources))       \
+      reshListCreate(0);                                        \
+    pthread_mutex_unlock(&listMutex);                           \
+  } while (0)
 
-  if ( buffersize < blocklen )
-    {
-      buffersize = blocklen;
-      buffer = srvp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      srvp->buffer = buffer;
-      srvp->buffersize = buffersize;
-    }
-  else
-    buffer = srvp->buffer;
 
-  size_t datasize = srvp->datasize;
 
-  size_t dprec = blocklen / datasize;
+#else
 
-  srvp->dprec = (int)dprec;
+static int listInit = 0;
 
-  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
-    {
-      Warning("Unexpected data precision %d", dprec);
-      return -1;
-    }
+#  define LIST_LOCK()
+#  define LIST_UNLOCK()
+#  define LIST_INIT(init0)        do {                          \
+  if ( !listInit )                                              \
+    {                                                           \
+      listInitialize();                                         \
+      if ((init0) && (!resHList || !resHList[0].resources))     \
+        reshListCreate(0);                                      \
+      listInit = 1;                                             \
+    }                                                           \
+  } while(0)
 
-  fileRead(fileID, buffer, blocklen);
+#endif
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+/**************************************************************/
 
-  if ( blocklen2 != blocklen )
+static void
+listInitResources(int nsp)
+{
+  xassert(nsp < resHListSize && nsp >= 0);
+  int size = resHList[nsp].size = MIN_LIST_SIZE;
+  xassert(resHList[nsp].resources == NULL);
+  resHList[nsp].resources = (listElem_t*) Calloc(MIN_LIST_SIZE, sizeof(listElem_t));
+  listElem_t *p = resHList[nsp].resources;
+
+  for (int i = 0; i < size; i++ )
     {
-      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
+      p[i].res.free.next = i + 1;
+      p[i].res.free.prev = i - 1;
+      p[i].status = RESH_UNUSED;
     }
 
-  return 0;
+  p[size-1].res.free.next = -1;
+  resHList[nsp].freeHead = 0;
+  int oldNsp = namespaceGetActive();
+  namespaceSetActive(nsp);
+  instituteDefaultEntries();
+  modelDefaultEntries();
+  namespaceSetActive(oldNsp);
 }
 
+static inline void
+reshListClearEntry(int i)
+{
+  resHList[i].size = 0;
+  resHList[i].resources = NULL;
+  resHList[i].freeHead = -1;
+}
 
-void srvWrite(int fileID, void *srv)
+void
+reshListCreate(int namespaceID)
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
-  size_t i;
-  union
-  {
-    INT32 i32[SRV_HEADER_LEN];
-    INT64 i64[SRV_HEADER_LEN];
-  } tempheader;
-  int byteswap = srvp->byteswap;
-  int dprec  = srvp->dprec;
-  int hprec  = srvp->hprec;
-  int *restrict header = srvp->header;
+  LIST_INIT(namespaceID != 0);
+  LIST_LOCK();
+  if (resHListSize <= namespaceID)
+    {
+      resHList = (struct resHList_t *) Realloc(resHList, (size_t)(namespaceID + 1) * sizeof (resHList[0]));
+      for (int i = resHListSize; i <= namespaceID; ++i)
+        reshListClearEntry(i);
+      resHListSize = namespaceID + 1;
+    }
+  listInitResources(namespaceID);
+  LIST_UNLOCK();
+}
 
-  /* write header record */
-  size_t blocklen = SRV_HEADER_LEN * (size_t)hprec;
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+/**************************************************************/
 
-  switch ( hprec )
+void
+reshListDestruct(int namespaceID)
+{
+  LIST_LOCK();
+  xassert(resHList && namespaceID >= 0 && namespaceID < resHListSize);
+  int callerNamespaceID = namespaceGetActive();
+  namespaceSetActive(namespaceID);
+  if (resHList[namespaceID].resources)
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	for (i = 0; i < SRV_HEADER_LEN; i++)
-          tempheader.i32[i] = (INT32) header[i];
-
-	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
-
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	for (i = 0; i < SRV_HEADER_LEN; i++)
-          tempheader.i64[i] = (INT64) header[i];
+      for ( int j = 0; j < resHList[namespaceID].size; j++ )
+        {
+          listElem_t *listElem = resHList[namespaceID].resources + j;
+          if (listElem->status & RESH_IN_USE_BIT)
+            listElem->res.v.ops->valDestroy(listElem->res.v.val);
+        }
+      Free(resHList[namespaceID].resources);
+      resHList[namespaceID].resources = NULL;
+      reshListClearEntry(namespaceID);
+    }
+  if (resHList[callerNamespaceID].resources)
+    namespaceSetActive(callerNamespaceID);
+  LIST_UNLOCK();
+}
 
-	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected header precision %d", hprec);
-        break;
-      }
-    }
+static void listDestroy ( void )
+{
+  LIST_LOCK();
+  for (int i = resHListSize; i > 0; --i)
+    if (resHList[i-1].resources)
+      namespaceDelete(i-1);
+  resHListSize = 0;
+  Free(resHList);
+  resHList = NULL;
+  cdiReset();
+  LIST_UNLOCK();
+}
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+/**************************************************************/
 
-  size_t datasize = (size_t)(header[4] * header[5]);
-  blocklen = datasize * (size_t)dprec;
+static
+void listInitialize ( void )
+{
+#if  defined  (HAVE_LIBPTHREAD)
+  pthread_mutexattr_t ma;
+  pthread_mutexattr_init(&ma);
+  pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);
+  /* initialize global API mutex lock */
+  pthread_mutex_init ( &listMutex, &ma);
+  pthread_mutexattr_destroy(&ma);
+#endif
+  /* file is special and has its own table, which needs to be
+   * created, before we register the listDestroy exit handler */
+  {
+    int null_id;
+    null_id = fileOpen_serial("/dev/null", "r");
+    if (null_id != -1)
+      fileClose_serial(null_id);
+  }
+  atexit ( listDestroy );
+}
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+/**************************************************************/
 
-  srvp->datasize = datasize;
+static
+void listSizeExtend()
+{
+  int nsp = namespaceGetActive ();
+  int oldSize = resHList[nsp].size;
+  size_t newListSize = (size_t)oldSize + MIN_LIST_SIZE;
 
-  void *buffer = srvp->buffer;
+  resHList[nsp].resources = (listElem_t*) Realloc(resHList[nsp].resources,
+                                                   newListSize * sizeof(listElem_t));
 
-  switch ( dprec )
+  listElem_t *r = resHList[nsp].resources;
+  for (size_t i = (size_t)oldSize; i < newListSize; ++i)
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
+      r[i].res.free.next = (int)i + 1;
+      r[i].res.free.prev = (int)i - 1;
+      r[i].status = RESH_UNUSED;
     }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  if (resHList[nsp].freeHead != -1)
+    r[resHList[nsp].freeHead].res.free.prev = (int)newListSize - 1;
+  r[newListSize-1].res.free.next = resHList[nsp].freeHead;
+  r[oldSize].res.free.prev = -1;
+  resHList[nsp].freeHead = oldSize;
+  resHList[nsp].size = (int)newListSize;
 }
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _STREAM_SRV_H
-#define _STREAM_SRV_H
 
-#ifndef _SERVICE_H
-#endif
+/**************************************************************/
 
-int    srvInqContents(stream_t *streamptr);
-int    srvInqTimestep(stream_t *streamptr, int tsID);
+static void
+reshPut_(int nsp, int entry, void *p, const resOps *ops)
+{
+  listElem_t *newListElem = resHList[nsp].resources + entry;
+  int next = newListElem->res.free.next,
+    prev = newListElem->res.free.prev;
+  if (next != -1)
+    resHList[nsp].resources[next].res.free.prev = prev;
+  if (prev != -1)
+    resHList[nsp].resources[prev].res.free.next = next;
+  else
+    resHList[nsp].freeHead = next;
+  newListElem->res.v.val = p;
+  newListElem->res.v.ops = ops;
+  newListElem->status = RESH_DESYNC_IN_USE;
+}
 
-int    srvInqRecord(stream_t *streamptr, int *varID, int *levelID);
-void   srvDefRecord(stream_t *streamptr);
-void   srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   srvReadRecord(stream_t *streamptr, double *data, int *nmiss);
-void   srvWriteRecord(stream_t *streamptr, const double *data);
+int reshPut ( void *p, const resOps *ops )
+{
+  xassert ( p && ops );
 
-void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
-void   srvWriteVarDP(stream_t *streamptr, int varID, const double *data);
+  LIST_INIT(1);
 
-void   srvReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
-void   srvWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
+  LIST_LOCK();
 
-#endif  /* _STREAM_SRV_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _STREAM_EXT_H
-#define _STREAM_EXT_H
+  int nsp = namespaceGetActive ();
 
-#ifndef _EXTRA_H
-#endif
+  if ( resHList[nsp].freeHead == -1) listSizeExtend();
+  int entry = resHList[nsp].freeHead;
+  cdiResH resH = namespaceIdxEncode2(nsp, entry);
+  reshPut_(nsp, entry, p, ops);
 
-int    extInqContents(stream_t *streamptr);
-int    extInqTimestep(stream_t *streamptr, int tsID);
+  LIST_UNLOCK();
 
-int    extInqRecord(stream_t *streamptr, int *varID, int *levelID);
-void   extDefRecord(stream_t *streamptr);
-void   extCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   extReadRecord(stream_t *streamptr, double *data, int *nmiss);
-void   extWriteRecord(stream_t *streamptr, const double *data);
+  return resH;
+}
 
-void   extReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
-void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
+/**************************************************************/
 
-void   extReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
-void   extWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
+static void
+reshRemove_(int nsp, int idx)
+{
+  int curFree = resHList[nsp].freeHead;
+  listElem_t *r = resHList[nsp].resources;
+  r[idx].res.free.next = curFree;
+  r[idx].res.free.prev = -1;
+  if (curFree != -1)
+    r[curFree].res.free.prev = idx;
+  r[idx].status = RESH_DESYNC_DELETED;
+  resHList[nsp].freeHead = idx;
+}
 
-#endif  /* _STREAM_EXT_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _STREAM_IEG_H
-#define _STREAM_IEG_H
+void reshDestroy(cdiResH resH)
+{
+  int nsp;
+  namespaceTuple_t nspT;
 
-#ifndef _IEG_H
-#endif
+  LIST_LOCK();
 
-int    iegInqContents(stream_t *streamptr);
-int    iegInqTimestep(stream_t *streamptr, int tsID);
+  nsp = namespaceGetActive ();
 
-int    iegInqRecord(stream_t *streamptr, int *varID, int *levelID);
-void   iegDefRecord(stream_t *streamptr);
-void   iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   iegReadRecord(stream_t *streamptr, double *data, int *nmiss);
-void   iegWriteRecord(stream_t *streamptr, const double *data);
+  nspT = namespaceResHDecode ( resH );
 
-void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
-void   iegWriteVarDP(stream_t *streamptr, int varID, const double *data);
+  xassert ( nspT.nsp == nsp
+            && nspT.idx >= 0
+            && nspT.idx < resHList[nsp].size
+            && resHList[nsp].resources[nspT.idx].res.v.ops);
 
-void   iegReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
-void   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
+  if (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
+    reshRemove_(nsp, nspT.idx);
 
-#endif  /* _STREAM_IEG_H */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  LIST_UNLOCK();
+}
 
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
-#endif
+void reshRemove ( cdiResH resH, const resOps * ops )
+{
+  int nsp;
+  namespaceTuple_t nspT;
 
-#include <ctype.h>
+  LIST_LOCK();
 
+  nsp = namespaceGetActive ();
 
+  nspT = namespaceResHDecode ( resH );
 
-static stream_t *stream_new_entry(int resH);
-static void stream_delete_entry(stream_t *streamptr);
-static int streamCompareP(void * streamptr1, void * streamptr2);
-static void streamDestroyP(void * streamptr);
-static void streamPrintP(void * streamptr, FILE * fp);
-static int streamGetPackSize(void * streamptr, void *context);
-static void streamPack(void * streamptr, void * buff, int size, int * position, void *context);
-static int streamTxCode(void);
+  xassert ( nspT.nsp == nsp
+            && nspT.idx >= 0
+            && nspT.idx < resHList[nsp].size
+            && (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
+            && resHList[nsp].resources[nspT.idx].res.v.ops
+            && resHList[nsp].resources[nspT.idx].res.v.ops == ops );
 
-const resOps streamOps = {
-  streamCompareP,
-  streamDestroyP,
-  streamPrintP,
-  streamGetPackSize,
-  streamPack,
-  streamTxCode
-};
+  reshRemove_(nsp, nspT.idx);
 
+  LIST_UNLOCK();
+}
 
+/**************************************************************/
 
-static
-int getByteorder(int byteswap)
+void reshReplace(cdiResH resH, void *p, const resOps *ops)
 {
-  int byteorder = -1;
-
-  switch (HOST_ENDIANNESS)
+  xassert(p && ops);
+  LIST_INIT(1);
+  LIST_LOCK();
+  int nsp = namespaceGetActive();
+  namespaceTuple_t nspT = namespaceResHDecode(resH);
+  while (resHList[nsp].size <= nspT.idx)
+    listSizeExtend();
+  listElem_t *q = resHList[nsp].resources + nspT.idx;
+  if (q->status & RESH_IN_USE_BIT)
     {
-    case CDI_BIGENDIAN:
-      byteorder = byteswap ? CDI_LITTLEENDIAN : CDI_BIGENDIAN;
-      break;
-    case CDI_LITTLEENDIAN:
-      byteorder = byteswap ? CDI_BIGENDIAN : CDI_LITTLEENDIAN;
-      break;
-    /* FIXME: does not currently adjust for PDP endianness */
-    case CDI_PDPENDIAN:
-    default:
-      Error("unhandled endianness");
+      q->res.v.ops->valDestroy(q->res.v.val);
+      reshRemove_(nsp, nspT.idx);
     }
-  return byteorder;
+  reshPut_(nsp, nspT.idx, p, ops);
+  LIST_UNLOCK();
 }
 
-// used also in CDO
-int cdiGetFiletype(const char *filename, int *byteorder)
+
+static listElem_t *
+reshGetElem(const char *caller, const char* expressionString, cdiResH resH, const resOps *ops)
 {
-  int filetype = CDI_EUFTYPE;
-  int swap = 0;
-  int version;
-  long recpos;
-  char buffer[8];
+  listElem_t *listElem;
+  xassert ( ops );
 
-  int fileID = fileOpen(filename, "r");
+  LIST_INIT(1);
 
-  if ( fileID == CDI_UNDEFID )
-    {
-      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
-	return FILETYPE_NC;
-      else
-	return CDI_ESYSTEM;
-    }
+  LIST_LOCK();
 
-  if ( fileRead(fileID, buffer, 8) != 8 ) return CDI_EUFTYPE;
+  int nsp = namespaceGetActive ();
 
-  fileRewind(fileID);
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
+  assert(nspT.idx >= 0);
 
-  if ( memcmp(buffer, "GRIB", 4) == 0 )
-    {
-      version = buffer[7];
-      if ( version <= 1 )
-	{
-	  filetype = FILETYPE_GRB;
-	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
-	}
-      else if ( version == 2 )
-	{
-	  filetype = FILETYPE_GRB2;
-	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
-	}
-    }
-  else if ( memcmp(buffer, "CDF\001", 4) == 0 )
-    {
-      filetype = FILETYPE_NC;
-      if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
-    }
-  else if ( memcmp(buffer, "CDF\002", 4) == 0 )
-    {
-      filetype = FILETYPE_NC2;
-      if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
-    }
-  else if ( memcmp(buffer+1, "HDF", 3) == 0 )
-    {
-      filetype = FILETYPE_NC4;
-      if ( CDI_Debug ) Message("found HDF file = %s", filename);
-    }
-#if  defined  (HAVE_LIBSERVICE)
-  else if ( srvCheckFiletype(fileID, &swap) )
-    {
-      filetype = FILETYPE_SRV;
-      if ( CDI_Debug ) Message("found SRV file = %s", filename);
-    }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-  else if ( extCheckFiletype(fileID, &swap) )
+  if (nspT.nsp == nsp &&
+      nspT.idx < resHList[nsp].size)
     {
-      filetype = FILETYPE_EXT;
-      if ( CDI_Debug ) Message("found EXT file = %s", filename);
+      listElem = resHList[nsp].resources + nspT.idx;
+      LIST_UNLOCK();
     }
-#endif
-#if  defined  (HAVE_LIBIEG)
-  else if ( iegCheckFiletype(fileID, &swap) )
+  else
     {
-      filetype = FILETYPE_IEG;
-      if ( CDI_Debug ) Message("found IEG file = %s", filename);
+      LIST_UNLOCK();
+      show_stackframe();
+
+      if ( resH == CDI_UNDEFID )
+        {
+          xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is CDI_UNDEFID (= %d).\n\tThis is most likely the result of a failed earlier call. Please check the IDs returned by CDI.", expressionString, caller, resH);
+        }
+      else
+        {
+          xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: the value is garbage (= %d, which resolves to namespace = %d, index = %d).\n\tThis is either the result of using an uninitialized variable,\n\tof using a value as an ID that is not an ID,\n\tor of using an ID after it has been invalidated.", expressionString, caller, resH, nspT.nsp, nspT.idx);
+        }
     }
-#endif
-#if  defined  (HAVE_LIBCGRIBEX)
-  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
+
+  if ( !(listElem && listElem->res.v.ops == ops) )
     {
-      if ( version <= 1 )
-	{
-	  filetype = FILETYPE_GRB;
-	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
-	}
-      else if ( version == 2 )
-	{
-	  filetype = FILETYPE_GRB2;
-	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
-	}
-    }
-#endif
+      show_stackframe();
 
-  fileClose(fileID);
+      xabortC(caller, "Error while trying to resolve the ID \"%s\" in `%s()`: list element not found. The failed ID is %d", expressionString, caller, (int)resH);
+    }
 
-  *byteorder = getByteorder(swap);
+  return listElem;
+}
 
-  return filetype;
+void *reshGetValue(const char * caller, const char* expressionString, cdiResH resH, const resOps * ops)
+{
+  return reshGetElem(caller, expressionString, resH, ops)->res.v.val;
 }
 
-/*
- at Function  streamInqFiletype
- at Title     Get the filetype
+/**************************************************************/
 
- at Prototype int streamInqFiletype(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+void reshGetResHListOfType(unsigned numIDs, int resHs[], const resOps *ops)
+{
+  xassert ( resHs && ops );
 
- at Description
-The function @func{streamInqFiletype} returns the filetype of a stream.
+  LIST_INIT(1);
 
- at Result
- at func{streamInqFiletype} returns the type of the file format,
-one of the set of predefined CDI file format types.
-The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC}, @func{FILETYPE_NC2},
- at func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV}, @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
+  LIST_LOCK();
 
- at EndFunction
-*/
-int streamInqFiletype(int streamID)
+  int nsp = namespaceGetActive();
+  unsigned j = 0;
+  for (int i = 0; i < resHList[nsp].size && j < numIDs; i++ )
+    if ((resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
+        && resHList[nsp].resources[i].res.v.ops == ops)
+      resHs[j++] = namespaceIdxEncode2(nsp, i);
+
+  LIST_UNLOCK();
+}
+
+enum cdiApplyRet
+cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
+                                      void *data), void *data)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->filetype;
+  xassert(func);
+
+  LIST_INIT(1);
+
+  LIST_LOCK();
+
+  int nsp = namespaceGetActive ();
+  enum cdiApplyRet ret = CDI_APPLY_GO_ON;
+  for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
+    if (resHList[nsp].resources[i].status & RESH_IN_USE_BIT)
+      ret = func(namespaceIdxEncode2(nsp, i),
+                 resHList[nsp].resources[i].res.v.val,
+                 resHList[nsp].resources[i].res.v.ops, data);
+  LIST_UNLOCK();
+  return ret;
 }
 
 
-int getByteswap(int byteorder)
+enum cdiApplyRet
+cdiResHFilterApply(const resOps *p,
+                   enum cdiApplyRet (*func)(int id, void *res, void *data),
+                   void *data)
 {
-  int byteswap = -1;
+  xassert(p && func);
 
-  switch (byteorder)
-    {
-    case CDI_BIGENDIAN:
-    case CDI_LITTLEENDIAN:
-    case CDI_PDPENDIAN:
-      byteswap = (HOST_ENDIANNESS != byteorder);
-      break;
-    case -1:
-      break;
-    default:
-      Error("unexpected byteorder %d query!", byteorder);
-    }
+  LIST_INIT(1);
 
-  return byteswap;
+  LIST_LOCK();
+
+  int nsp = namespaceGetActive ();
+  enum cdiApplyRet ret = CDI_APPLY_GO_ON;
+  listElem_t *r = resHList[nsp].resources;
+  for (int i = 0; i < resHList[nsp].size && ret > 0; ++i)
+    if ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == p)
+      ret = func(namespaceIdxEncode2(nsp, i), r[i].res.v.val,
+                 data);
+  LIST_UNLOCK();
+  return ret;
 }
 
-/*
- at Function  streamDefByteorder
- at Title     Define the byte order
 
- at Prototype void streamDefByteorder(int streamID, int byteorder)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  byteorder The byte order of a dataset, one of the CDI constants @func{CDI_BIGENDIAN} and
-                     @func{CDI_LITTLEENDIAN}.
 
- at Description
-The function @func{streamDefByteorder} defines the byte order of a binary dataset
-with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILETYPE_IEG}.
 
- at EndFunction
-*/
-void streamDefByteorder(int streamID, int byteorder)
+/**************************************************************/
+
+unsigned reshCountType(const resOps *ops)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  streamptr->byteorder = byteorder;
-  int filetype = streamptr->filetype;
+  unsigned countType = 0;
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
-	srvp->byteswap = getByteswap(byteorder);
+  xassert(ops);
 
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
-	extp->byteswap = getByteswap(byteorder);
+  LIST_INIT(1);
 
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
-	iegp->byteswap = getByteswap(byteorder);
+  LIST_LOCK();
 
-	break;
-      }
-#endif
-    }
-  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-}
+  int nsp = namespaceGetActive ();
 
-/*
- at Function  streamInqByteorder
- at Title     Get the byte order
+  listElem_t *r = resHList[nsp].resources;
+  size_t len = (size_t)resHList[nsp].size;
+  for (size_t i = 0; i < len; i++ )
+    countType += ((r[i].status & RESH_IN_USE_BIT) && r[i].res.v.ops == ops);
 
- at Prototype int streamInqByteorder(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+  LIST_UNLOCK();
 
- at Description
-The function @func{streamInqByteorder} returns the byte order of a binary dataset
-with the file format type @func{FILETYPE_SRV}, @func{FILETYPE_EXT} or @func{FILETYPE_IEG}.
+  return countType;
+}
 
- at Result
- at func{streamInqByteorder} returns the type of the byte order.
-The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDIAN}
+/**************************************************************/
 
- at EndFunction
-*/
-int streamInqByteorder(int streamID)
+int
+reshResourceGetPackSize_intern(int resH, const resOps *ops, void *context, const char* caller, const char* expressionString)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->byteorder;
+  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
+  return curr->res.v.ops->valGetPackSize(curr->res.v.val, context);
 }
 
-
-const char *streamFilesuffix(int filetype)
+void
+reshPackResource_intern(int resH, const resOps *ops, void *buf, int buf_size, int *position, void *context,
+                        const char* caller, const char* expressionString)
 {
-  // static char *fileSuffix[] = {"", ".grb", ".g2", ".nc", ".nc", ".nc4", ".nc4", ".srv", ".ext", ".ieg"};
-  /* note: the 2nd dimenstion of the fileSuffix array must be equal to or
-   * larger than the length of the longest suffix (dot and \0 terminator
-   * included) */
-  static const char fileSuffix[][5] = {"", ".grb", ".grb", ".nc", ".nc", ".nc", ".nc", ".srv", ".ext", ".ieg"};
-  int size = (int)(sizeof(fileSuffix)/sizeof(fileSuffix[0]));
-
-  if ( filetype > 0 && filetype < size )
-    return fileSuffix[filetype];
-  else
-    return fileSuffix[0];
+  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
+  curr->res.v.ops->valPack(curr->res.v.val, buf, buf_size, position, context);
 }
 
+enum {
+  resHPackHeaderNInt = 2,
+  resHDeleteNInt = 2,
+};
 
-const char *streamFilename(int streamID)
+static int getPackBufferSize(void *context)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->filename;
-}
+  int intpacksize, packBufferSize = 0;
 
-static
-long cdiInqTimeSize(int streamID)
-{
-  int tsID = 0, nrecs;
-  stream_t *streamptr = stream_to_pointer(streamID);
-  long ntsteps = streamptr->ntsteps;
+  int nsp = namespaceGetActive ();
 
-  if ( ntsteps == (long)CDI_UNDEFID )
-    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
-      ntsteps = streamptr->ntsteps;
+  /* pack start marker, namespace and sererator marker */
+  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, CDI_DATATYPE_INT, context));
 
-  return ntsteps;
+  /* pack resources, type marker and seperator marker */
+  listElem_t *r = resHList[nsp].resources;
+  for ( int i = 0; i < resHList[nsp].size; i++)
+    if (r[i].status & RESH_SYNC_BIT)
+      {
+        if (r[i].status == RESH_DESYNC_DELETED)
+          {
+            packBufferSize += resHDeleteNInt * intpacksize;
+          }
+        else if (r[i].status == RESH_DESYNC_IN_USE)
+          {
+            xassert ( r[i].res.v.ops );
+            /* packed resource plus 1 int for type */
+            packBufferSize +=
+              r[i].res.v.ops->valGetPackSize(r[i].res.v.val, context)
+              + intpacksize;
+          }
+      }
+  /* end marker */
+  packBufferSize += intpacksize;
+
+  return packBufferSize;
 }
 
-static
-int cdiInqContents(stream_t * streamptr)
+/**************************************************************/
+
+void reshPackBufferDestroy ( char ** buffer )
 {
-  int status = 0;
+  if ( buffer ) free ( *buffer );
+}
 
-  int filetype = streamptr->filetype;
+/**************************************************************/
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        status = grbInqContents(streamptr);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        status = srvInqContents(streamptr);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        status = extInqContents(streamptr);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        status = iegInqContents(streamptr);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        status = cdfInqContents(streamptr);
-	break;
-      }
-#endif
-    default:
-      {
-	if ( CDI_Debug )
-	  Message("%s support not compiled in!", strfiletype(filetype));
+int reshGetTxCode(cdiResH resH)
+{
+  int type = 0;
 
-	status = CDI_ELIBNAVAIL;
-        break;
-      }
-    }
+  LIST_LOCK();
 
-  if ( status == 0 )
+  int nsp = namespaceGetActive ();
+
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
+  assert(nspT.idx >= 0);
+
+  if (nspT.nsp == nsp &&
+      nspT.idx < resHList[nsp].size)
     {
-      int vlistID = streamptr->vlistID;
-      int taxisID = vlistInqTaxis(vlistID);
-      if ( taxisID != CDI_UNDEFID )
-        {
-          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
-          taxis_t *taxisptr2 = taxisPtr(taxisID);
-          ptaxisCopy(taxisptr2, taxisptr1);
-        }
+      listElem_t *listElem = resHList[nsp].resources + nspT.idx;
+      xassert ( listElem->res.v.ops );
+      type = listElem->res.v.ops->valTxCode();
     }
 
-  return status;
+  LIST_UNLOCK();
+
+  return type;
 }
 
-int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
-                                 int filetype, stream_t *streamptr,
-                                 int recordBufIsToBeCreated)
+/**************************************************************/
+
+int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
 {
-  int fileID;
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+  int packBufferPos = 0;
+  int end = END;
+
+  xassert ( packBuffer );
+
+  LIST_LOCK();
+
+  int nsp = namespaceGetActive ();
+
+  int pBSize = *packBufferSize = getPackBufferSize(context);
+  char *pB = *packBuffer = (char *) Malloc((size_t)pBSize);
+
+  {
+    int header[resHPackHeaderNInt] = { START, nsp };
+    serializePack(header, resHPackHeaderNInt,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
+  }
+
+  listElem_t *r = resHList[nsp].resources;
+  for ( int i = 0; i < resHList[nsp].size; i++ )
+    if (r[i].status & RESH_SYNC_BIT)
       {
-#ifndef __cplusplus
-        fileID = gribOpen(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = gribOpen(filename, temp);
-#endif
-        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
-        if (recordBufIsToBeCreated)
+        if (r[i].status == RESH_DESYNC_DELETED)
           {
-            streamptr->record = (Record *) Malloc(sizeof(Record));
-            streamptr->record->buffer = NULL;
+            int temp[resHDeleteNInt]
+              = { RESH_DELETE, namespaceIdxEncode2(nsp, i) };
+            serializePack(temp, resHDeleteNInt, CDI_DATATYPE_INT,
+                          pB, pBSize, &packBufferPos, context);
           }
-        break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-#ifndef __cplusplus
-        fileID = fileOpen(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = fileOpen(filename, temp);
-#endif
-        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
-        if (recordBufIsToBeCreated)
+        else
           {
-            streamptr->record = (Record *) Malloc(sizeof(Record));
-            streamptr->record->buffer = NULL;
-            streamptr->record->exsep  = srvNew();
+            listElem_t * curr = r + i;
+            xassert ( curr->res.v.ops );
+            int type = curr->res.v.ops->valTxCode();
+            if ( ! type ) continue;
+            serializePack(&type, 1, CDI_DATATYPE_INT, pB,
+                          pBSize, &packBufferPos, context);
+            curr->res.v.ops->valPack(curr->res.v.val,
+                                     pB, pBSize, &packBufferPos, context);
           }
-        break;
+        r[i].status &= ~RESH_SYNC_BIT;
       }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-#ifndef __cplusplus
-        fileID = fileOpen(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = fileOpen(filename, temp);
-#endif
 
-        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
-        if (recordBufIsToBeCreated)
-          {
-            streamptr->record = (Record *) Malloc(sizeof(Record));
-            streamptr->record->buffer = NULL;
-            streamptr->record->exsep  = extNew();
-          }
-        break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-#ifndef __cplusplus
-        fileID = fileOpen(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = fileOpen(filename, temp);
-#endif
-        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
-        if (recordBufIsToBeCreated)
-          {
-            streamptr->record = (Record *) Malloc(sizeof(Record));
-            streamptr->record->buffer = NULL;
-            streamptr->record->exsep   = iegNew();
-          }
-        break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-      {
-#ifndef __cplusplus
-        fileID = cdfOpen(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = cdfOpen(filename, temp);
-#endif
-        break;
-      }
-    case FILETYPE_NC2:
-      {
-#ifndef __cplusplus
-        fileID = cdfOpen64(filename, (char [2]){filemode, 0});
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = cdfOpen64(filename, temp);
-#endif
-        break;
-      }
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-#ifndef __cplusplus
-        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
-#else
-        char temp[2] = { filemode, 0 };
-        fileID = cdf4Open(filename, temp, &filetype);
-#endif
-        break;
-      }
-#endif
-    default:
-      {
-        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
-        return CDI_ELIBNAVAIL;
-      }
-    }
+  LIST_UNLOCK();
 
-  streamptr->filetype = filetype;
+  serializePack(&end, 1,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
 
-  return fileID;
+  return packBufferPos;
+}
+
+/**************************************************************/
+
+/* for thread safety this feature would have to be integrated in reshPut */
+
+void reshSetStatus ( cdiResH resH, const resOps * ops, int status )
+{
+  int nsp;
+  namespaceTuple_t nspT;
+  listElem_t * listElem;
+
+  xassert((ops != NULL) ^ !(status & RESH_IN_USE_BIT));
+
+  LIST_INIT(1);
+
+  LIST_LOCK();
+
+  nsp = namespaceGetActive ();
+
+  nspT = namespaceResHDecode ( resH );
+
+  xassert ( nspT.nsp == nsp &&
+            nspT.idx >= 0 &&
+            nspT.idx < resHList[nsp].size );
+
+  xassert ( resHList[nsp].resources );
+  listElem = resHList[nsp].resources + nspT.idx;
+
+  xassert((!ops || (listElem->res.v.ops == ops))
+          && (listElem->status & RESH_IN_USE_BIT) == (status & RESH_IN_USE_BIT));
+
+  listElem->status = status;
+
+  LIST_UNLOCK();
 }
 
+/**************************************************************/
 
-int streamOpenID(const char *filename, char filemode, int filetype, int resH)
+int reshGetStatus ( cdiResH resH, const resOps * ops )
 {
-  if ( CDI_Debug )
-    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
-            filename?filename:"(NUL)");
+  int nsp;
+  namespaceTuple_t nspT;
 
-  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
+  LIST_INIT(1);
 
-  stream_t *streamptr = stream_new_entry(resH);
-  int streamID = CDI_ESYSTEM;
+  LIST_LOCK();
 
-  int (*streamOpenDelegate)(const char *filename, char filemode,
-                            int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
-    = (int (*)(const char *, char, int, stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
+  nsp = namespaceGetActive ();
 
-  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
-  if ( fileID < 0 )
-    {
-      streamID = fileID;
-    }
-  else
-    {
-      streamID = streamptr->self;
-      if ( streamID < 0 ) return CDI_ELIMIT;
+  nspT = namespaceResHDecode ( resH );
 
-      streamptr->filemode = filemode;
-      streamptr->filename = strdupx(filename);
-      streamptr->fileID   = fileID;
+  xassert ( nspT.nsp == nsp &&
+            nspT.idx >= 0 &&
+            nspT.idx < resHList[nsp].size );
 
-      if ( filemode == 'r' )
-        {
-          int vlistID = vlistCreate();
-          if ( vlistID < 0 ) return CDI_ELIMIT;
+  listElem_t *listElem = resHList[nsp].resources + nspT.idx;
 
-          cdiVlistMakeInternal(vlistID);
-          streamptr->vlistID = vlistID;
-          /* cdiReadByteorder(streamID); */
-          int status = cdiInqContents(streamptr);
-          if ( status < 0 )
-            {
-              streamID = status;
-            }
-          else
-            {
-              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
-              vlistptr->ntsteps = streamptr->ntsteps;
-              cdiVlistMakeImmutable(vlistID);
-            }
-        }
-    }
+  const resOps *elemOps = listElem->res.v.ops;
 
-  if ( streamID < 0 )
-    {
-      Free(streamptr->record);
-      stream_delete_entry(streamptr);
-    }
+  LIST_UNLOCK();
 
-  return streamID;
+  xassert(listElem && (!(listElem->status & RESH_IN_USE_BIT) || elemOps == ops));
+
+  return listElem->status;
 }
 
-static int streamOpen(const char *filename, const char *filemode, int filetype)
+/**************************************************************/
+
+void reshLock ()
 {
-  if (!filemode || strlen(filemode) != 1) return CDI_EINVAL;
-  return streamOpenID(filename, (char)tolower(filemode[0]),
-                      filetype, CDI_UNDEFID);
+  LIST_LOCK();
 }
 
-static int streamOpenA(const char *filename, const char *filemode, int filetype)
+/**************************************************************/
+
+void reshUnlock ()
 {
-  int fileID = CDI_UNDEFID;
-  int streamID = CDI_ESYSTEM;
-  int status;
-  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
-  vlist_t *vlistptr;
+  LIST_UNLOCK();
+}
 
-  if ( CDI_Debug )
-    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
-  if ( CDI_Debug ) printf("streamOpenA: %s\n", filename); // seg fault without this line on thunder/squall with "cdo cat x y"
+/**************************************************************/
 
-  if ( ! filename || ! filemode || filetype < 0 ) return CDI_EINVAL;
+int reshListCompare ( int nsp0, int nsp1 )
+{
+  LIST_INIT(1);
+  LIST_LOCK();
 
-  {
-    int (*streamOpenDelegate)(const char *filename, char filemode,
-                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
-      = (int (*)(const char *, char, int, stream_t *, int))
-      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
+  xassert(resHListSize > nsp0 && resHListSize > nsp1 &&
+          nsp0 >= 0 && nsp1 >= 0);
 
-    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
-  }
+  int valCompare = 0;
+  int i, listSizeMin = (resHList[nsp0].size <= resHList[nsp1].size)
+    ? resHList[nsp0].size : resHList[nsp1].size;
+  listElem_t *resources0 = resHList[nsp0].resources,
+    *resources1 = resHList[nsp1].resources;
+  for (i = 0; i < listSizeMin; i++)
+    {
+      int occupied0 = (resources0[i].status & RESH_IN_USE_BIT) != 0,
+        occupied1 = (resources1[i].status & RESH_IN_USE_BIT) != 0;
+      /* occupation mismatch ? */
+      int diff = occupied0 ^ occupied1;
+      valCompare |= (diff << cdiResHListOccupationMismatch);
+      if (!diff && occupied0)
+        {
+          /* both occupied, do resource types match? */
+          diff = (resources0[i].res.v.ops != resources1[i].res.v.ops
+                  || resources0[i].res.v.ops == NULL);
+          valCompare |= (diff << cdiResHListResourceTypeMismatch);
+          if (!diff)
+            {
+              /* types match, does content match also? */
+              diff
+                = resources0[i].res.v.ops->valCompare(resources0[i].res.v.val,
+                                                      resources1[i].res.v.val);
+              valCompare |= (diff << cdiResHListResourceContentMismatch);
+            }
+        }
+    }
+  /* find resources in nsp 0 beyond end of nsp 1 */
+  for (int j = listSizeMin; j < resHList[nsp0].size; ++j)
+    valCompare |= (((resources0[j].status & RESH_IN_USE_BIT) != 0)
+                   << cdiResHListOccupationMismatch);
+  /* find resources in nsp 1 beyond end of nsp 0 */
+  for (; i < resHList[nsp1].size; ++i)
+    valCompare |= (((resources1[i].status & RESH_IN_USE_BIT) != 0)
+                   << cdiResHListOccupationMismatch);
 
-  if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
+  LIST_UNLOCK();
 
-  streamID = streamptr->self;
+  return valCompare;
+}
 
-  streamptr->filemode = tolower(*filemode);
-  streamptr->filename = strdupx(filename);
-  streamptr->fileID   = fileID;
+/**************************************************************/
 
-  streamptr->vlistID = vlistCreate();
-  cdiVlistMakeInternal(streamptr->vlistID);
-  /* cdiReadByteorder(streamID); */
-  status = cdiInqContents(streamptr);
-  if ( status < 0 ) return status;
-  vlistptr = vlist_to_pointer(streamptr->vlistID);
-  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
-  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
+void reshListPrint(FILE *fp)
+{
+  int i, j, temp;
+  listElem_t * curr;
 
-  {
-    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
-      = (void (*)(stream_t *, int))
-      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
+  LIST_INIT(1);
 
-    streamCloseDelegate(streamptr, 0);
-  }
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        fileID = gribOpen(filename, filemode);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        fileID = fileOpen(filename, filemode);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        fileID = fileOpen(filename, filemode);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        fileID = fileOpen(filename, filemode);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-      {
-	fileID = cdfOpen(filename, filemode);
-	streamptr->ncmode = 2;
-	break;
-      }
-    case FILETYPE_NC2:
-      {
-	fileID = cdfOpen64(filename, filemode);
-	streamptr->ncmode = 2;
-	break;
-      }
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	fileID = cdf4Open(filename, filemode, &filetype);
-	streamptr->ncmode = 2;
-	break;
-      }
-#endif
-    default:
-      {
-	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
-	return CDI_ELIBNAVAIL;
-      }
-    }
+  temp = namespaceGetActive ();
 
-  if ( fileID == CDI_UNDEFID )
-    streamID = CDI_UNDEFID;
-  else
-    streamptr->fileID = fileID;
+  fprintf ( fp, "\n\n##########################################\n#\n#  print " \
+            "global resource list \n#\n" );
 
-  return streamID;
-}
+  for ( i = 0; i < namespaceGetNumber (); i++ )
+    {
+      namespaceSetActive ( i );
 
-/*
- at Function  streamOpenRead
- at Title     Open a dataset for reading
+      fprintf ( fp, "\n" );
+      fprintf ( fp, "##################################\n" );
+      fprintf ( fp, "#\n" );
+      fprintf ( fp, "# namespace=%d\n", i );
+      fprintf ( fp, "#\n" );
+      fprintf ( fp, "##################################\n\n" );
 
- at Prototype int streamOpenRead(const char *path)
- at Parameter
-    @Item  path  The name of the dataset to be read.
+      fprintf ( fp, "resHList[%d].size=%d\n", i, resHList[i].size );
 
- at Description
-The function @func{streamOpenRead} opens an existing dataset for reading.
+      for ( j = 0; j < resHList[i].size; j++ )
+        {
+          curr = resHList[i].resources + j;
+          if (!(curr->status & RESH_IN_USE_BIT))
+            {
+              curr->res.v.ops->valPrint(curr->res.v.val, fp);
+              fprintf ( fp, "\n" );
+            }
+        }
+    }
+  fprintf ( fp, "#\n#  end global resource list" \
+            "\n#\n##########################################\n\n" );
 
- at Result
-Upon successful completion @func{streamOpenRead} returns an identifier to the
-open stream. Otherwise, a negative number with the error status is returned.
+  namespaceSetActive ( temp );
+}
 
- at Errors
- at List
-   @Item  CDI_ESYSTEM     Operating system error.
-   @Item  CDI_EINVAL      Invalid argument.
-   @Item  CDI_EUFILETYPE  Unsupported file type.
-   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
- at EndList
 
- at Example
-Here is an example using @func{streamOpenRead} to open an existing NetCDF
-file named @func{foo.nc} for reading:
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
 
- at Source
-   ...
-int streamID;
-   ...
-streamID = streamOpenRead("foo.nc");
-if ( streamID < 0 ) handle_error(streamID);
-   ...
- at EndSource
- at EndFunction
-*/
-int streamOpenRead(const char *filename)
+
+int
+serializeGetSize(int count, int datatype, void *context)
 {
-  cdiInitialize();
+  int (*serialize_get_size_p)(int count, int datatype, void *context)
+    = (int (*)(int, int, void *))
+    namespaceSwitchGet(NSSWITCH_SERIALIZE_GET_SIZE).func;
+  return serialize_get_size_p(count, datatype, context);
+}
 
-  int byteorder = 0;
-  int filetype = cdiGetFiletype(filename, &byteorder);
+void serializePack(const void *data, int count, int datatype,
+                   void *buf, int buf_size, int *position, void *context)
+{
+  void (*serialize_pack_p)(const void *data, int count, int datatype,
+                           void *buf, int buf_size, int *position, void *context)
+    = (void (*)(const void *, int, int, void *, int, int *, void *))
+    namespaceSwitchGet(NSSWITCH_SERIALIZE_PACK).func;
+  serialize_pack_p(data, count, datatype, buf, buf_size, position, context);
+}
 
-  if ( filetype < 0 ) return filetype;
+void serializeUnpack(const void *buf, int buf_size, int *position,
+                     void *data, int count, int datatype, void *context)
+{
+  void (*serialize_unpack_p)(const void *buf, int buf_size, int *position,
+                             void *data, int count, int datatype, void *context)
+    = (void (*)(const void *, int, int *, void *, int, int, void *))
+    namespaceSwitchGet(NSSWITCH_SERIALIZE_UNPACK).func;
+  serialize_unpack_p(buf, buf_size, position, data, count, datatype, context);
+}
 
-  int streamID = streamOpen(filename, "r", filetype);
 
-  if ( streamID >= 0 )
-    {
-      stream_t *streamptr = stream_to_pointer(streamID);
-      streamptr->byteorder = byteorder;
-    }
 
-  return streamID;
+int
+serializeGetSizeInCore(int count, int datatype, void *context)
+{
+  int elemSize;
+  (void)context;
+  switch (datatype)
+  {
+  case CDI_DATATYPE_INT8:
+    elemSize = sizeof (int8_t);
+    break;
+  case CDI_DATATYPE_INT16:
+    elemSize = sizeof (int16_t);
+    break;
+  case CDI_DATATYPE_UINT32:
+    elemSize = sizeof (uint32_t);
+    break;
+  case CDI_DATATYPE_INT:
+    elemSize = sizeof (int);
+    break;
+  case CDI_DATATYPE_FLT:
+  case CDI_DATATYPE_FLT64:
+    elemSize = sizeof (double);
+    break;
+  case CDI_DATATYPE_TXT:
+  case CDI_DATATYPE_UCHAR:
+    elemSize = 1;
+    break;
+  case CDI_DATATYPE_LONG:
+    elemSize = sizeof (long);
+    break;
+  default:
+    xabort("Unexpected datatype");
+  }
+  return count * elemSize;
 }
 
+void serializePackInCore(const void *data, int count, int datatype,
+                         void *buf, int buf_size, int *position, void *context)
+{
+  int size = serializeGetSize(count, datatype, context);
+  int pos = *position;
+  xassert(INT_MAX - pos >= size && buf_size - pos >= size);
+  memcpy((unsigned char *)buf + pos, data, (size_t)size);
+  pos += size;
+  *position = pos;
+}
 
-int streamOpenAppend(const char *filename)
+void serializeUnpackInCore(const void *buf, int buf_size, int *position,
+                           void *data, int count, int datatype, void *context)
 {
-  cdiInitialize();
+  int size = serializeGetSize(count, datatype, context);
+  int pos = *position;
+  xassert(INT_MAX - pos >= size && buf_size - pos >= size);
+  memcpy(data, (unsigned char *)buf + pos, (size_t)size);
+  pos += size;
+  *position = pos;
+}
 
-  int byteorder = 0;
-  int filetype = cdiGetFiletype(filename, &byteorder);
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  if ( filetype < 0 ) return filetype;
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
-  int streamID = streamOpenA(filename, "a", filetype);
 
-  if ( streamID >= 0 )
-    {
-      stream_t *streamptr = stream_to_pointer(streamID);
-      streamptr->byteorder = byteorder;
-    }
 
-  return streamID;
-}
+enum {
+  SRV_HEADER_LEN = 8,
+};
+
+
+static int initSrvLib      = 0;
+static int srvDefaultHprec = 0;
+static int srvDefaultDprec = 0;
+
 
 /*
- at Function  streamOpenWrite
- at Title     Create a new dataset
+ * A version string.
+ */
+#undef  LIBVERSION
+#define LIBVERSION      1.4.0
+#define XSTRING(x)	#x
+#define STRING(x)	XSTRING(x)
+static const char srv_libvers[] = STRING(LIBVERSION) " of " __DATE__" " __TIME__;
 
- at Prototype int streamOpenWrite(const char *path, int filetype)
- at Parameter
-    @Item  path      The name of the new dataset.
-    @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
-                     The valid CDI file format types are @func{FILETYPE_GRB}, @func{FILETYPE_GRB2}, @func{FILETYPE_NC},
-                     @func{FILETYPE_NC2}, @func{FILETYPE_NC4}, @func{FILETYPE_NC4C}, @func{FILETYPE_SRV},
-                     @func{FILETYPE_EXT} and @func{FILETYPE_IEG}.
+const char *srvLibraryVersion(void)
+{
+  return srv_libvers;
+}
 
- at Description
-The function @func{streamOpenWrite} creates a new datset.
- at Result
-Upon successful completion @func{streamOpenWrite} returns an identifier to the
-open stream. Otherwise, a negative number with the error status is returned.
 
- at Errors
- at List
-   @Item  CDI_ESYSTEM     Operating system error.
-   @Item  CDI_EINVAL      Invalid argument.
-   @Item  CDI_EUFILETYPE  Unsupported file type.
-   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
- at EndList
+static int SRV_Debug = 0;    /* If set to 1, debugging */
 
- at Example
-Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
 
- at Source
-   ...
-int streamID;
-   ...
-streamID = streamOpenWrite("foo.nc", FILETYPE_NC);
-if ( streamID < 0 ) handle_error(streamID);
-   ...
- at EndSource
- at EndFunction
-*/
-int streamOpenWrite(const char *filename, int filetype)
+void srvDebug(int debug)
 {
-  cdiInitialize();
+  SRV_Debug = debug;
 
-  return streamOpen(filename, "w", filetype);
+  if ( SRV_Debug )
+    Message("debug level %d", debug);
 }
 
 static
-void streamDefaultValue ( stream_t * streamptr )
+void srvLibInit()
 {
-  streamptr->self              = CDI_UNDEFID;
-  streamptr->accesstype        = CDI_UNDEFID;
-  streamptr->accessmode        = 0;
-  streamptr->filetype          = FILETYPE_UNDEF;
-  streamptr->byteorder         = CDI_UNDEFID;
-  streamptr->fileID            = 0;
-  streamptr->filemode          = 0;
-  streamptr->numvals           = 0;
-  streamptr->filename          = NULL;
-  streamptr->record            = NULL;
-  streamptr->varsAllocated     = 0;
-  streamptr->nrecs             = 0;
-  streamptr->nvars             = 0;
-  streamptr->vars              = NULL;
-  streamptr->ncmode            = 0;
-  streamptr->curTsID           = CDI_UNDEFID;
-  streamptr->rtsteps           = 0;
-  streamptr->ntsteps           = CDI_UNDEFID;
-  streamptr->tsteps            = NULL;
-  streamptr->tstepsTableSize   = 0;
-  streamptr->tstepsNextID      = 0;
-  streamptr->historyID         = CDI_UNDEFID;
-  streamptr->vlistID           = CDI_UNDEFID;
-  streamptr->globalatts        = 0;
-  streamptr->localatts         = 0;
-  streamptr->vct.ilev          = 0;
-  streamptr->vct.mlev          = 0;
-  streamptr->vct.ilevID        = CDI_UNDEFID;
-  streamptr->vct.mlevID        = CDI_UNDEFID;
-  streamptr->unreduced         = cdiDataUnreduced;
-  streamptr->sortname          = cdiSortName;
-  streamptr->have_missval      = cdiHaveMissval;
-  streamptr->comptype          = COMPRESS_NONE;
-  streamptr->complevel         = 0;
+  const char *envName = "SRV_PRECISION";
 
-  basetimeInit(&streamptr->basetime);
+  char *envString = getenv(envName);
+  if ( envString )
+    {
+      int nrun;
+      if ( strlen(envString) == 2 ) nrun = 1;
+      else                          nrun = 2;
+
+      int pos = 0;
+      while ( nrun-- )
+	{
+	  switch ( tolower((int) envString[pos]) )
+	    {
+	    case 'i':
+	      {
+		switch ( (int) envString[pos+1] )
+		  {
+		  case '4': srvDefaultHprec = EXSE_SINGLE_PRECISION; break;
+		  case '8': srvDefaultHprec = EXSE_DOUBLE_PRECISION; break;
+		  default:
+		    Message("Invalid digit in %s: %s", envName, envString);
+		  }
+		break;
+	      }
+	    case 'r':
+	      {
+		switch ( (int) envString[pos+1] )
+		  {
+		  case '4': srvDefaultDprec = EXSE_SINGLE_PRECISION; break;
+		  case '8': srvDefaultDprec = EXSE_DOUBLE_PRECISION; break;
+		  default:
+		    Message("Invalid digit in %s: %s", envName, envString);
+		  }
+		break;
+	      }
+	    default:
+              {
+                Message("Invalid character in %s: %s", envName, envString);
+                break;
+              }
+            }
+	  pos += 2;
+	}
+    }
 
-  int i;
-  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->xdimID[i]   = CDI_UNDEFID;
-  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ydimID[i]   = CDI_UNDEFID;
-  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
-  for ( i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
-  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncxvarID[i] = CDI_UNDEFID;
-  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncyvarID[i] = CDI_UNDEFID;
-  for ( i = 0; i < MAX_GRIDS_PS; i++ ) streamptr->ncavarID[i] = CDI_UNDEFID;
+  initSrvLib = 1;
+}
 
-  streamptr->gribContainers    = NULL;
+static
+void srvInit(srvrec_t *srvp)
+{
+  srvp->checked    = 0;
+  srvp->byteswap   = 0;
+  srvp->hprec      = 0;
+  srvp->dprec      = 0;
+  srvp->datasize   = 0;
+  srvp->buffersize = 0;
+  srvp->buffer     = NULL;
 }
 
 
-static stream_t *stream_new_entry(int resH)
+void *srvNew(void)
 {
-  stream_t *streamptr;
+  if ( ! initSrvLib ) srvLibInit();
 
-  cdiInitialize(); /* ***************** make MT version !!! */
+  srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
 
-  streamptr = (stream_t *) Malloc(sizeof(stream_t));
-  streamDefaultValue ( streamptr );
-  if (resH == CDI_UNDEFID)
-    streamptr->self = reshPut(streamptr, &streamOps);
-  else
-    {
-      streamptr->self = resH;
-      reshReplace(resH, streamptr, &streamOps);
-    }
+  srvInit(srvp);
 
-  return streamptr;
+  return (void*)srvp;
 }
 
 
-void
-cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
+void srvDelete(void *srv)
 {
-  int fileID   = streamptr->fileID;
-  int filetype = streamptr->filetype;
-  if ( fileID == CDI_UNDEFID )
-    Warning("File %s not open!", streamptr->filename);
-  else
-    switch (filetype)
-      {
-#if  defined  (HAVE_LIBGRIB)
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
-        {
-          gribClose(fileID);
-          if (recordBufIsToBeDeleted)
-            gribContainersDelete(streamptr);
-          break;
-        }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-      case FILETYPE_SRV:
-        {
-          fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            srvDelete(streamptr->record->exsep);
-          break;
-        }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-      case FILETYPE_EXT:
-        {
-          fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            extDelete(streamptr->record->exsep);
-          break;
-        }
-#endif
-#if  defined  (HAVE_LIBIEG)
-      case FILETYPE_IEG:
-        {
-          fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            iegDelete(streamptr->record->exsep);
-          break;
-        }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-      case FILETYPE_NC:
-      case FILETYPE_NC2:
-      case FILETYPE_NC4:
-      case FILETYPE_NC4C:
-        {
-          cdfClose(fileID);
-          break;
-        }
-#endif
-      default:
-        {
-          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
-          break;
-        }
-      }
-}
-
+  srvrec_t *srvp = (srvrec_t *) srv;
 
-static void deallocate_sleveltable_t(sleveltable_t *entry)
-{
-  if (entry->recordID) Free(entry->recordID);
-  if (entry->lindex)   Free(entry->lindex);
-  entry->recordID = NULL;
-  entry->lindex   = NULL;
+  if ( srvp )
+    {
+      if ( srvp->buffer ) Free(srvp->buffer);
+      Free(srvp);
+    }
 }
 
 
-/*
- at Function  streamClose
- at Title     Close an open dataset
-
- at Prototype  void streamClose(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
-
- at Description
-The function @func{streamClose} closes an open dataset.
-
- at EndFunction
-*/
-void streamClose(int streamID)
+int srvCheckFiletype(int fileID, int *swap)
 {
-  int index;
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  if ( CDI_Debug )
-    Message("streamID = %d filename = %s", streamID, streamptr->filename);
+  size_t data = 0;
+  size_t dimx = 0, dimy = 0;
+  size_t fact = 0;
+  int found = 0;
+  unsigned char buffer[72], *pbuf;
 
-  int vlistID  = streamptr->vlistID;
+  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
 
-  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
-    = (void (*)(stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
+  size_t blocklen  = (size_t) get_UINT32(buffer);
+  size_t sblocklen = (size_t) get_SUINT32(buffer);
 
-  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
+  if ( SRV_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
-  if ( streamptr->record )
+  if ( blocklen == 32 )
     {
-      if ( streamptr->record->buffer )
-        Free(streamptr->record->buffer);
-
-      Free(streamptr->record);
+     *swap = 0;
+      fact = blocklen>>3;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
+      pbuf = buffer+4*fact;      dimx = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+5*fact;      dimy = (size_t) get_UINT32(pbuf);
+      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
     }
-
-  streamptr->filetype = 0;
-  if ( streamptr->filename ) Free(streamptr->filename);
-
-  for ( index = 0; index < streamptr->nvars; index++ )
+  else if ( blocklen == 64 )
     {
-      sleveltable_t *pslev = streamptr->vars[index].recordTable;
-      unsigned nsub = streamptr->vars[index].subtypeSize >= 0
-        ? (unsigned)streamptr->vars[index].subtypeSize : 0U;
-      for (size_t isub=0; isub < nsub; isub++)
-        {
-          deallocate_sleveltable_t(pslev + isub);
-        }
-      if (pslev) Free(pslev);
+     *swap = 0;
+      fact = blocklen>>3;
+      if ( fileRead(fileID, buffer, blocklen+8) != blocklen+8 ) return found;
+      pbuf = buffer+4*fact;      dimx = (size_t) get_UINT64(pbuf);
+      pbuf = buffer+5*fact;      dimy = (size_t) get_UINT64(pbuf);
+      pbuf = buffer+blocklen+4;  data = (size_t) get_UINT32(pbuf);
     }
-  Free(streamptr->vars);
-  streamptr->vars = NULL;
-
-  for ( index = 0; index < streamptr->ntsteps; ++index )
+  else if ( sblocklen == 32 )
     {
-      if ( streamptr->tsteps[index].records )
-        Free(streamptr->tsteps[index].records);
-      if ( streamptr->tsteps[index].recIDs )
-        Free(streamptr->tsteps[index].recIDs);
-      taxisDestroyKernel(&streamptr->tsteps[index].taxis);
+     *swap = 1;
+      fact = sblocklen>>3;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
+      pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT32(pbuf);
+      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
+    }
+  else if ( sblocklen == 64 )
+    {
+     *swap = 1;
+      fact = sblocklen>>3;
+      if ( fileRead(fileID, buffer, sblocklen+8) != sblocklen+8 ) return found;
+      pbuf = buffer+4*fact;       dimx = (size_t) get_SUINT64(pbuf);
+      pbuf = buffer+5*fact;       dimy = (size_t) get_SUINT64(pbuf);
+      pbuf = buffer+sblocklen+4;  data = (size_t) get_SUINT32(pbuf);
     }
 
-  if ( streamptr->tsteps ) Free(streamptr->tsteps);
+  fileRewind(fileID);
 
-  if ( streamptr->basetime.timevar_cache ) Free(streamptr->basetime.timevar_cache);
+  if      ( data && dimx*dimy*fact == data ) found = 1;
+  else if ( data && dimx*dimy*8    == data ) found = 1;
 
-  if ( vlistID != -1 )
+  if ( SRV_Debug )
     {
-      if ( streamptr->filemode != 'w' )
-	if ( vlistInqTaxis(vlistID) != -1 )
-	  {
-	    taxisDestroy(vlistInqTaxis(vlistID));
-	  }
-
-      cdiVlistDestroy_(vlistID);
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
     }
 
-  stream_delete_entry(streamptr);
+  return found;
 }
 
-static void stream_delete_entry(stream_t *streamptr)
+
+int srvInqHeader(void *srv, int *header)
 {
-  int idx;
+  srvrec_t *srvp = (srvrec_t *) srv;
 
-  xassert ( streamptr );
+  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
+    header[i] = srvp->header[i];
 
-  idx = streamptr->self;
-  Free( streamptr );
-  reshRemove ( idx, &streamOps );
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
 
-  if ( CDI_Debug )
-    Message("Removed idx %d from stream list", idx);
+  return 0;
 }
 
 
-void cdiStreamSync_(stream_t *streamptr)
+int srvDefHeader(void *srv, const int *header)
 {
-  int fileID   = streamptr->fileID;
-  int filetype = streamptr->filetype;
-  int vlistID  = streamptr->vlistID;
-  int nvars    = vlistNvars(vlistID);
+  srvrec_t *srvp = (srvrec_t *) srv;
 
-  if ( fileID == CDI_UNDEFID )
-    Warning("File %s not open!", streamptr->filename);
-  else if ( vlistID == CDI_UNDEFID )
-    Warning("Vlist undefined for file %s!", streamptr->filename);
-  else if ( nvars == 0 )
-    Warning("No variables defined!");
-  else
+  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
+    srvp->header[i] = header[i];
+
+  srvp->datasize = (size_t)(header[4] * header[5]);
+
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
+
+  return 0;
+}
+
+static
+int srvInqData(srvrec_t *srvp, int prec, void *data)
+{
+  size_t i;
+  int ierr = 0;
+  int byteswap = srvp->byteswap;
+  size_t datasize = srvp->datasize;
+  void *buffer = srvp->buffer;
+  int dprec = srvp->dprec;
+
+  switch ( dprec )
     {
-      if ( streamptr->filemode == 'w' || streamptr->filemode == 'a' )
-	{
-	  switch (filetype)
-	    {
-#if  defined  (HAVE_LIBNETCDF)
-	    case FILETYPE_NC:
-	    case FILETYPE_NC2:
-	    case FILETYPE_NC4:
-	    case FILETYPE_NC4C:
-	      {
-		void cdf_sync(int ncid);
-		if ( streamptr->ncmode == 2 ) cdf_sync(fileID);
-		break;
-	      }
-#endif
-	    default:
-	      {
-		fileFlush(fileID);
-		break;
-	      }
-	    }
-	}
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( sizeof(FLT32) == 4 )
+	  {
+	    if ( byteswap ) swap4byte(buffer, datasize);
+
+	    if ( dprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT32));
+	    else
+	      for ( i = 0; i < datasize; i++ )
+		((double *) data)[i] = (double) ((float *) buffer)[i];
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT32));
+	  }
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+	if ( sizeof(FLT64) == 8 )
+	  {
+	    if ( byteswap ) swap8byte(buffer, datasize);
+
+	    if ( dprec == prec )
+	      memcpy(data, buffer, datasize*sizeof(FLT64));
+	    else
+	      for ( i = 0; i < datasize; i++ )
+		((float *) data)[i] = (float) ((double *) buffer)[i];
+	  }
+	else
+	  {
+	    Error("not implemented for %d byte float", sizeof(FLT64));
+	  }
+	break;
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
     }
+
+  return ierr;
 }
 
-/*
- at Function  streamSync
- at Title     Synchronize an Open Dataset to Disk
 
- at Prototype  void streamSync(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+int srvInqDataSP(void *srv, float *data)
+{
+  return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
+}
 
- at Description
-The function @func{streamSync} offers a way to synchronize the disk copy of a dataset with in-memory buffers.
 
- at EndFunction
-*/
-void streamSync(int streamID)
+int srvInqDataDP(void *srv, double *data)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-
-  void (*myStreamSync_)(stream_t *streamptr)
-    = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
-  myStreamSync_(streamptr);
+  return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
 }
 
 
-int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
+static int
+srvDefData(void *srv, int prec, const void *data)
 {
-  int taxisID = 0;
+  srvrec_t *srvp = (srvrec_t *) srv;
+  size_t i;
+  int dprec, hprec;
+  void *buffer;
 
-  stream_check_ptr(__func__, streamptr);
+  if ( srvDefaultDprec ) dprec = srvDefaultDprec;
+  else                   dprec = srvp->dprec;
 
-  if ( CDI_Debug )
-    Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+  if ( ! dprec ) dprec = prec;
 
-  int vlistID = streamptr->vlistID;
+  srvp->dprec = dprec;
 
-  int time_is_varying = vlistHasTime(vlistID);
+  if ( srvDefaultHprec ) hprec = srvDefaultHprec;
+  else                   hprec = srvp->hprec;
 
-  if ( time_is_varying )
-    {
-      taxisID = vlistInqTaxis(vlistID);
-      if ( taxisID == CDI_UNDEFID )
-        {
-          Warning("taxisID undefined for fileID = %d! Using absolute time axis.", streamptr->self);
-          taxisID = taxisCreate(TAXIS_ABSOLUTE);
-          vlistDefTaxis(vlistID, taxisID);
-        }
-    }
+  if ( ! hprec ) hprec = dprec;
 
-  int newtsID = tstepsNewEntry(streamptr);
+  srvp->hprec = hprec;
 
-  if ( tsID != newtsID )
-    Error("Internal problem: tsID = %d newtsID = %d", tsID, newtsID);
+  int *header = srvp->header;
 
-  streamptr->curTsID = tsID;
+  size_t datasize = (size_t)(header[4] * header[5]);
+  size_t blocklen = datasize * (size_t)dprec;
 
-  if ( time_is_varying )
-    {
-      taxis_t *taxisptr1 = taxisPtr(taxisID);
-      taxis_t *taxisptr2 = &streamptr->tsteps[tsID].taxis;
-      ptaxisCopy(taxisptr2, taxisptr1);
-    }
+  srvp->datasize = datasize;
 
-  streamptr->ntsteps = tsID + 1;
+  size_t buffersize = srvp->buffersize;
 
-#ifdef HAVE_LIBNETCDF
-  if ((streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C)
-      && time_is_varying)
+  if ( buffersize != blocklen )
     {
-      void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
-        = (void (*)(stream_t *, int))
-        namespaceSwitchGet(NSSWITCH_CDF_DEF_TIMESTEP).func;
-      myCdfDefTimestep(streamptr, tsID);
+      buffersize = blocklen;
+      buffer = srvp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      srvp->buffer = buffer;
+      srvp->buffersize = buffersize;
     }
-#endif
-
-  cdi_create_records(streamptr, tsID);
+  else
+    buffer = srvp->buffer;
 
-  return (int)streamptr->ntsteps;
-}
+  switch ( dprec )
+    {
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( dprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT32));
+	else
+	  for ( i = 0; i < datasize; i++ )
+	    ((float *) buffer)[i] = (float) ((double *) data)[i];
 
-/*
- at Function  streamDefTimestep
- at Title     Define time step
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	if ( dprec == prec )
+	  memcpy(buffer, data, datasize*sizeof(FLT64));
+	else
+	  for ( i = 0; i < datasize; i++ )
+	    ((double *) buffer)[i] = (double) ((float *) data)[i];
 
- at Prototype int streamDefTimestep(int streamID, int tsID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  tsID      Timestep identifier.
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
+    }
 
- at Description
-The function @func{streamDefTimestep} defines the time step of a stream.
+  return 0;
+}
 
- at Result
- at func{streamDefTimestep} returns the number of records of the time step.
 
- at EndFunction
-*/
-int streamDefTimestep(int streamID, int tsID)
+int srvDefDataSP(void *srv, const float *data)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  int (*myStreamDefTimestep_)(stream_t *streamptr, int tsID)
-    = (int (*)(stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_DEF_TIMESTEP_).func;
-  return myStreamDefTimestep_(streamptr, tsID);
+  return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
-int streamInqCurTimestepID(int streamID)
+
+int srvDefDataDP(void *srv, const double *data)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->curTsID;
+  return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
 }
 
 
-/*
- at Function  streamInqTimestep
- at Title     Get time step
-
- at Prototype int streamInqTimestep(int streamID, int tsID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
-    @Item  tsID      Timestep identifier.
-
- at Description
-The function @func{streamInqTimestep} returns the time step of a stream.
-
- at Result
- at func{streamInqTimestep} returns the number of records of the time step.
-
- at EndFunction
-*/
-int streamInqTimestep(int streamID, int tsID)
+int srvRead(int fileID, void *srv)
 {
-  int nrecs = 0;
-  int taxisID;
-  stream_t *streamptr = stream_to_pointer(streamID);
-  int vlistID = streamptr->vlistID;
+  srvrec_t *srvp = (srvrec_t *) srv;
+  size_t i;
+  union {
+    INT32 i32[SRV_HEADER_LEN];
+    INT64 i64[SRV_HEADER_LEN];
+  } tempheader;
+  void *buffer;
+  int status;
 
-  if ( tsID < streamptr->rtsteps )
+  if ( ! srvp->checked )
     {
-      streamptr->curTsID = tsID;
-      nrecs = streamptr->tsteps[tsID].nrecs;
-      streamptr->tsteps[tsID].curRecID = CDI_UNDEFID;
-      taxisID = vlistInqTaxis(vlistID);
-      if ( taxisID == -1 )
-	Error("Timestep undefined for fileID = %d", streamID);
-      ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
-
-      return nrecs;
+      status = srvCheckFiletype(fileID, &srvp->byteswap);
+      if ( status == 0 ) Error("Not a SERVICE file!");
+      srvp->checked = 1;
     }
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
-    {
-      return 0;
-    }
+  int byteswap = srvp->byteswap;
 
-  int filetype = streamptr->filetype;
+  /* read header record */
+  size_t blocklen = binReadF77Block(fileID, byteswap);
 
-  if ( CDI_Debug )
-    Message("streamID = %d  tsID = %d  filetype = %d", streamID, tsID, filetype);
+  if ( fileEOF(fileID) ) return -1;
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        nrecs = grbInqTimestep(streamptr, tsID);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        nrecs = srvInqTimestep(streamptr, tsID);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        nrecs = extInqTimestep(streamptr, tsID);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+  if ( SRV_Debug )
+    Message("blocklen = %lu", blocklen);
+
+  size_t hprec = blocklen / SRV_HEADER_LEN;
+
+  srvp->hprec = (int)hprec;
+
+  switch ( hprec )
+    {
+    case EXSE_SINGLE_PRECISION:
       {
-        nrecs = iegInqTimestep(streamptr, tsID);
+	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+
+	for ( i = 0; i < SRV_HEADER_LEN; i++ )
+          srvp->header[i] = (int)tempheader.i32[i];
+
 	break;
       }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case EXSE_DOUBLE_PRECISION:
       {
-        nrecs = cdfInqTimestep(streamptr, tsID);
+	binReadInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
+
+	for ( i = 0; i < SRV_HEADER_LEN; i++ )
+          srvp->header[i] = (int)tempheader.i64[i];
+
 	break;
       }
-#endif
     default:
       {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
+	Error("Unexpected header precision %d", hprec);
+        break;
       }
     }
 
-  taxisID = vlistInqTaxis(vlistID);
-  if ( taxisID == -1 )
-    Error("Timestep undefined for fileID = %d", streamID);
+  size_t blocklen2 = binReadF77Block(fileID, byteswap);
 
-  ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
+  if ( blocklen2 != blocklen )
+    {
+      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
+    }
 
-  return nrecs;
-}
+  srvp->datasize = (size_t)(srvp->header[4] * srvp->header[5]);
 
-#if 0
-void streamWriteContents(int streamID, char *cname)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
 
-  int vlistID = streamptr->vlistID;
+  blocklen = binReadF77Block(fileID, byteswap);
 
-  FILE *cnp = fopen(cname, "w");
+  size_t buffersize = srvp->buffersize;
 
-  if ( cnp == NULL ) SysError(cname);
+  if ( buffersize < blocklen )
+    {
+      buffersize = blocklen;
+      buffer = srvp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      srvp->buffer = buffer;
+      srvp->buffersize = buffersize;
+    }
+  else
+    buffer = srvp->buffer;
 
-  fprintf(cnp, "#CDI library version %s\n", cdiLibraryVersion());
-  fprintf(cnp, "#\n");
+  size_t datasize = srvp->datasize;
 
-  fprintf(cnp, "filename: %s\n", streamptr->filename);
-  int filetype = streamptr->filetype;
-  fprintf(cnp, "filetype: %s\n", strfiletype(filetype));
+  size_t dprec = blocklen / datasize;
 
-  fprintf(cnp, "#\n");
-  fprintf(cnp, "#grids:\n");
+  srvp->dprec = (int)dprec;
 
-  int ngrids = vlistNgrids(vlistID);
-  for ( int i = 0; i < ngrids; i++ )
+  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
     {
-      int gridID   = vlistGrid(vlistID, i);
-      int gridtype = gridInqType(gridID);
-      int xsize    = gridInqXsize(gridID);
-      int ysize    = gridInqYsize(gridID);
-      fprintf(cnp, "%4d:%4d:%4d:%4d\n", i+1, gridtype, xsize, ysize);
+      Warning("Unexpected data precision %d", dprec);
+      return -1;
     }
 
-  fprintf(cnp, "#\n");
+  fileRead(fileID, buffer, blocklen);
 
-  fprintf(cnp, "varID:code:gridID:zaxisID:tsteptype:datatype\n");
+  blocklen2 = binReadF77Block(fileID, byteswap);
 
-  int nvars = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
+  if ( blocklen2 != blocklen )
     {
-      int code      = vlistInqVarCode(vlistID, varID);
-      int gridID    = vlistInqVarGrid(vlistID, varID);
-      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-      int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-      int datatype  = vlistInqVarDatatype(vlistID, varID);
-      fprintf(cnp, "%4d:%4d:%4d:%4d:%4d:%4d:\n",
-	      varID+1, code, gridID, zaxisID, tsteptype, datatype);
+      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
     }
 
-  fprintf(cnp, "#\n");
+  return 0;
+}
 
-  fprintf(cnp, "tsID:nrecs:date:time\n");
 
-  int tsID = 0;
-  while (1)
+void srvWrite(int fileID, void *srv)
+{
+  srvrec_t *srvp = (srvrec_t *) srv;
+  size_t i;
+  union
+  {
+    INT32 i32[SRV_HEADER_LEN];
+    INT64 i64[SRV_HEADER_LEN];
+  } tempheader;
+  int byteswap = srvp->byteswap;
+  int dprec  = srvp->dprec;
+  int hprec  = srvp->hprec;
+  int *restrict header = srvp->header;
+
+  /* write header record */
+  size_t blocklen = SRV_HEADER_LEN * (size_t)hprec;
+
+  binWriteF77Block(fileID, byteswap, blocklen);
+
+  switch ( hprec )
     {
-      int nrecs      = streamptr->tsteps[tsID].nallrecs;
-      int date       = streamptr->tsteps[tsID].taxis.vdate;
-      int time       = streamptr->tsteps[tsID].taxis.vtime;
-      off_t position = streamptr->tsteps[tsID].position;
+    case EXSE_SINGLE_PRECISION:
+      {
+	for (i = 0; i < SRV_HEADER_LEN; i++)
+          tempheader.i32[i] = (INT32) header[i];
 
-      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
-	      tsID, nrecs, date, time, (long) position);
+	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	for (i = 0; i < SRV_HEADER_LEN; i++)
+          tempheader.i64[i] = (INT64) header[i];
+
+	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
 
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
-      else
 	break;
+      }
+    default:
+      {
+	Error("unexpected header precision %d", hprec);
+        break;
+      }
     }
 
-  fprintf(cnp, "#\n");
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-  fprintf(cnp, "tsID:recID:varID:levID:size:pos\n");
+  size_t datasize = (size_t)(header[4] * header[5]);
+  blocklen = datasize * (size_t)dprec;
 
-  tsID = 0;
-  while (1)
-    {
-      int nrecs = streamptr->tsteps[tsID].nallrecs;
-      for ( int recID = 0; recID < nrecs; recID++ )
-	{
-	  int varID   = streamptr->tsteps[tsID].records[recID].varID;
-	  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
-	  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
-	  long recsize = (long)streamptr->tsteps[tsID].records[recID].size;
-	  fprintf(cnp, "%4d:%4d:%4d:%4d:%4ld:%ld\n",
-		  tsID, recID, varID, levelID, recsize, (long) recpos);
-	}
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
-      else
+  srvp->datasize = datasize;
+
+  void *buffer = srvp->buffer;
+
+  switch ( dprec )
+    {
+    case EXSE_SINGLE_PRECISION:
+      {
+	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
 	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
     }
 
-  fclose(cnp);
+  binWriteF77Block(fileID, byteswap, blocklen);
 }
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _STREAM_SRV_H
+#define _STREAM_SRV_H
+
+#ifndef _SERVICE_H
 #endif
 
-// This function is used in CDO!
-off_t streamNvals(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+int    srvInqContents(stream_t *streamptr);
+int    srvInqTimestep(stream_t *streamptr, int tsID);
 
-  return streamptr->numvals;
-}
+int    srvInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void   srvDefRecord(stream_t *streamptr);
+void   srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
+void   srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
+void   srvWriteRecord(stream_t *streamptr, const double *data);
 
-/*
- at Function  streamDefVlist
- at Title     Define the variable list
+void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
+void   srvWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
- at Prototype void streamDefVlist(int streamID, int vlistID)
- at Parameter
-    @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
+void   srvReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
+void   srvWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
- at Description
-The function @func{streamDefVlist} defines the variable list of a stream.
+#endif  /* _STREAM_SRV_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _STREAM_EXT_H
+#define _STREAM_EXT_H
 
-To safeguard against errors by modifying the wrong vlist object,
-this function makes the passed vlist object immutable.
-All further vlist changes have to use the vlist object returned by streamInqVlist().
+#ifndef _EXTRA_H
+#endif
 
- at EndFunction
-*/
-void streamDefVlist(int streamID, int vlistID)
-{
-  void (*myStreamDefVlist)(int streamID, int vlistID)
-    = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
-  myStreamDefVlist(streamID, vlistID);
-}
+int    extInqContents(stream_t *streamptr);
+int    extInqTimestep(stream_t *streamptr, int tsID);
 
-/* the single image implementation of streamDefVlist */
-void
-cdiStreamDefVlist_(int streamID, int vlistID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+int    extInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void   extDefRecord(stream_t *streamptr);
+void   extCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
+void   extReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
+void   extWriteRecord(stream_t *streamptr, const double *data);
 
-  if ( streamptr->vlistID == CDI_UNDEFID )
-    {
-      int vlistCopy = vlistDuplicate(vlistID);
-      cdiVlistMakeInternal(vlistCopy);
-      cdiVlistMakeImmutable(vlistID);
-      cdiStreamSetupVlist(streamptr, vlistCopy);
-    }
-  else
-    Warning("vlist already defined for %s!", streamptr->filename);
-}
+void   extReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
+void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
+
+void   extReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
+void   extWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
+#endif  /* _STREAM_EXT_H */
 /*
- at Function  streamInqVlist
- at Title     Get the variable list
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifndef _STREAM_IEG_H
+#define _STREAM_IEG_H
 
- at Prototype int streamInqVlist(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+#ifndef _IEG_H
+#endif
 
- at Description
-The function @func{streamInqVlist} returns the variable list of a stream.
+int    iegInqContents(stream_t *streamptr);
+int    iegInqTimestep(stream_t *streamptr, int tsID);
 
- at Result
- at func{streamInqVlist} returns an identifier to the variable list.
+int    iegInqRecord(stream_t *streamptr, int *varID, int *levelID);
+void   iegDefRecord(stream_t *streamptr);
+void   iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
+void   iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
+void   iegWriteRecord(stream_t *streamptr, const double *data);
 
- at EndFunction
-*/
-int streamInqVlist(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->vlistID;
-}
+void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
+void   iegWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
+void   iegReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
+void   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
-void streamDefCompType(int streamID, int comptype)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if ( streamptr->comptype != comptype )
-    {
-      streamptr->comptype = comptype;
-      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-    }
-}
+#endif  /* _STREAM_IEG_H */
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef  HAVE_CONFIG_H
+#endif
 
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
 
-void streamDefCompLevel(int streamID, int complevel)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if ( streamptr->complevel != complevel )
-    {
-      streamptr->complevel = complevel;
-      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-    }
-}
+#include <sys/stat.h> // struct stat
+#include <ctype.h>
 
 
-int streamInqCompType(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->comptype;
-}
 
+static stream_t *stream_new_entry(int resH);
+static void stream_delete_entry(stream_t *streamptr);
+static int streamCompareP(void * streamptr1, void * streamptr2);
+static void streamDestroyP(void * streamptr);
+static void streamPrintP(void * streamptr, FILE * fp);
+static int streamGetPackSize(void * streamptr, void *context);
+static void streamPack(void * streamptr, void * buff, int size, int * position, void *context);
+static int streamTxCode(void);
 
-int streamInqCompLevel(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->complevel;
-}
+const resOps streamOps = {
+  streamCompareP,
+  streamDestroyP,
+  streamPrintP,
+  streamGetPackSize,
+  streamPack,
+  streamTxCode
+};
 
-int streamInqFileID(int streamID)
-{
-  stream_t *streamptr = ( stream_t *) reshGetVal ( streamID, &streamOps );
-  return streamptr->fileID;
-}
 
 
-void cdiDefAccesstype(int streamID, int type)
+static
+int getByteorder(int byteswap)
 {
-  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
+  int byteorder = -1;
 
-  if ( streamptr->accesstype == CDI_UNDEFID )
+  switch (HOST_ENDIANNESS)
     {
-      streamptr->accesstype = type;
+    case CDI_BIGENDIAN:
+      byteorder = byteswap ? CDI_LITTLEENDIAN : CDI_BIGENDIAN;
+      break;
+    case CDI_LITTLEENDIAN:
+      byteorder = byteswap ? CDI_BIGENDIAN : CDI_LITTLEENDIAN;
+      break;
+    /* FIXME: does not currently adjust for PDP endianness */
+    case CDI_PDPENDIAN:
+    default:
+      Error("unhandled endianness");
     }
-  else if ( streamptr->accesstype != type )
-    Error("Changing access type from %s not allowed!",
-          streamptr->accesstype == TYPE_REC ? "REC to VAR" : "VAR to REC");
-}
-
-
-int cdiInqAccesstype(int streamID)
-{
-  stream_t *streamptr = (stream_t *) reshGetVal ( streamID, &streamOps );
-  return streamptr->accesstype;
+  return byteorder;
 }
 
-static
-int streamTxCode(void)
+// used also in CDO
+int cdiGetFiletype(const char *filename, int *byteorder)
 {
-  return STREAM;
-}
+  int filetype = CDI_EUFTYPE;
+  int swap = 0;
+  int version;
+  long recpos;
 
-void
-cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
-{
-  void (*myStreamSetupVlist)(stream_t *streamptr, int vlistID)
-    = (void (*)(stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_SETUP_VLIST).func;
-  myStreamSetupVlist(streamptr, vlistID);
-}
+  int fileID = fileOpen(filename, "r");
 
-void
-cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
-{
-  int nvars = vlistNvars(vlistID);
-  streamptr->vlistID = vlistID;
-  for (int varID = 0; varID < nvars; varID++ )
+  if ( fileID == CDI_UNDEFID )
     {
-      int gridID    = vlistInqVarGrid(vlistID, varID);
-      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-      int tilesetID = vlistInqVarSubtype(vlistID, varID);
-      stream_new_var(streamptr, gridID, zaxisID, tilesetID);
-      if ( streamptr->have_missval )
-        vlistDefVarMissval(vlistID, varID,
-                           vlistInqVarMissval(vlistID, varID));
+      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
+	return CDI_FILETYPE_NC;
+      else
+	return CDI_ESYSTEM;
     }
 
-  if (streamptr->filemode == 'w')
-    switch (streamptr->filetype)
-      {
-#ifdef HAVE_LIBNETCDF
-      case FILETYPE_NC:
-      case FILETYPE_NC2:
-      case FILETYPE_NC4:
-      case FILETYPE_NC4C:
+  char buffer[8];
+  if ( fileRead(fileID, buffer, 8) != 8 )
+    {
+      struct stat buf;
+      if ( stat(filename, &buf) == 0 )
         {
-          void (*myCdfDefVars)(stream_t *streamptr)
-            = (void (*)(stream_t *))
-            namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
-          myCdfDefVars(streamptr);
+          if ( buf.st_size == 0 ) return CDI_EISEMPTY;
+          if ( buf.st_mode&S_IFDIR ) return CDI_EISDIR;
         }
-        break;
-#endif
-#ifdef HAVE_LIBGRIB
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
-        gribContainersNew(streamptr);
-        break;
-#endif
-      default:
-        ;
-      }
-}
 
+      return CDI_EUFTYPE;
+    }
 
-void cdiStreamGetIndexList(unsigned numIDs, int *IDs)
-{
-  reshGetResHListOfType(numIDs, IDs, &streamOps);
+  fileRewind(fileID);
+
+  if ( memcmp(buffer, "GRIB", 4) == 0 )
+    {
+      version = buffer[7];
+      if ( version <= 1 )
+	{
+	  filetype = CDI_FILETYPE_GRB;
+	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
+	}
+      else if ( version == 2 )
+	{
+	  filetype = CDI_FILETYPE_GRB2;
+	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
+	}
+    }
+  else if ( memcmp(buffer, "CDF\001", 4) == 0 )
+    {
+      filetype = CDI_FILETYPE_NC;
+      if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
+    }
+  else if ( memcmp(buffer, "CDF\002", 4) == 0 )
+    {
+      filetype = CDI_FILETYPE_NC2;
+      if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
+    }
+  else if ( memcmp(buffer, "CDF\005", 4) == 0 )
+    {
+      filetype = CDI_FILETYPE_NC5;
+      if ( CDI_Debug ) Message("found CDF5 file = %s", filename);
+    }
+  else if ( memcmp(buffer+1, "HDF", 3) == 0 )
+    {
+      filetype = CDI_FILETYPE_NC4;
+      if ( CDI_Debug ) Message("found HDF file = %s", filename);
+    }
+  else if ( srvCheckFiletype(fileID, &swap) )
+    {
+      filetype = CDI_FILETYPE_SRV;
+      if ( CDI_Debug ) Message("found SRV file = %s", filename);
+    }
+  else if ( extCheckFiletype(fileID, &swap) )
+    {
+      filetype = CDI_FILETYPE_EXT;
+      if ( CDI_Debug ) Message("found EXT file = %s", filename);
+    }
+  else if ( iegCheckFiletype(fileID, &swap) )
+    {
+      filetype = CDI_FILETYPE_IEG;
+      if ( CDI_Debug ) Message("found IEG file = %s", filename);
+    }
+  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
+    {
+      if ( version <= 1 )
+	{
+	  filetype = CDI_FILETYPE_GRB;
+	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
+	}
+      else if ( version == 2 )
+	{
+	  filetype = CDI_FILETYPE_GRB2;
+	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
+	}
+    }
+
+  fileClose(fileID);
+
+  *byteorder = getByteorder(swap);
+
+  return filetype;
 }
 
-int streamInqNvars ( int streamID )
+/*
+ at Function  streamInqFiletype
+ at Title     Get the filetype
+
+ at Prototype int streamInqFiletype(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+
+ at Description
+The function @func{streamInqFiletype} returns the filetype of a stream.
+
+ at Result
+ at func{streamInqFiletype} returns the type of the file format,
+one of the set of predefined CDI file format types.
+The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC}, @func{CDI_FILETYPE_NC2},
+ at func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
+
+ at EndFunction
+*/
+int streamInqFiletype(int streamID)
 {
-  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
-  return streamptr->nvars;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->filetype;
 }
 
 
-static int streamCompareP(void * streamptr1, void * streamptr2)
+int getByteswap(int byteorder)
 {
-  stream_t * s1 = ( stream_t * ) streamptr1;
-  stream_t * s2 = ( stream_t * ) streamptr2;
-  enum {
-    differ = -1,
-    equal  = 0,
-  };
-
-  xassert ( s1 );
-  xassert ( s2 );
-
-  if ( s1->filetype  != s2->filetype  ) return differ;
-  if ( s1->byteorder != s2->byteorder ) return differ;
-  if ( s1->comptype  != s2->comptype  ) return differ;
-  if ( s1->complevel != s2->complevel ) return differ;
+  int byteswap = -1;
 
-  if ( s1->filename )
+  switch (byteorder)
     {
-      if (strcmp(s1->filename, s2->filename))
-	return differ;
+    case CDI_BIGENDIAN:
+    case CDI_LITTLEENDIAN:
+    case CDI_PDPENDIAN:
+      byteswap = (HOST_ENDIANNESS != byteorder);
+      break;
+    case -1:
+      break;
+    default:
+      Error("unexpected byteorder %d query!", byteorder);
     }
-  else if ( s2->filename )
-    return differ;
 
-  return equal;
+  return byteswap;
 }
 
+/*
+ at Function  streamDefByteorder
+ at Title     Define the byte order
 
-void streamDestroyP ( void * streamptr )
-{
-  stream_t * sp = ( stream_t * ) streamptr;
-
-  xassert ( sp );
-
-  int id = sp->self;
-  streamClose ( id );
-}
+ at Prototype void streamDefByteorder(int streamID, int byteorder)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  byteorder The byte order of a dataset, one of the CDI constants @func{CDI_BIGENDIAN} and
+                     @func{CDI_LITTLEENDIAN}.
 
+ at Description
+The function @func{streamDefByteorder} defines the byte order of a binary dataset
+with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
 
-void streamPrintP   ( void * streamptr, FILE * fp )
+ at EndFunction
+*/
+void streamDefByteorder(int streamID, int byteorder)
 {
-  stream_t * sp = ( stream_t * ) streamptr;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  streamptr->byteorder = byteorder;
+  int filetype = streamptr->filetype;
 
-  if ( !sp ) return;
+  switch (filetype)
+    {
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:
+      {
+	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+	srvp->byteswap = getByteswap(byteorder);
 
-  fprintf(fp, "#\n"
-          "# streamID %d\n"
-          "#\n"
-          "self          = %d\n"
-          "accesstype    = %d\n"
-          "accessmode    = %d\n"
-          "filetype      = %d\n"
-          "byteorder     = %d\n"
-          "fileID        = %d\n"
-          "filemode      = %d\n"
-          "filename      = %s\n"
-          "nrecs         = %d\n"
-          "nvars         = %d\n"
-          "varsAllocated = %d\n"
-          "curTsID       = %d\n"
-          "rtsteps       = %d\n"
-          "ntsteps       = %ld\n"
-          "tstepsTableSize= %d\n"
-          "tstepsNextID  = %d\n"
-          "ncmode        = %d\n"
-          "vlistID       = %d\n"
-          "historyID     = %d\n"
-          "globalatts    = %d\n"
-          "localatts     = %d\n"
-          "unreduced     = %d\n"
-          "sortname      = %d\n"
-          "have_missval  = %d\n"
-          "ztype         = %d\n"
-          "zlevel        = %d\n",
-          sp->self, sp->self, sp->accesstype, sp->accessmode,
-          sp->filetype, sp->byteorder, sp->fileID, sp->filemode,
-          sp->filename, sp->nrecs, sp->nvars, sp->varsAllocated,
-          sp->curTsID, sp->rtsteps, sp->ntsteps, sp->tstepsTableSize,
-          sp->tstepsNextID, sp->ncmode, sp->vlistID, sp->historyID,
-          sp->globalatts, sp->localatts, sp->unreduced, sp->sortname,
-          sp->have_missval, sp->comptype, sp->complevel);
-}
+	break;
+      }
+#endif
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:
+      {
+	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+	extp->byteswap = getByteswap(byteorder);
 
-enum {
-  streamNint = 10,
-};
+	break;
+      }
+#endif
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:
+      {
+	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+	iegp->byteswap = getByteswap(byteorder);
 
-static int
-streamGetPackSize(void * voidP, void *context)
-{
-  stream_t * streamP = ( stream_t * ) voidP;
-  int packBufferSize
-    = serializeGetSize(streamNint, DATATYPE_INT, context)
-    + serializeGetSize(2, DATATYPE_UINT32, context)
-    + serializeGetSize((int)strlen(streamP->filename) + 1,
-                       DATATYPE_TXT, context)
-    + serializeGetSize(1, DATATYPE_FLT64, context);
-  return packBufferSize;
+	break;
+      }
+#endif
+    }
+  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
 }
 
+/*
+ at Function  streamInqByteorder
+ at Title     Get the byte order
 
-static void
-streamPack(void * streamptr, void * packBuffer, int packBufferSize,
-           int * packBufferPos, void *context)
-{
-  stream_t * streamP = ( stream_t * ) streamptr;
-  int intBuffer[streamNint];
+ at Prototype int streamInqByteorder(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
-  intBuffer[0] = streamP->self;
-  intBuffer[1] = streamP->filetype;
-  intBuffer[2] = (int)strlen(streamP->filename) + 1;
-  intBuffer[3] = streamP->vlistID;
-  intBuffer[4] = streamP->byteorder;
-  intBuffer[5] = streamP->comptype;
-  intBuffer[6] = streamP->complevel;
-  intBuffer[7] = streamP->unreduced;
-  intBuffer[8] = streamP->sortname;
-  intBuffer[9] = streamP->have_missval;
+ at Description
+The function @func{streamInqByteorder} returns the byte order of a binary dataset
+with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
 
-  serializePack(intBuffer, streamNint, DATATYPE_INT, packBuffer, packBufferSize, packBufferPos, context);
-  uint32_t d = cdiCheckSum(DATATYPE_INT, streamNint, intBuffer);
-  serializePack(&d, 1, DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
+ at Result
+ at func{streamInqByteorder} returns the type of the byte order.
+The valid CDI byte order types are @func{CDI_BIGENDIAN} and @func{CDI_LITTLEENDIAN}
 
-  serializePack(&cdiDefaultMissval, 1, DATATYPE_FLT64, packBuffer, packBufferSize, packBufferPos, context);
-  serializePack(streamP->filename, intBuffer[2], DATATYPE_TXT, packBuffer, packBufferSize, packBufferPos, context);
-  d = cdiCheckSum(DATATYPE_TXT, intBuffer[2], streamP->filename);
-  serializePack(&d, 1, DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
+ at EndFunction
+*/
+int streamInqByteorder(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->byteorder;
 }
 
-struct streamAssoc
-streamUnpack(char * unpackBuffer, int unpackBufferSize,
-             int * unpackBufferPos, int originNamespace, void *context)
+
+const char *streamFilesuffix(int filetype)
 {
-  int intBuffer[streamNint];
-  uint32_t d;
-  char filename[CDI_MAX_NAME];
+  // static char *fileSuffix[] = {"", ".grb", ".g2", ".nc", ".nc", ".nc4", ".nc4", ".srv", ".ext", ".ieg"};
+  /* note: the 2nd dimenstion of the fileSuffix array must be equal to or
+   * larger than the length of the longest suffix (dot and \0 terminator
+   * included) */
+  static const char fileSuffix[][5] = {"", ".grb", ".grb", ".nc", ".nc", ".nc", ".nc", ".srv", ".ext", ".ieg"};
+  int size = (int)(sizeof(fileSuffix)/sizeof(fileSuffix[0]));
 
-  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  intBuffer, streamNint, DATATYPE_INT, context);
-  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
-  xassert(cdiCheckSum(DATATYPE_INT, streamNint, intBuffer) == d);
+  if ( filetype > 0 && filetype < size )
+    return fileSuffix[filetype];
+  else
+    return fileSuffix[0];
+}
 
-  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &cdiDefaultMissval, 1, DATATYPE_FLT64, context);
-  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &filename, intBuffer[2], DATATYPE_TXT, context);
-  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
-  xassert(d == cdiCheckSum(DATATYPE_TXT, intBuffer[2], filename));
-  int targetStreamID = namespaceAdaptKey(intBuffer[0], originNamespace),
-    streamID = streamOpenID(filename, 'w', intBuffer[1], targetStreamID);
-  xassert(streamID >= 0 && targetStreamID == streamID);
-  streamDefByteorder(streamID, intBuffer[4]);
-  streamDefCompType(streamID, intBuffer[5]);
-  streamDefCompLevel(streamID, intBuffer[6]);
+
+const char *streamFilename(int streamID)
+{
   stream_t *streamptr = stream_to_pointer(streamID);
-  streamptr->unreduced = intBuffer[7];
-  streamptr->sortname = intBuffer[8];
-  streamptr->have_missval = intBuffer[9];
-  struct streamAssoc retval = { streamID, intBuffer[3] };
-  return retval;
+  return streamptr->filename;
 }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifdef HAVE_CONFIG_H
-#endif
+static
+long cdiInqTimeSize(int streamID)
+{
+  int tsID = 0, nrecs;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  long ntsteps = streamptr->ntsteps;
 
+  if ( ntsteps == (long)CDI_UNDEFID )
+    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
+      ntsteps = streamptr->ntsteps;
 
+  return ntsteps;
+}
 
-/* the single image implementation */
-int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
+static
+int cdiInqContents(stream_t *streamptr)
 {
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
-  // A value > 0 is returned in this case, otherwise it returns zero.
   int status = 0;
-
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  check_parg(data);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
-
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
-
   int filetype = streamptr->filetype;
 
   switch (filetype)
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+#ifdef  HAVE_LIBGRIB
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
-        grb_write_var(streamptr, varID, memtype, data, nmiss);
+        status = grbInqContents(streamptr);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvWriteVarDP(streamptr, varID, (double *)data);
+        status = srvInqContents(streamptr);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extWriteVarDP(streamptr, varID, (double *)data);
+        status = extInqContents(streamptr);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegWriteVarDP(streamptr, varID, (double *)data);
+        status = iegInqContents(streamptr);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+#ifdef  HAVE_LIBNETCDF
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
       {
-        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+        status = cdfInqContents(streamptr);
 	break;
       }
 #endif
     default:
       {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
+	if ( CDI_Debug )
+	  Message("%s support not compiled in!", strfiletype(filetype));
+
+	status = CDI_ELIBNAVAIL;
+        break;
       }
     }
 
+  if ( status == 0 )
+    {
+      int vlistID = streamptr->vlistID;
+      int taxisID = vlistInqTaxis(vlistID);
+      if ( taxisID != CDI_UNDEFID )
+        {
+          taxis_t *taxisptr1 = &streamptr->tsteps[0].taxis;
+          taxis_t *taxisptr2 = taxisPtr(taxisID);
+          ptaxisCopy(taxisptr2, taxisptr1);
+        }
+    }
+
   return status;
 }
 
-/*
- at Function  streamWriteVar
- at Title     Write a variable
+int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
+                                 int filetype, stream_t *streamptr,
+                                 int recordBufIsToBeCreated)
+{
+  int fileID;
+  switch (filetype)
+    {
+#ifdef  HAVE_LIBGRIB
+    case CDI_FILETYPE_GRB:
+#ifdef  HAVE_LIBGRIB_API
+    case CDI_FILETYPE_GRB2:
+#endif
+      {
+#ifndef __cplusplus
+        fileID = gribOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = gribOpen(filename, temp);
+#endif
+        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
+        if (recordBufIsToBeCreated)
+          {
+            streamptr->record = (Record *) Malloc(sizeof(Record));
+            streamptr->record->buffer = NULL;
+          }
+        break;
+      }
+#endif
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:
+      {
+#ifndef __cplusplus
+        fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
+        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
+        if (recordBufIsToBeCreated)
+          {
+            streamptr->record = (Record *) Malloc(sizeof(Record));
+            streamptr->record->buffer = NULL;
+            streamptr->record->exsep  = srvNew();
+          }
+        break;
+      }
+#endif
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:
+      {
+#ifndef __cplusplus
+        fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
 
- at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
+        if (recordBufIsToBeCreated)
+          {
+            streamptr->record = (Record *) Malloc(sizeof(Record));
+            streamptr->record->buffer = NULL;
+            streamptr->record->exsep  = extNew();
+          }
+        break;
+      }
+#endif
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:
+      {
+#ifndef __cplusplus
+        fileID = fileOpen(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = fileOpen(filename, temp);
+#endif
+        if ( fileID < 0 ) fileID = CDI_ESYSTEM;
+        if (recordBufIsToBeCreated)
+          {
+            streamptr->record = (Record *) Malloc(sizeof(Record));
+            streamptr->record->buffer = NULL;
+            streamptr->record->exsep  = iegNew();
+          }
+        break;
+      }
+#endif
+#ifdef  HAVE_LIBNETCDF
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC5:
+      {
+#ifndef __cplusplus
+        fileID = cdfOpen(filename, (char [2]){filemode, 0}, filetype);
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen(filename, temp, filetype);
+#endif
+        break;
+      }
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+      {
+#ifndef __cplusplus
+        fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdf4Open(filename, temp, &filetype);
+#endif
+        break;
+      }
+#endif
+    default:
+      {
+        if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
+        return CDI_ELIBNAVAIL;
+      }
+    }
 
- at Description
-The function streamWriteVar writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                               const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+  streamptr->filetype = filetype;
 
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  return fileID;
 }
 
-/*
- at Function  streamWriteVarF
- at Title     Write a variable
-
- at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
 
- at Description
-The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
- at EndFunction
-*/
-void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+int streamOpenID(const char *filename, char filemode, int filetype, int resH)
 {
-  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                              const void *data, int nmiss)
-    = (int (*)(int, int, int, const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
-  
-  if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+  if ( CDI_Debug )
+    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
+            filename?filename:"(NUL)");
+
+  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
+
+  stream_t *streamptr = stream_new_entry(resH);
+  int streamID = CDI_ESYSTEM;
+
+  int (*streamOpenDelegate)(const char *filename, char filemode,
+                            int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
+    = (int (*)(const char *, char, int, stream_t *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
+
+  int fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
+  if ( fileID < 0 )
     {
-      // In case the file format does not support single precision writing,
-      // we fall back to double precision writing, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
-      myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
-      Free(conversionBuffer);
+      streamID = fileID;
+    }
+  else
+    {
+      streamID = streamptr->self;
+      if ( streamID < 0 ) return CDI_ELIMIT;
+
+      streamptr->filemode = filemode;
+      streamptr->filename = strdupx(filename);
+      streamptr->fileID   = fileID;
+
+      if ( filemode == 'r' )
+        {
+          int vlistID = vlistCreate();
+          if ( vlistID < 0 ) return CDI_ELIMIT;
+
+          cdiVlistMakeInternal(vlistID);
+          streamptr->vlistID = vlistID;
+          /* cdiReadByteorder(streamID); */
+          int status = cdiInqContents(streamptr);
+          if ( status < 0 )
+            {
+              streamID = status;
+            }
+          else
+            {
+              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
+              vlistptr->ntsteps = streamptr->ntsteps;
+              cdiVlistMakeImmutable(vlistID);
+            }
+        }
+    }
+
+  if ( streamID < 0 )
+    {
+      Free(streamptr->record);
+      stream_delete_entry(streamptr);
     }
+
+  return streamID;
+}
+
+static
+int streamOpen(const char *filename, const char *filemode, int filetype)
+{
+  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
+  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
 }
 
-static
-int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
-{
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
+static
+int streamOpenA(const char *filename, const char *filemode, int filetype)
+{
+  if ( CDI_Debug )
+    Message("Open %s file (mode=%c); filename: %s", strfiletype(filetype), (int) *filemode, filename);
+  if ( CDI_Debug ) printf("streamOpenA: %s\n", filename); // seg fault without this line on thunder/squall with "cdo cat x y"
+
+  if ( ! filename || ! filemode || filetype < 0 ) return CDI_EINVAL;
+
+  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
+  int fileID = CDI_UNDEFID;
+
+  {
+    int (*streamOpenDelegate)(const char *filename, char filemode,
+                              int filetype, stream_t *streamptr, int recordBufIsToBeCreated)
+      = (int (*)(const char *, char, int, stream_t *, int))
+      namespaceSwitchGet(NSSWITCH_STREAM_OPEN_BACKEND).func;
+
+    fileID = streamOpenDelegate(filename, 'r', filetype, streamptr, 1);
+  }
+
+  if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
+
+  int streamID = streamptr->self;
 
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+  streamptr->filemode = tolower(*filemode);
+  streamptr->filename = strdupx(filename);
+  streamptr->fileID   = fileID;
 
-  check_parg(data);
+  streamptr->vlistID = vlistCreate();
+  cdiVlistMakeInternal(streamptr->vlistID);
+  /* cdiReadByteorder(streamID); */
+  int status = cdiInqContents(streamptr);
+  if ( status < 0 ) return status;
+  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
+  vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
+  // Needed for NetCDF4
+  for ( int varID = 0; varID < vlistptr->nvars; ++varID )
+    streamptr->vars[varID].defmiss = true;
 
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
+  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
 
-  int filetype = streamptr->filetype;
+  {
+    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
+      = (void (*)(stream_t *, int))
+      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
+
+    streamCloseDelegate(streamptr, 0);
+  }
 
   switch (filetype)
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+#ifdef  HAVE_LIBGRIB
+    case CDI_FILETYPE_GRB:
+#ifdef  HAVE_LIBGRIB_API
+    case CDI_FILETYPE_GRB2:
+#endif
       {
-        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        fileID = gribOpen(filename, filemode);
+        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+        fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+        fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+        fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-      break;
+#ifdef  HAVE_LIBNETCDF
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC5:
+      {
+	fileID = cdfOpen(filename, filemode, filetype);
+	streamptr->ncmode = 2;
+	break;
+      }
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+      {
+	fileID = cdf4Open(filename, filemode, &filetype);
+	streamptr->ncmode = 2;
+	break;
+      }
 #endif
     default:
       {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
+	if ( CDI_Debug ) Message("%s support not compiled in!", strfiletype(filetype));
+	return CDI_ELIBNAVAIL;
       }
     }
 
-  return status;
+  if ( fileID == CDI_UNDEFID )
+    streamID = CDI_UNDEFID;
+  else
+    streamptr->fileID = fileID;
+
+  return streamID;
 }
 
 /*
- at Function  streamWriteVarSlice
- at Title     Write a horizontal slice of a variable
+ at Function  streamOpenRead
+ at Title     Open a dataset for reading
 
- at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+ at Prototype int streamOpenRead(const char *path)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+    @Item  path  The name of the dataset to be read.
 
 @Description
-The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
+The function @func{streamOpenRead} opens an existing dataset for reading.
+
+ at Result
+Upon successful completion @func{streamOpenRead} returns an identifier to the
+open stream. Otherwise, a negative number with the error status is returned.
+
+ at Errors
+ at List
+   @Item  CDI_ESYSTEM     Operating system error.
+   @Item  CDI_EINVAL      Invalid argument.
+   @Item  CDI_EUFILETYPE  Unsupported file type.
+   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
+ at EndList
+
+ at Example
+Here is an example using @func{streamOpenRead} to open an existing NetCDF
+file named @func{foo.nc} for reading:
+
+ at Source
+   ...
+int streamID;
+   ...
+streamID = streamOpenRead("foo.nc");
+if ( streamID < 0 ) handle_error(streamID);
+   ...
+ at EndSource
 @EndFunction
 */
-void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+int streamOpenRead(const char *filename)
 {
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  cdiInitialize();
+
+  int byteorder = 0;
+  int filetype = cdiGetFiletype(filename, &byteorder);
+
+  if ( filetype < 0 ) return filetype;
+
+  int streamID = streamOpen(filename, "r", filetype);
+
+  if ( streamID >= 0 )
+    {
+      stream_t *streamptr = stream_to_pointer(streamID);
+      streamptr->byteorder = byteorder;
+    }
+
+  return streamID;
+}
+
+
+int streamOpenAppend(const char *filename)
+{
+  cdiInitialize();
+
+  int byteorder = 0;
+  int filetype = cdiGetFiletype(filename, &byteorder);
+
+  if ( filetype < 0 ) return filetype;
+
+  int streamID = streamOpenA(filename, "a", filetype);
+
+  if ( streamID >= 0 )
+    {
+      stream_t *streamptr = stream_to_pointer(streamID);
+      streamptr->byteorder = byteorder;
+    }
+
+  return streamID;
 }
 
 /*
- at Function  streamWriteVarSliceF
- at Title     Write a horizontal slice of a variable
+ at Function  streamOpenWrite
+ at Title     Create a new dataset
 
- at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+ at Prototype int streamOpenWrite(const char *path, int filetype)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to a block of single precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+    @Item  path      The name of the new dataset.
+    @Item  filetype  The type of the file format, one of the set of predefined CDI file format types.
+                     The valid CDI file format types are @func{CDI_FILETYPE_GRB}, @func{CDI_FILETYPE_GRB2}, @func{CDI_FILETYPE_NC},
+                     @func{CDI_FILETYPE_NC2}, @func{CDI_FILETYPE_NC4}, @func{CDI_FILETYPE_NC4C}, @func{CDI_FILETYPE_NC5}, @func{CDI_FILETYPE_SRV},
+                     @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
 
 @Description
-The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
+The function @func{streamOpenWrite} creates a new datset.
+ at Result
+Upon successful completion @func{streamOpenWrite} returns an identifier to the
+open stream. Otherwise, a negative number with the error status is returned.
+
+ at Errors
+ at List
+   @Item  CDI_ESYSTEM     Operating system error.
+   @Item  CDI_EINVAL      Invalid argument.
+   @Item  CDI_EUFILETYPE  Unsupported file type.
+   @Item  CDI_ELIBNAVAIL  Library support not compiled in.
+ at EndList
+
+ at Example
+Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
+
+ at Source
+   ...
+int streamID;
+   ...
+streamID = streamOpenWrite("foo.nc", CDI_FILETYPE_NC);
+if ( streamID < 0 ) handle_error(streamID);
+   ...
+ at EndSource
 @EndFunction
 */
-void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+int streamOpenWrite(const char *filename, int filetype)
 {
-  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
-    {
-      // In case the file format does not support single precision writing,
-      // we fall back to double precision writing, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
-      streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
-      Free(conversionBuffer);
-    }
-}
-
+  cdiInitialize();
 
-void
-streamWriteVarChunk(int streamID, int varID,
-                    const int rect[][2], const double *data, int nmiss)
-{
-  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
-                                    const int rect[][2], const void *data,
-                                    int nmiss)
-    = (void (*)(int, int, int, const int [][2], const void *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
-  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
+  return streamOpen(filename, "w", filetype);
 }
 
-/* single image implementation */
-void
-cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss)
+static
+void streamDefaultValue ( stream_t * streamptr )
 {
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
-
-  stream_t *streamptr = stream_to_pointer(streamID);
+  streamptr->self              = CDI_UNDEFID;
+  streamptr->accesstype        = CDI_UNDEFID;
+  streamptr->accessmode        = 0;
+  streamptr->filetype          = CDI_FILETYPE_UNDEF;
+  streamptr->byteorder         = CDI_UNDEFID;
+  streamptr->fileID            = 0;
+  streamptr->filemode          = 0;
+  streamptr->numvals           = 0;
+  streamptr->filename          = NULL;
+  streamptr->record            = NULL;
+  streamptr->varsAllocated     = 0;
+  streamptr->nrecs             = 0;
+  streamptr->nvars             = 0;
+  streamptr->vars              = NULL;
+  streamptr->ncmode            = 0;
+  streamptr->curTsID           = CDI_UNDEFID;
+  streamptr->rtsteps           = 0;
+  streamptr->ntsteps           = CDI_UNDEFID;
+  streamptr->tsteps            = NULL;
+  streamptr->tstepsTableSize   = 0;
+  streamptr->tstepsNextID      = 0;
+  streamptr->historyID         = CDI_UNDEFID;
+  streamptr->vlistID           = CDI_UNDEFID;
+  streamptr->globalatts        = 0;
+  streamptr->localatts         = 0;
+  streamptr->unreduced         = cdiDataUnreduced;
+  streamptr->sortname          = cdiSortName > 0;
+  streamptr->sortparam         = cdiSortParam > 0;
+  streamptr->have_missval      = cdiHaveMissval;
+  streamptr->comptype          = CDI_COMPRESS_NONE;
+  streamptr->complevel         = 0;
 
-  // streamDefineTaxis(streamID);
+  basetimeInit(&streamptr->basetime);
 
-  int filetype = streamptr->filetype;
+#ifdef HAVE_LIBNETCDF
+  for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->zaxisID[i]  = CDI_UNDEFID;
+  for ( int i = 0; i < MAX_ZAXES_PS; i++ ) streamptr->nczvarID[i] = CDI_UNDEFID;
 
-  switch (filetype)
+  for ( int i = 0; i < MAX_GRIDS_PS; i++ )
     {
-#if defined (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-#endif
-#if defined (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-#endif
-#if defined (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-#endif
-#if defined (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-#endif
-#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
-  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
-      xabort("streamWriteVarChunk not implemented for filetype %s!",
-             strfiletype(filetype));
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
-      break;
-#endif
-    default:
-      Error("%s support not compiled in!", strfiletype(filetype));
-      break;
+      streamptr->ncgrid[i].gridID = CDI_UNDEFID;
+      for (size_t j = 0; j < CDF_SIZE_ncIDs; ++j)
+        streamptr->ncgrid[i].ncIDs[j] = CDI_UNDEFID;
     }
+
+  streamptr->vct.ilev          = 0;
+  streamptr->vct.mlev          = 0;
+  streamptr->vct.ilevID        = CDI_UNDEFID;
+  streamptr->vct.mlevID        = CDI_UNDEFID;
+#endif
+
+  streamptr->gribContainers    = NULL;
 }
 
 static
-int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
+stream_t *stream_new_entry(int resH)
 {
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
-
-  check_parg(data);
+  cdiInitialize(); /* ***************** make MT version !!! */
 
-  stream_t *streamptr = stream_to_pointer(streamID);
+  stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));
+  streamDefaultValue ( streamptr );
 
-  switch (streamptr->filetype)
+  if (resH == CDI_UNDEFID)
+    streamptr->self = reshPut(streamptr, &streamOps);
+  else
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grb_write_record(streamptr, memtype, data, nmiss);
-      break;
+      streamptr->self = resH;
+      reshReplace(resH, streamptr, &streamOps);
+    }
+
+  return streamptr;
+}
+
+
+void cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
+{
+  int fileID   = streamptr->fileID;
+  int filetype = streamptr->filetype;
+  if ( fileID == CDI_UNDEFID )
+    Warning("File %s not open!", streamptr->filename);
+  else
+    switch (filetype)
+      {
+#ifdef  HAVE_LIBGRIB
+      case CDI_FILETYPE_GRB:
+      case CDI_FILETYPE_GRB2:
+        {
+          gribClose(fileID);
+          if ( recordBufIsToBeDeleted ) gribContainersDelete(streamptr);
+          break;
+        }
 #endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      srvWriteRecord(streamptr, (const double *)data);
-      break;
+#ifdef  HAVE_LIBSERVICE
+      case CDI_FILETYPE_SRV:
+        {
+          fileClose(fileID);
+          if ( recordBufIsToBeDeleted ) srvDelete(streamptr->record->exsep);
+          break;
+        }
 #endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      extWriteRecord(streamptr, (const double *)data);
-      break;
+#ifdef  HAVE_LIBEXTRA
+      case CDI_FILETYPE_EXT:
+        {
+          fileClose(fileID);
+          if ( recordBufIsToBeDeleted ) extDelete(streamptr->record->exsep);
+          break;
+        }
 #endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      iegWriteRecord(streamptr, (const double *)data);
-      break;
+#ifdef  HAVE_LIBIEG
+      case CDI_FILETYPE_IEG:
+        {
+          fileClose(fileID);
+          if ( recordBufIsToBeDeleted ) iegDelete(streamptr->record->exsep);
+          break;
+        }
 #endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-	cdf_write_record(streamptr, memtype, data, nmiss);
-	break;
-      }
+#ifdef  HAVE_LIBNETCDF
+      case CDI_FILETYPE_NC:
+      case CDI_FILETYPE_NC2:
+      case CDI_FILETYPE_NC4:
+      case CDI_FILETYPE_NC4C:
+      case CDI_FILETYPE_NC5:
+        {
+          cdfClose(fileID);
+          if (streamptr->ntsteps == 0)
+            {
+              if ( streamptr->tsteps[0].records )
+                {
+                  Free(streamptr->tsteps[0].records);
+                  streamptr->tsteps[0].records = NULL;
+                }
+              if ( streamptr->tsteps[0].recIDs )
+                {
+                  Free(streamptr->tsteps[0].recIDs);
+                  streamptr->tsteps[0].recIDs = NULL;
+                }
+            }
+          break;
+        }
 #endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
+      default:
+        {
+          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
+          break;
+        }
       }
-    }
+}
 
-  return status;
+
+static
+void deallocate_sleveltable_t(sleveltable_t *entry)
+{
+  if (entry->recordID) Free(entry->recordID);
+  if (entry->lindex)   Free(entry->lindex);
+  entry->recordID = NULL;
+  entry->lindex   = NULL;
 }
 
+
 /*
- at Function  streamWriteRecord
- at Title     Write a horizontal slice of a variable
+ at Function  streamClose
+ at Title     Close an open dataset
 
- at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
+ at Prototype  void streamClose(int streamID)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  data      Pointer to a block of double precision floating point data values to be written.
-    @Item  nmiss     Number of missing values.
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
 @Description
-The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
-The values are converted to the external data type of the variable, if necessary.
+The function @func{streamClose} closes an open dataset.
+
 @EndFunction
 */
-void streamWriteRecord(int streamID, const double *data, int nmiss)
+void streamClose(int streamID)
 {
-  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  if ( CDI_Debug )
+    Message("streamID = %d filename = %s", streamID, streamptr->filename);
+
+  int vlistID  = streamptr->vlistID;
+
+  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
+    = (void (*)(stream_t *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
+
+  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
+
+  if ( streamptr->record )
+    {
+      if ( streamptr->record->buffer )
+        Free(streamptr->record->buffer);
+
+      Free(streamptr->record);
+    }
+
+  streamptr->filetype = 0;
+  if ( streamptr->filename ) Free(streamptr->filename);
+
+  for ( int index = 0; index < streamptr->nvars; index++ )
+    {
+      sleveltable_t *pslev = streamptr->vars[index].recordTable;
+      unsigned nsub = streamptr->vars[index].subtypeSize >= 0
+        ? (unsigned)streamptr->vars[index].subtypeSize : 0U;
+      for (size_t isub=0; isub < nsub; isub++)
+        {
+          deallocate_sleveltable_t(pslev + isub);
+        }
+      if (pslev) Free(pslev);
+    }
+  Free(streamptr->vars);
+  streamptr->vars = NULL;
+
+  for ( int index = 0; index < streamptr->ntsteps; ++index )
+    {
+      if ( streamptr->tsteps[index].records ) Free(streamptr->tsteps[index].records);
+      if ( streamptr->tsteps[index].recIDs  ) Free(streamptr->tsteps[index].recIDs);
+      taxisDestroyKernel(&streamptr->tsteps[index].taxis);
+    }
+
+  if ( streamptr->tsteps ) Free(streamptr->tsteps);
+
+  if ( streamptr->basetime.timevar_cache ) Free(streamptr->basetime.timevar_cache);
+
+  if ( vlistID != -1 )
+    {
+      if ( streamptr->filemode != 'w' && vlistInqTaxis(vlistID) != -1 )
+        taxisDestroy(vlistInqTaxis(vlistID));
+
+      cdiVlistDestroy_(vlistID);
+    }
+
+  stream_delete_entry(streamptr);
+}
+
+static
+void stream_delete_entry(stream_t *streamptr)
+{
+  xassert ( streamptr );
+
+  int idx = streamptr->self;
+  Free(streamptr);
+  reshRemove ( idx, &streamOps );
+
+  if ( CDI_Debug )
+    Message("Removed idx %d from stream list", idx);
 }
 
 
-void streamWriteRecordF(int streamID, const float *data, int nmiss)
+void cdiStreamSync_(stream_t *streamptr)
 {
-  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+  int fileID   = streamptr->fileID;
+  int filetype = streamptr->filetype;
+  int vlistID  = streamptr->vlistID;
+  int nvars    = vlistNvars(vlistID);
+
+  if      ( fileID == CDI_UNDEFID )  Warning("File %s not open!", streamptr->filename);
+  else if ( vlistID == CDI_UNDEFID ) Warning("Vlist undefined for file %s!", streamptr->filename);
+  else if ( nvars == 0 )             Warning("No variables defined!");
+  else
     {
-      // In case the file format does not support single precision writing,
-      // we fall back to double precision writing, converting the data on the fly.
-      stream_t *streamptr = stream_to_pointer(streamID);
-      int varID  = streamptr->record->varID;
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
-      streamWriteRecord(streamID, conversionBuffer, nmiss);
-      Free(conversionBuffer);
+      if ( streamptr->filemode == 'w' || streamptr->filemode == 'a' )
+	{
+	  switch (filetype)
+	    {
+#ifdef  HAVE_LIBNETCDF
+	    case CDI_FILETYPE_NC:
+	    case CDI_FILETYPE_NC2:
+	    case CDI_FILETYPE_NC4:
+	    case CDI_FILETYPE_NC4C:
+	    case CDI_FILETYPE_NC5:
+	      {
+		void cdf_sync(int ncid);
+		if ( streamptr->ncmode == 2 ) cdf_sync(fileID);
+		break;
+	      }
+#endif
+	    default:
+	      {
+		fileFlush(fileID);
+		break;
+	      }
+	    }
+	}
     }
 }
 
-#ifdef HAVE_CONFIG_H
-#endif
+/*
+ at Function  streamSync
+ at Title     Synchronize an Open Dataset to Disk
 
+ at Prototype  void streamSync(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
 
+ at Description
+The function @func{streamSync} offers a way to synchronize the disk copy of a dataset with in-memory buffers.
 
-/* the single image implementation */
-static
-int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
+ at EndFunction
+*/
+void streamSync(int streamID)
 {
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+  void (*myStreamSync_)(stream_t *streamptr)
+    = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
+  myStreamSync_(streamptr);
+}
 
-  check_parg(data);
-  check_parg(nmiss);
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  int filetype = streamptr->filetype;
+int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
+{
+  stream_check_ptr(__func__, streamptr);
+
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+
+  int vlistID = streamptr->vlistID;
+  int time_is_varying = vlistHasTime(vlistID);
+  int taxisID = vlistInqTaxis(vlistID) ;
+
+  /* moved to cdiStreamSetupVlist
+  int taxisID = time_is_varying ? vlistInqTaxis(vlistID) : CDI_UNDEFID;
+  if ( time_is_varying )
+    {
+      if ( taxisID == CDI_UNDEFID )
+        {
+          Warning("taxisID undefined for fileID = %d! Using absolute time axis.", streamptr->self);
+          taxisID = taxisCreate(TAXIS_ABSOLUTE);
+          vlistDefTaxis(vlistID, taxisID);
+        }
+    }
+  */
+  if ( tsID > 0 )
+    {
+      int newtsID = tstepsNewEntry(streamptr);
+      if ( tsID != newtsID )
+        Error("Internal problem: tsID = %d newtsID = %d", tsID, newtsID);
+    }
+
+  if ( time_is_varying )
+    ptaxisCopy(&streamptr->tsteps[tsID].taxis, taxisPtr(taxisID));
 
-  *nmiss = 0;
+  streamptr->curTsID = tsID;
+  streamptr->ntsteps = tsID + 1;
 
-  switch (filetype)
+#ifdef HAVE_LIBNETCDF
+  if ((streamptr->filetype == CDI_FILETYPE_NC  ||
+       streamptr->filetype == CDI_FILETYPE_NC2 ||
+       streamptr->filetype == CDI_FILETYPE_NC5 ||
+       streamptr->filetype == CDI_FILETYPE_NC4 ||
+       streamptr->filetype == CDI_FILETYPE_NC4C)
+      && time_is_varying)
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-        grb_read_var(streamptr, varID, memtype, data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      {
-        cdf_read_var(streamptr, varID, memtype, data, nmiss);
-	break;
-      }
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
-      }
+      void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
+        = (void (*)(stream_t *, int))
+        namespaceSwitchGet(NSSWITCH_CDF_DEF_TIMESTEP).func;
+      myCdfDefTimestep(streamptr, tsID);
     }
+#endif
 
-  return status;
+  cdi_create_records(streamptr, tsID);
+
+  return (int)streamptr->ntsteps;
 }
 
 /*
- at Function  streamReadVar
- at Title     Read a variable
+ at Function  streamDefTimestep
+ at Title     Define a timestep
 
- at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+ at Prototype int streamDefTimestep(int streamID, int tsID)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  tsID      Timestep identifier.
 
 @Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
+The function @func{streamDefTimestep} defines a timestep of a stream by the identifier tsID.
+The identifier tsID is the timestep index starting at 0 for the first timestep.
+Before calling this function the functions @func{taxisDefVdate} and @func{taxisDefVtime} should be used
+to define the timestamp for this timestep. All calls to write the data refer to this timestep.
+
+ at Result
+ at func{streamDefTimestep} returns the number of expected records of the timestep.
+
 @EndFunction
 */
-void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+int streamDefTimestep(int streamID, int tsID)
 {
-  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int (*myStreamDefTimestep_)(stream_t *streamptr, int tsID)
+    = (int (*)(stream_t *, int))
+    namespaceSwitchGet(NSSWITCH_STREAM_DEF_TIMESTEP_).func;
+  return myStreamDefTimestep_(streamptr, tsID);
+}
+
+
+int streamInqCurTimestepID(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->curTsID;
 }
 
 /*
- at Function  streamReadVarF
- at Title     Read a variable
+ at Function  streamInqTimestep
+ at Title     Get timestep information
 
- at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
+ at Prototype int streamInqTimestep(int streamID, int tsID)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+    @Item  tsID      Timestep identifier.
 
 @Description
-The function streamReadVar reads all the values of one time step of a variable
-from an open dataset.
+The function @func{streamInqTimestep} sets the next timestep to the identifier tsID.
+The identifier tsID is the timestep index starting at 0 for the first timestep.
+After a call to this function the functions @func{taxisInqVdate} and @func{taxisInqVtime} can be used
+to read the timestamp for this timestep. All calls to read the data refer to this timestep.
+
+ at Result
+ at func{streamInqTimestep} returns the number of records of the timestep or 0, if the end of the file is reached.
+
 @EndFunction
 */
-void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
+int streamInqTimestep(int streamID, int tsID)
 {
-  if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
-    {
-      // In case the file format does not support single precision reading,
-      // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      streamReadVar(streamID, varID, conversionBuffer, nmiss);
-      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
-      Free(conversionBuffer);
-    }
-}
-
+  int nrecs = 0;
+  int taxisID;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int vlistID = streamptr->vlistID;
 
-static
-int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
-{
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
+  if ( tsID < streamptr->rtsteps )
+    {
+      streamptr->curTsID = tsID;
+      nrecs = streamptr->tsteps[tsID].nrecs;
+      streamptr->tsteps[tsID].curRecID = CDI_UNDEFID;
+      taxisID = vlistInqTaxis(vlistID);
+      if ( taxisID == -1 )
+	Error("Timestep undefined for fileID = %d", streamID);
+      ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
 
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+      return nrecs;
+    }
 
-  check_parg(data);
-  check_parg(nmiss);
+  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
+    {
+      return 0;
+    }
 
-  stream_t *streamptr = stream_to_pointer(streamID);
   int filetype = streamptr->filetype;
 
-  *nmiss = 0;
+  if ( CDI_Debug )
+    Message("streamID = %d  tsID = %d  filetype = %d", streamID, tsID, filetype);
 
   switch (filetype)
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+#ifdef  HAVE_LIBGRIB
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
-        grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        nrecs = grbInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+#ifdef  HAVE_LIBSERVICE
+    case CDI_FILETYPE_SRV:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+        nrecs = srvInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+#ifdef  HAVE_LIBEXTRA
+    case CDI_FILETYPE_EXT:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+        nrecs = extInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+#ifdef  HAVE_LIBIEG
+    case CDI_FILETYPE_IEG:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+        nrecs = iegInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+#ifdef  HAVE_LIBNETCDF
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
       {
-        cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-        break;
+        nrecs = cdfInqTimestep(streamptr, tsID);
+	break;
       }
 #endif
     default:
       {
 	Error("%s support not compiled in!", strfiletype(filetype));
-        status = 2;
 	break;
       }
     }
 
-  return status;
-}
-
-/*
- at Function  streamReadVarSlice
- at Title     Read a horizontal slice of a variable
-
- at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
-
- at Description
-The function streamReadVarSlice reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
-    {
-      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      memset(data, 0, elementCount * sizeof(*data));
-    }
-}
-
-/*
- at Function  streamReadVarSliceF
- at Title     Read a horizontal slice of a variable
+  taxisID = vlistInqTaxis(vlistID);
+  if ( taxisID == -1 )
+    Error("Timestep undefined for fileID = %d", streamID);
 
- at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
-    @Item  varID     Variable identifier.
-    @Item  levelID   Level identifier.
-    @Item  data      Pointer to the location into which the data values are read.
-                     The caller must allocate space for the returned values.
-    @Item  nmiss     Number of missing values.
+  ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
 
- at Description
-The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
-from an open dataset.
- at EndFunction
-*/
-void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
-{
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
-    {
-      // In case the file format does not support single precision reading,
-      // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
-      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
-      Free(conversionBuffer);
-    }
+  return nrecs;
 }
 
-static
-int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
+#if 0
+void streamWriteContents(int streamID, char *cname)
 {
-  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
-  // A value > 0 is returned in this case, otherwise it returns zero.
-  int status = 0;
-
-  check_parg(data);
-  check_parg(nmiss);
-
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  *nmiss = 0;
+  int vlistID = streamptr->vlistID;
 
-  switch (streamptr->filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grb_read_record(streamptr, memtype, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      srvReadRecord(streamptr, (double *)data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      extReadRecord(streamptr, (double *)data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      iegReadRecord(streamptr, (double *)data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
-      cdf_read_record(streamptr, memtype, data, nmiss);
-      break;
-#endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
-    }
+  FILE *cnp = fopen(cname, "w");
 
-  return status;
-}
+  if ( cnp == NULL ) SysError(cname);
 
+  fprintf(cnp, "#CDI library version %s\n"
+          "#\n", cdiLibraryVersion());
 
-void streamReadRecord(int streamID, double *data, int *nmiss)
-{
-  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
-}
+  int filetype = streamptr->filetype;
+  fprintf(cnp, "filename: %s\n"
+          "filetype: %s\n", streamptr->filename, strfiletype(filetype));
 
+  fputs("#\n#grids:\n", cnp);
 
-void streamReadRecordF(int streamID, float *data, int *nmiss)
-{
-  if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
+  int ngrids = vlistNgrids(vlistID);
+  for ( int i = 0; i < ngrids; i++ )
     {
-      // In case the file format does not support single precision reading,
-      // we fall back to double precision reading, converting the data on the fly.
-      stream_t *streamptr = stream_to_pointer(streamID);
-      int tsID   = streamptr->curTsID;
-      int vrecID = streamptr->tsteps[tsID].curRecID;
-      int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
-      int varID  = streamptr->tsteps[tsID].records[recID].varID;
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
-      streamReadRecord(streamID, conversionBuffer, nmiss);
-      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
-      Free(conversionBuffer);
+      int gridID   = vlistGrid(vlistID, i);
+      int gridtype = gridInqType(gridID);
+      size_t xsize    = gridInqXsize(gridID);
+      size_t ysize    = gridInqYsize(gridID);
+      fprintf(cnp, "%4d:%4d:%4zu:%4zu\n", i+1, gridtype, xsize, ysize);
     }
-}
-#ifndef _VARSCAN_H
-#define _VARSCAN_H
-
-#ifndef _GRID_H
-#endif
-
-
-void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
-		  int level1, int level2, int level_sf, int level_unit, int prec,
-		  int *pvarID, int *plevelID, int tsteptype, int numavg, int ltype1, int ltype2,
-		  const char *name, const char *stdname, const char *longname, const char *units,
-                  const var_tile_t *tiles, int *tile_index);
-
-void varDefVCT(size_t vctsize, double *vctptr);
-void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
 
-int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
-		 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
-		 const char *longname, const char *units, int prec, int mode, int ltype);
+  fputs("#\nvarID:code:gridID:zaxisID:tsteptype:datatype\n", cnp);
 
-void varDefMissval(int varID, double missval);
-void varDefCompType(int varID, int comptype);
-void varDefCompLevel(int varID, int complevel);
-void varDefInst(int varID, int instID);
-int  varInqInst(int varID);
-void varDefModel(int varID, int modelID);
-int  varInqModel(int varID);
-void varDefTable(int varID, int tableID);
-int  varInqTable(int varID);
-void varDefEnsembleInfo(int varID, int ens_idx, int ens_count, int forecast_type);
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int code      = vlistInqVarCode(vlistID, varID);
+      int gridID    = vlistInqVarGrid(vlistID, varID);
+      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+      int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+      int datatype  = vlistInqVarDatatype(vlistID, varID);
+      fprintf(cnp, "%4d:%4d:%4d:%4d:%4d:%4d:\n",
+	      varID+1, code, gridID, zaxisID, tsteptype, datatype);
+    }
 
-void varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
-void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
+  fputs("#\ntsID:nrecs:date:time\n", cnp);
 
+  int tsID = 0;
+  while (1)
+    {
+      int nrecs      = streamptr->tsteps[tsID].nallrecs;
+      int date       = streamptr->tsteps[tsID].taxis.vdate;
+      int time       = streamptr->tsteps[tsID].taxis.vtime;
+      off_t position = streamptr->tsteps[tsID].position;
 
-void varDefOptGribInt(int varID, int tile_index, long lval, const char *keyword);
-void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keyword);
-int varOptGribNentries(int varID);
+      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
+	      tsID, nrecs, date, time, (long) position);
 
-int  zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype);
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
+	break;
+    }
 
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+  fputs("#\ntsID:recID:varID:levID:size:pos\n", cnp);
 
-#ifdef HAVE_LIBNETCDF
+  tsID = 0;
+  while (1)
+    {
+      int nrecs = streamptr->tsteps[tsID].nallrecs;
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+	  int levelID = streamptr->tsteps[tsID].records[recID].levelID;
+	  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
+	  long recsize = (long)streamptr->tsteps[tsID].records[recID].size;
+	  fprintf(cnp, "%4d:%4d:%4d:%4d:%4ld:%ld\n",
+		  tsID, recID, varID, levelID, recsize, (long) recpos);
+	}
 
-//#define TEST_GROUPS 1
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
+	break;
+    }
 
-#include <limits.h>
-#include <ctype.h>
-#include <math.h>
-#include <float.h>
-#ifdef HAVE_MMAP
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#endif
-#ifdef HAVE_LIBPTHREAD
-#include <pthread.h>
+  fclose(cnp);
+}
 #endif
 
-#include <netcdf.h>
-
-
-//#define PROJECTION_TEST
+// This function is used in CDO!
+size_t streamNvals(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->numvals;
+}
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+/*
+ at Function  streamDefVlist
+ at Title     Define the variable list
 
-static const char bndsName[] = "bnds";
+ at Prototype void streamDefVlist(int streamID, int vlistID)
+ at Parameter
+    @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
 
-#define  X_AXIS  1
-#define  Y_AXIS  2
-#define  Z_AXIS  3
-#define  T_AXIS  4
+ at Description
+The function @func{streamDefVlist} defines the variable list of a stream.
 
-#define  POSITIVE_UP    1
-#define  POSITIVE_DOWN  2
+To safeguard against errors by modifying the wrong vlist object,
+this function makes the passed vlist object immutable.
+All further vlist changes have to use the vlist object returned by streamInqVlist().
 
-typedef struct {
-  int     ncvarid;
-  int     dimtype;
-  size_t  len;
-  char    name[CDI_MAX_NAME];
+ at EndFunction
+*/
+void streamDefVlist(int streamID, int vlistID)
+{
+  void (*myStreamDefVlist)(int streamID, int vlistID)
+    = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
+  myStreamDefVlist(streamID, vlistID);
 }
-ncdim_t;
-#define  MAX_COORDVARS  4
-#define  MAX_AUXVARS    4
 
-typedef struct {
-  int      ncid;
-  int      ignore;
-  short    isvar;
-  short    islon;
-  int      islat;
-  int      islev;
-  int      istime;
-  int      warn;
-  int      tsteptype;
-  int      param;
-  int      code;
-  int      tabnum;
-  int      climatology;
-  int      bounds;
-  int      lformula;
-  int      lformulaterms;
-  int      gridID;
-  int      zaxisID;
-  int      gridtype;
-  int      zaxistype;
-  int      xdim;
-  int      ydim;
-  int      zdim;
-  int      xvarid;
-  int      yvarid;
-  int      zvarid;
-  int      tvarid;
-  int      psvarid;
-  int      p0varid;
-  int      ncoordvars;
-  int      coordvarids[MAX_COORDVARS];
-  int      nauxvars;
-  int      auxvarids[MAX_AUXVARS];
-  int      cellarea;
-  int      calendar;
-  int      tableID;
-  int      truncation;
-  int      position;
-  int      defmissval;
-  int      deffillval;
-  int      xtype;
-  int      ndims;
-  int      gmapid;
-  int      positive;
-  int      dimids[8];
-  int      dimtype[8];
-  int      chunks[8];
-  int      chunked;
-  int      chunktype;
-  int      natts;
-  int      deflate;
-  int      lunsigned;
-  int      lvalidrange;
-  int     *atts;
-  size_t   vctsize;
-  double  *vct;
-  double   missval;
-  double   fillval;
-  double   addoffset;
-  double   scalefactor;
-  double   validrange[2];
-  char     name[CDI_MAX_NAME];
-  char     longname[CDI_MAX_NAME];
-  char     stdname[CDI_MAX_NAME];
-  char     units[CDI_MAX_NAME];
-  char     extra[CDI_MAX_NAME];
-  ensinfo_t   *ensdata;    /* Ensemble information */
+/* the single image implementation of streamDefVlist */
+void cdiStreamDefVlist_(int streamID, int vlistID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  if ( streamptr->vlistID == CDI_UNDEFID )
+    {
+      int vlistCopy = vlistDuplicate(vlistID);
+      cdiVlistMakeInternal(vlistCopy);
+      cdiVlistMakeImmutable(vlistID);
+      cdiStreamSetupVlist(streamptr, vlistCopy);
+    }
+  else
+    Warning("vlist already defined for %s!", streamptr->filename);
 }
-ncvar_t;
 
-static
-void strtolower(char *str)
+/*
+ at Function  streamInqVlist
+ at Title     Get the variable list
+
+ at Prototype int streamInqVlist(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+
+ at Description
+The function @func{streamInqVlist} returns the variable list of a stream.
+
+ at Result
+ at func{streamInqVlist} returns an identifier to the variable list.
+
+ at EndFunction
+*/
+int streamInqVlist(int streamID)
 {
-  if ( str )
-    for (size_t i = 0; str[i]; ++i)
-      str[i] = (char)tolower((int)str[i]);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->vlistID;
 }
 
-static
-int get_timeunit(size_t len, const char *ptu)
-{
-  int timeunit = -1;
 
-  if ( len > 2 )
+void streamDefCompType(int streamID, int comptype)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if ( streamptr->comptype != comptype )
     {
-      if      ( memcmp(ptu, "sec",    3) == 0 )          timeunit = TUNIT_SECOND;
-      else if ( memcmp(ptu, "minute", 6) == 0 )          timeunit = TUNIT_MINUTE;
-      else if ( memcmp(ptu, "hour",   4) == 0 )          timeunit = TUNIT_HOUR;
-      else if ( memcmp(ptu, "day",    3) == 0 )          timeunit = TUNIT_DAY;
-      else if ( memcmp(ptu, "month",  5) == 0 )          timeunit = TUNIT_MONTH;
-      else if ( memcmp(ptu, "calendar_month", 14) == 0 ) timeunit = TUNIT_MONTH;
-      else if ( memcmp(ptu, "year",   4) == 0 )          timeunit = TUNIT_YEAR;
+      streamptr->comptype = comptype;
+      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
     }
-  else if ( len == 1 )
+}
+
+
+void streamDefCompLevel(int streamID, int complevel)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if ( streamptr->complevel != complevel )
     {
-      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
+      streamptr->complevel = complevel;
+      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
     }
+}
 
-  return timeunit;
+
+int streamInqCompType(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->comptype;
 }
 
-static
-bool isTimeUnits(const char *timeunits)
+
+int streamInqCompLevel(int streamID)
 {
-  bool status = strncmp(timeunits, "sec",    3) == 0
-    || strncmp(timeunits, "minute", 6) == 0
-    || strncmp(timeunits, "hour",   4) == 0
-    || strncmp(timeunits, "day",    3) == 0
-    || strncmp(timeunits, "month",  5) == 0;
-  return status;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->complevel;
 }
 
-static
-bool isTimeAxisUnits(const char *timeunits)
+int streamInqFileID(int streamID)
 {
-  bool status = false;
+  stream_t *streamptr = ( stream_t *) reshGetVal ( streamID, &streamOps );
+  return streamptr->fileID;
+}
 
-  size_t len = strlen(timeunits);
-  char *tu = (char *) Malloc((len+1)*sizeof(char));
-  memcpy(tu, timeunits, (len+1) * sizeof(char));
-  char *ptu = tu;
 
-  for (size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
+void cdiDefAccesstype(int streamID, int type)
+{
+  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
 
-  int timeunit = get_timeunit(len, ptu);
-  if ( timeunit != -1 )
+  if ( streamptr->accesstype == CDI_UNDEFID )
     {
-
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
-        {
-          while ( isspace(*ptu) ) ptu++;
-
-          int timetype = memcmp(ptu, "as", 2) == 0 ? TAXIS_ABSOLUTE :
-            memcmp(ptu, "since", 5) == 0 ? TAXIS_RELATIVE : -1;
-
-          status = timetype != -1;
-        }
+      streamptr->accesstype = type;
     }
+  else if ( streamptr->accesstype != type )
+    Error("Changing access type from %s not allowed!",
+          streamptr->accesstype == TYPE_REC ? "REC to VAR" : "VAR to REC");
+}
 
-  Free(tu);
 
-  return status;
+int cdiInqAccesstype(int streamID)
+{
+  stream_t *streamptr = (stream_t *) reshGetVal ( streamID, &streamOps );
+  return streamptr->accesstype;
 }
 
 static
-void scanTimeString(const char *ptu, int *rdate, int *rtime)
+int streamTxCode(void)
 {
-  int year = 1, month = 1, day = 1;
-  int hour = 0, minute = 0, second = 0;
-  int v1 = 1, v2 = 1, v3 = 1;
+  return STREAM;
+}
 
-  *rdate = 0;
-  *rtime = 0;
+void cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
+{
+  void (*myStreamSetupVlist)(stream_t *streamptr, int vlistID)
+    = (void (*)(stream_t *, int)) namespaceSwitchGet(NSSWITCH_STREAM_SETUP_VLIST).func;
+  myStreamSetupVlist(streamptr, vlistID);
+}
 
-  if ( *ptu )
+
+void cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
+{
+  streamptr->vlistID = vlistID;
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
     {
-      v1 = atoi(ptu);
-      if ( v1 < 0 ) ptu++;
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu )
-        {
-          v2 = atoi(++ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu )
-            {
-              v3 = atoi(++ptu);
-              while ( isdigit((int) *ptu) ) ptu++;
-            }
-        }
+      int gridID    = vlistInqVarGrid(vlistID, varID);
+      int zaxisID   = vlistInqVarZaxis(vlistID, varID);
+      int tilesetID = vlistInqVarSubtype(vlistID, varID);
+      stream_new_var(streamptr, gridID, zaxisID, tilesetID);
+      if ( streamptr->have_missval )
+        vlistDefVarMissval(vlistID, varID, vlistInqVarMissval(vlistID, varID));
     }
 
-  if ( v3 > 999 && v1 < 32 )
-    { year = v3; month = v2; day = v1; }
-  else
-    { year = v1; month = v2; day = v3; }
-
-  while ( isspace((int) *ptu) ) ptu++;
-
-  if ( *ptu )
+  if (streamptr->filemode == 'w')
     {
-      while ( ! isdigit((int) *ptu) ) ptu++;
-
-      hour = atoi(ptu);
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu == ':' )
+      tstepsNewEntry(streamptr); // timestep 0
+      int vlistID = streamptr->vlistID;
+      int time_is_varying = vlistHasTime(vlistID);
+      if ( time_is_varying )
         {
-          ptu++;
-          minute = atoi(ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu == ':' )
+          int taxisID = vlistInqTaxis(vlistID);
+          if ( taxisID == CDI_UNDEFID )
             {
-              ptu++;
-              second = atoi(ptu);
+              Warning("taxisID undefined for fileID = %d! Using absolute time axis.", streamptr->self);
+              taxisID = taxisCreate(TAXIS_ABSOLUTE);
+              vlistDefTaxis(vlistID, taxisID);
             }
+
+          if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
+            switch (streamptr->filetype)
+              {
+#ifdef HAVE_LIBNETCDF
+              case CDI_FILETYPE_NC:
+              case CDI_FILETYPE_NC2:
+              case CDI_FILETYPE_NC4:
+              case CDI_FILETYPE_NC4C:
+              case CDI_FILETYPE_NC5:
+                {
+                  taxis_t *taxisptr = taxisPtr(taxisID);
+                  if ( taxisptr->rdate == -1 ) taxisDefRdate(taxisID, 10101);
+                }
+                break;
+#endif
+              default:
+                ;
+              }
+          ptaxisCopy(&streamptr->tsteps[0].taxis, taxisPtr(taxisID));
         }
-    }
 
-  *rdate = cdiEncodeDate(year, month, day);
-  *rtime = cdiEncodeTime(hour, minute, second);
+      switch (streamptr->filetype)
+        {
+#ifdef HAVE_LIBNETCDF
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
+          {
+            /* calls cdfDefVars in serial mode but
+             * cdiPioClientStreamNOP (i.e. nothing) on client ranks
+             * and cdiPioServerCdfDefVars on server ranks in parallel mode*/
+            void (*myCdfDefVars)(stream_t *streamptr)
+              = (void (*)(stream_t *)) namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
+            myCdfDefVars(streamptr);
+          }
+          break;
+#endif
+#ifdef HAVE_LIBGRIB
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
+          gribContainersNew(streamptr);
+          break;
+#endif
+        default:
+          ;
+        }
+    }
 }
 
-static
-int scanTimeUnit(const char *unitstr)
-{
-  size_t len = strlen(unitstr);
-  int timeunit = get_timeunit(len, unitstr);
-  if ( timeunit == -1 )
-    Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  return timeunit;
+void cdiStreamGetIndexList(unsigned numIDs, int *IDs)
+{
+  reshGetResHListOfType(numIDs, IDs, &streamOps);
 }
 
-static
-void setForecastTime(const char *timestr, taxis_t *taxis)
+int streamInqNvars ( int streamID )
 {
-  (*taxis).fdate = 0;
-  (*taxis).ftime = 0;
-
-  int len = (int) strlen(timestr);
-  if ( len == 0 ) return;
-
-  int fdate = 0, ftime = 0;
-  scanTimeString(timestr, &fdate, &ftime);
-
-  (*taxis).fdate = fdate;
-  (*taxis).ftime = ftime;
+  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
+  return streamptr->nvars;
 }
 
-static
-int setBaseTime(const char *timeunits, taxis_t *taxis)
+
+static int streamCompareP(void * streamptr1, void * streamptr2)
 {
-  int timetype = TAXIS_ABSOLUTE;
-  int rdate = -1, rtime = -1;
+  stream_t * s1 = ( stream_t * ) streamptr1;
+  stream_t * s2 = ( stream_t * ) streamptr2;
+  enum {
+    differ = -1,
+    equal  = 0,
+  };
 
-  size_t len = strlen(timeunits);
-  char *tu = (char *) Malloc((len+1) * sizeof (char));
-  memcpy(tu, timeunits, (len+1) * sizeof (char));
-  char *ptu = tu;
+  xassert ( s1 );
+  xassert ( s2 );
 
-  for ( size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int) ptu[i]);
+  if ( s1->filetype  != s2->filetype  ) return differ;
+  if ( s1->byteorder != s2->byteorder ) return differ;
+  if ( s1->comptype  != s2->comptype  ) return differ;
+  if ( s1->complevel != s2->complevel ) return differ;
 
-  int timeunit = get_timeunit(len, ptu);
-  if ( timeunit == -1 )
+  if ( s1->filename )
     {
-      Message("Unsupported TIMEUNIT: %s!", timeunits);
-      return (1);
+      if (strcmp(s1->filename, s2->filename))
+	return differ;
     }
+  else if ( s2->filename )
+    return differ;
 
-  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-  if ( *ptu )
-    {
-      while ( isspace(*ptu) ) ptu++;
-
-      if ( memcmp(ptu, "as", 2) == 0 )
-        timetype = TAXIS_ABSOLUTE;
-      else if ( memcmp(ptu, "since", 5) == 0 )
-        timetype = TAXIS_RELATIVE;
+  return equal;
+}
 
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
-        {
-          while ( isspace(*ptu) ) ptu++;
 
-          if ( timetype == TAXIS_ABSOLUTE )
-            {
-              if ( memcmp(ptu, "%y%m%d.%f", 9) != 0 && timeunit == TUNIT_DAY )
-                {
-                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
-                  timeunit = -1;
-                }
-              else if ( memcmp(ptu, "%y%m.%f", 7) != 0 && timeunit == TUNIT_MONTH )
-                {
-                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
-                  timeunit = -1;
-                }
-            }
-          else if ( timetype == TAXIS_RELATIVE )
-            {
-              scanTimeString(ptu, &rdate, &rtime);
+void streamDestroyP ( void * streamptr )
+{
+  stream_t *sp = ( stream_t * ) streamptr;
 
-              (*taxis).rdate = rdate;
-              (*taxis).rtime = rtime;
+  xassert ( sp );
 
-              if ( CDI_Debug )
-                Message("rdate = %d  rtime = %d", rdate, rtime);
-            }
-        }
-    }
+  int id = sp->self;
+  streamClose ( id );
+}
 
-  (*taxis).type = timetype;
-  (*taxis).unit = timeunit;
 
-  Free(tu);
+void streamPrintP   ( void * streamptr, FILE * fp )
+{
+  stream_t * sp = ( stream_t * ) streamptr;
 
-  if ( CDI_Debug )
-    Message("timetype = %d  unit = %d", timetype, timeunit);
+  if ( !sp ) return;
 
-  return 0;
+  fprintf(fp, "#\n"
+          "# streamID %d\n"
+          "#\n"
+          "self          = %d\n"
+          "accesstype    = %d\n"
+          "accessmode    = %d\n"
+          "filetype      = %d\n"
+          "byteorder     = %d\n"
+          "fileID        = %d\n"
+          "filemode      = %d\n"
+          "filename      = %s\n"
+          "nrecs         = %d\n"
+          "nvars         = %d\n"
+          "varsAllocated = %d\n"
+          "curTsID       = %d\n"
+          "rtsteps       = %d\n"
+          "ntsteps       = %ld\n"
+          "tstepsTableSize= %d\n"
+          "tstepsNextID  = %d\n"
+          "ncmode        = %d\n"
+          "vlistID       = %d\n"
+          "historyID     = %d\n"
+          "globalatts    = %d\n"
+          "localatts     = %d\n"
+          "unreduced     = %d\n"
+          "sortname      = %d\n"
+          "have_missval  = %d\n"
+          "ztype         = %d\n"
+          "zlevel        = %d\n",
+          sp->self, sp->self, sp->accesstype, sp->accessmode,
+          sp->filetype, sp->byteorder, sp->fileID, sp->filemode,
+          sp->filename, sp->nrecs, sp->nvars, sp->varsAllocated,
+          sp->curTsID, sp->rtsteps, sp->ntsteps, sp->tstepsTableSize,
+          sp->tstepsNextID, sp->ncmode, sp->vlistID, sp->historyID,
+          sp->globalatts, sp->localatts, sp->unreduced, sp->sortname,
+          sp->have_missval, sp->comptype, sp->complevel);
 }
 
-static
-void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
+enum {
+  streamNint = 10,
+};
+
+static int
+streamGetPackSize(void * voidP, void *context)
 {
-  nc_type atttype;
-  size_t nc_attlen;
+  stream_t * streamP = ( stream_t * ) voidP;
+  int packBufferSize
+    = serializeGetSize(streamNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(2, CDI_DATATYPE_UINT32, context)
+    + serializeGetSize((int)strlen(streamP->filename) + 1,
+                       CDI_DATATYPE_TXT, context)
+    + serializeGetSize(1, CDI_DATATYPE_FLT64, context);
+  return packBufferSize;
+}
 
-  *attint = 0;
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+static void
+streamPack(void * streamptr, void * packBuffer, int packBufferSize,
+           int * packBufferPos, void *context)
+{
+  stream_t * streamP = ( stream_t * ) streamptr;
+  int intBuffer[streamNint];
 
-  if ( atttype != NC_CHAR )
-    {
-      int *pintatt = (int)nc_attlen > attlen
-        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
+  intBuffer[0] = streamP->self;
+  intBuffer[1] = streamP->filetype;
+  intBuffer[2] = (int)strlen(streamP->filename) + 1;
+  intBuffer[3] = streamP->vlistID;
+  intBuffer[4] = streamP->byteorder;
+  intBuffer[5] = streamP->comptype;
+  intBuffer[6] = streamP->complevel;
+  intBuffer[7] = streamP->unreduced;
+  intBuffer[8] = streamP->sortname;
+  intBuffer[9] = streamP->have_missval;
 
-      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+  serializePack(intBuffer, streamNint, CDI_DATATYPE_INT, packBuffer, packBufferSize, packBufferPos, context);
+  uint32_t d = cdiCheckSum(CDI_DATATYPE_INT, streamNint, intBuffer);
+  serializePack(&d, 1, CDI_DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
 
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
-          Free(pintatt);
-        }
-    }
+  serializePack(&cdiDefaultMissval, 1, CDI_DATATYPE_FLT64, packBuffer, packBufferSize, packBufferPos, context);
+  serializePack(streamP->filename, intBuffer[2], CDI_DATATYPE_TXT, packBuffer, packBufferSize, packBufferPos, context);
+  d = cdiCheckSum(CDI_DATATYPE_TXT, intBuffer[2], streamP->filename);
+  serializePack(&d, 1, CDI_DATATYPE_UINT32, packBuffer, packBufferSize, packBufferPos, context);
 }
 
-static
-void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
+struct streamAssoc
+streamUnpack(char * unpackBuffer, int unpackBufferSize,
+             int * unpackBufferPos, int originNamespace, void *context)
 {
-  nc_type atttype;
-  size_t nc_attlen;
-
-  *attdouble = 0;
+  int intBuffer[streamNint];
+  uint32_t d;
+  char filename[CDI_MAX_NAME];
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                  intBuffer, streamNint, CDI_DATATYPE_INT, context);
+  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                  &d, 1, CDI_DATATYPE_UINT32, context);
+  xassert(cdiCheckSum(CDI_DATATYPE_INT, streamNint, intBuffer) == d);
 
-  if ( atttype != NC_CHAR )
-    {
-      double *pdoubleatt = NULL;
+  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                  &cdiDefaultMissval, 1, CDI_DATATYPE_FLT64, context);
+  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                  &filename, intBuffer[2], CDI_DATATYPE_TXT, context);
+  serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                  &d, 1, CDI_DATATYPE_UINT32, context);
+  xassert(d == cdiCheckSum(CDI_DATATYPE_TXT, intBuffer[2], filename));
+  int targetStreamID = namespaceAdaptKey(intBuffer[0], originNamespace),
+    streamID = streamOpenID(filename, 'w', intBuffer[1], targetStreamID);
+  xassert(streamID >= 0 && targetStreamID == streamID);
+  streamDefByteorder(streamID, intBuffer[4]);
+  streamDefCompType(streamID, intBuffer[5]);
+  streamDefCompLevel(streamID, intBuffer[6]);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  streamptr->unreduced = intBuffer[7];
+  streamptr->sortname = intBuffer[8];
+  streamptr->have_missval = intBuffer[9];
+  struct streamAssoc retval = { streamID, intBuffer[3] };
+  return retval;
+}
 
-      if ( (int)nc_attlen > attlen )
-        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
-      else
-        pdoubleatt = attdouble;
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
+#endif
 
-      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
 
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
-          Free(pdoubleatt);
-        }
-    }
-}
 
-static
-void cdfGetAttText(int fileID, int ncvarid,const char *attname, int attlen, char *atttext)
+/* the single image implementation */
+int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss)
 {
-  nc_type atttype;
-  size_t nc_attlen;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-  if ( atttype == NC_CHAR )
-    {
-      char attbuf[65636];
-      if ( nc_attlen < sizeof(attbuf) )
-        {
-          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
+  check_parg(data);
 
-          if ( (int) nc_attlen > (attlen-1) ) nc_attlen = (size_t)(attlen-1);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
 
-          attbuf[nc_attlen++] = 0;
-          memcpy(atttext, attbuf, nc_attlen);
-        }
-      else
-        {
-          atttext[0] = 0;
-        }
-    }
-#if  defined  (HAVE_NETCDF4)
-  else if ( atttype == NC_STRING )
-    {
-      if ( nc_attlen == 1 )
-        {
-          char *attbuf = NULL;
-          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
 
-          size_t ssize = strlen(attbuf) + 1;
+  int filetype = streamptr->filetype;
 
-          if ( ssize > (size_t)attlen ) ssize = (size_t)attlen;
-          memcpy(atttext, attbuf, ssize);
-          atttext[ssize - 1] = 0;
-          Free(attbuf);
-        }
-      else
-        {
-          atttext[0] = 0;
-        }
-    }
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
+      {
+        grb_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
 #endif
-}
-
-static
-int xtypeIsText(int xtype)
-{
-  int isText = FALSE;
-
-  if ( xtype == NC_CHAR )
-    isText = TRUE;
-#if  defined  (HAVE_NETCDF4)
-  else if ( xtype == NC_STRING )
-    isText = TRUE;
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
 #endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      {
+        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
 
-  return isText;
+  return status;
 }
 
-static
-int xtypeIsFloat(int xtype)
+/*
+ at Function  streamWriteVar
+ at Title     Write a variable
+
+ at Prototype void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteVar writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
 {
-  int isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
-  return isFloat;
+  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
+    = (void (*)(int, int, int, const void *, size_t))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
+
+  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 }
 
-static
-int cdfInqDatatype(int xtype, int lunsigned)
-{
-  int datatype = -1;
+/*
+ at Function  streamWriteVarF
+ at Title     Write a variable
 
-#if  defined  (HAVE_NETCDF4)
-  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
-#endif
+ at Prototype void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-  if      ( xtype == NC_BYTE   )  datatype = DATATYPE_INT8;
-  /* else if ( xtype == NC_CHAR   )  datatype = DATATYPE_UINT8; */
-  else if ( xtype == NC_SHORT  )  datatype = DATATYPE_INT16;
-  else if ( xtype == NC_INT    )  datatype = DATATYPE_INT32;
-  else if ( xtype == NC_FLOAT  )  datatype = DATATYPE_FLT32;
-  else if ( xtype == NC_DOUBLE )  datatype = DATATYPE_FLT64;
-#if  defined  (HAVE_NETCDF4)
-  else if ( xtype == NC_UBYTE  )  datatype = DATATYPE_UINT8;
-  else if ( xtype == NC_LONG   )  datatype = DATATYPE_INT32;
-  else if ( xtype == NC_USHORT )  datatype = DATATYPE_UINT16;
-  else if ( xtype == NC_UINT   )  datatype = DATATYPE_UINT32;
-  else if ( xtype == NC_INT64  )  datatype = DATATYPE_FLT64;
-  else if ( xtype == NC_UINT64 )  datatype = DATATYPE_FLT64;
-#endif
+ at Description
+The function streamWriteVarF writes the values of one time step of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
+{
+  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
+    = (int (*)(int, int, int, const void *, size_t))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
 
-  return datatype;
+  if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data
+      // on the fly.
+      int vlistID = streamInqVlist(streamID);
+      size_t elementCount = gridInqSize(vlistInqVarGrid(vlistID, varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) conversionBuffer, nmiss);
+      Free(conversionBuffer);
+    }
 }
 
-
-void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
+static
+int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
-  int vlistID1 = streamptr1->vlistID;
-  int tsID     = streamptr1->curTsID;
-  int vrecID   = streamptr1->tsteps[tsID].curRecID;
-  int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
-  int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
-  int gridID   = vlistInqVarGrid(vlistID1, ivarID);
-  int datasize = gridInqSize(gridID);
-  int datatype = vlistInqVarDatatype(vlistID1, ivarID);
-  int memtype  = datatype != DATATYPE_FLT32 ? MEMTYPE_DOUBLE : MEMTYPE_FLOAT;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  void *data
-    = Malloc((size_t)datasize
-             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-  int nmiss;
-  cdf_read_record(streamptr1, memtype, data, &nmiss);
-  cdf_write_record(streamptr2, memtype, data, nmiss);
+  check_parg(data);
 
-  Free(data);
-}
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
 
-/* not used
-int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
-{
-  int tsID, recID;
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
 
-  recID = streamptr->tsteps[0].curRecID++;
-  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
-  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
+  int filetype = streamptr->filetype;
 
-  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
+  switch (filetype)
     {
-      streamptr->tsteps[0].curRecID = 0;
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
+      {
+        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
     }
 
-  *varID   = streamptr->tsteps[0].records[recID].varID;
-  *levelID = streamptr->tsteps[0].records[recID].levelID;
+  return status;
+}
 
-  streamptr->record->varID   = *varID;
-  streamptr->record->levelID = *levelID;
+/*
+ at Function  streamWriteVarSlice
+ at Title     Write a horizontal slice of a variable
 
-  if ( CDI_Debug )
-    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);
+ at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-  return (recID+1);
-}
+ at Description
+The function streamWriteVarSlice writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
 */
-
-
-void cdfDefRecord(stream_t *streamptr)
+void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
 {
-  (void)streamptr;
+  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 }
 
-#if defined(NC_SZIP_NN_OPTION_MASK)
-static
-void cdfDefVarSzip(int ncid, int ncvarid)
-{
-  int retval;
-  /* Set options_mask and bits_per_pixel. */
-  int options_mask = NC_SZIP_NN_OPTION_MASK;
-  int bits_per_pixel = 16;
-
-  if ((retval = nc_def_var_szip(ncid, ncvarid, options_mask, bits_per_pixel)))
-    {
-      if ( retval == NC_EINVAL )
-        {
-          static int lwarn = TRUE;
+/*
+ at Function  streamWriteVarSliceF
+ at Title     Write a horizontal slice of a variable
 
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("NetCDF4/Szip compression not compiled in!");
-            }
-        }
-      else
-        Error("nc_def_var_szip failed, status = %d", retval);
-    }
-}
-#endif
+ at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to a block of single precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
 
-static
-void cdfDefTimeValue(stream_t *streamptr, int tsID)
+ at Description
+The function streamWriteVarSliceF writes the values of a horizontal slice of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
 {
-  int fileID = streamptr->fileID;
-
-  if ( CDI_Debug )
-    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
-
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
-
-  if ( streamptr->ncmode == 1 )
+  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
     }
+}
 
-  size_t index = (size_t)tsID;
-
-  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
-  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
 
-  int ncvarid = streamptr->basetime.ncvarid;
-  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+void streamWriteVarChunk(int streamID, int varID,
+                         const int rect[][2], const double *data, size_t nmiss)
+{
+  void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
+                                    const int rect[][2], const void *data, size_t nmiss)
+    = (void (*)(int, int, int, const int [][2], const void *, size_t))
+    namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
+  myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
+}
 
-  if ( taxis->has_bounds )
-    {
-      size_t start[2], count[2];
+/* single image implementation */
+void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
+                             const int rect[][2], const void *data, size_t nmiss)
+{
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-      ncvarid = streamptr->basetime.ncvarboundsid;
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
-      start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
-      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+  // streamDefineTaxis(streamID);
 
-      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
-      start[0] = (size_t)tsID; count[0] = 1; start[1] = 1; count[1] = 1;
-      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
-    }
+  int filetype = streamptr->filetype;
 
-  ncvarid = streamptr->basetime.leadtimeid;
-  if ( taxis->type == TAXIS_FORECAST && ncvarid != UNDEFID )
+  switch (filetype)
     {
-      timevalue = taxis->fc_period;
-      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+#if defined (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
+#endif
+#if defined (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+#endif
+#if defined (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+#endif
+#if defined (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+#endif
+#if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
+  || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
+      xabort("streamWriteVarChunk not implemented for filetype %s!",
+             strfiletype(filetype));
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
+      break;
+#endif
+    default:
+      Error("%s support not compiled in!", strfiletype(filetype));
+      break;
     }
-
-  /*
-printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
-  */
 }
 
 static
-int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis)
+int stream_write_record(int streamID, int memtype, const void *data, size_t nmiss)
 {
-  int time_bndsid = -1;
-  int dims[2];
-
-  dims[0] = nctimedimid;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  /* fprintf(stderr, "time has bounds\n"); */
+  check_parg(data);
 
-  if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
-    cdf_def_dim(fileID, bndsName, 2, &dims[1]);
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  const char *bndsAttName, *bndsAttVal;
-  size_t bndsAttValLen;
-  char tmpstr[CDI_MAX_NAME];
-  if ( taxis->climatology )
-    {
-      static const char climatology_bndsName[] = "climatology_bnds",
-        climatology_bndsAttName[] = "climatology";
-      bndsAttName = climatology_bndsAttName;
-      bndsAttValLen = sizeof (climatology_bndsName) - 1;
-      bndsAttVal = climatology_bndsName;
-    }
-  else
+  switch (streamptr->filetype)
     {
-      size_t taxisnameLen = strlen(taxis_name);
-      memcpy(tmpstr, taxis_name, taxisnameLen);
-      tmpstr[taxisnameLen] = '_';
-      memcpy(tmpstr + taxisnameLen + 1, bndsName, sizeof (bndsName));
-      size_t tmpstrLen = taxisnameLen + sizeof (bndsName);
-      static const char generic_bndsAttName[] = "bounds";
-      bndsAttName = generic_bndsAttName;
-      bndsAttValLen = tmpstrLen;
-      bndsAttVal = tmpstr;
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
+      grb_write_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      {
+	cdf_write_record(streamptr, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
     }
-  cdf_def_var(fileID, bndsAttVal, NC_DOUBLE, 2, dims, &time_bndsid);
-  cdf_put_att_text(fileID, nctimevarid, bndsAttName, bndsAttValLen, bndsAttVal);
 
-  return (time_bndsid);
+  return status;
 }
 
-static
-void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis)
+/*
+ at Function  streamWriteRecord
+ at Title     Write a horizontal slice of a variable
+
+ at Prototype void streamWriteRecord(int streamID, const double *data, size_t nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
+    @Item  data      Pointer to a block of double precision floating point data values to be written.
+    @Item  nmiss     Number of missing values.
+
+ at Description
+The function streamWriteRecord writes the values of a horizontal slice (record) of a variable to an open dataset.
+The values are converted to the external data type of the variable, if necessary.
+ at EndFunction
+*/
+void streamWriteRecord(int streamID, const double *data, size_t nmiss)
 {
-  unitstr[0] = 0;
+  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
+
 
-  if ( taxis0->type == TAXIS_ABSOLUTE )
+void streamWriteRecordF(int streamID, const float *data, size_t nmiss)
+{
+  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
-      if ( taxis0->unit == TUNIT_YEAR )
-        sprintf(unitstr, "year as %s", "%Y.%f");
-      else if ( taxis0->unit == TUNIT_MONTH )
-        sprintf(unitstr, "month as %s", "%Y%m.%f");
-      else
-        sprintf(unitstr, "day as %s", "%Y%m%d.%f");
+      // In case the file format does not support single precision writing,
+      // we fall back to double precision writing, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int varID = streamptr->record->varID;
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
+      streamWriteRecord(streamID, conversionBuffer, nmiss);
+      Free(conversionBuffer);
     }
-  else
-    {
-      int timeunit = taxis->unit != -1 ? taxis->unit : TUNIT_HOUR;
-      int rdate    = taxis->rdate;
-      int rtime    = taxis->rtime;
-      if ( rdate == -1 )
-        {
-          rdate  = taxis->vdate;
-          rtime  = taxis->vtime;
-        }
+}
 
-      int year, month, day, hour, minute, second;
-      cdiDecodeDate(rdate, &year, &month, &day);
-      cdiDecodeTime(rtime, &hour, &minute, &second);
+#ifdef HAVE_CONFIG_H
+#endif
 
-      if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
-      if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
-      if ( timeunit == TUNIT_3HOURS  ||
-	   timeunit == TUNIT_6HOURS  ||
-	   timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
 
-      sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d",
-              tunitNamePtr(timeunit), year, month, day, hour, minute, second);
-    }
-}
 
+/* the single image implementation */
 static
-void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
+int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, size_t *nmiss)
 {
-  unitstr[0] = 0;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-  if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
-  if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
-  if ( timeunit == TUNIT_3HOURS  ||
-       timeunit == TUNIT_6HOURS  ||
-       timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
+  check_parg(data);
+  check_parg(nmiss);
 
-  strcpy(unitstr, tunitNamePtr(timeunit));
-}
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
 
-static
-void cdfDefCalendar(int fileID, int ncvarid, int calendar)
-{
-  static const struct { int calCode; const char *calStr; } calTab[] = {
-    { CALENDAR_STANDARD, "standard" },
-    { CALENDAR_PROLEPTIC, "proleptic_gregorian" },
-    { CALENDAR_NONE, "none" },
-    { CALENDAR_360DAYS, "360_day" },
-    { CALENDAR_365DAYS, "365_day" },
-    { CALENDAR_366DAYS, "366_day" },
-  };
-  enum { calTabSize = sizeof calTab / sizeof calTab[0] };
+  *nmiss = 0;
 
-  for (size_t i = 0; i < calTabSize; ++i)
-    if (calTab[i].calCode == calendar)
+  switch (filetype)
+    {
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
-        const char *calstr = calTab[i].calStr;
-        size_t len = strlen(calstr);
-        cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
-        break;
+        grb_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarDP(streamptr, varID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      {
+        cdf_read_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
       }
+    }
+
+  return status;
 }
 
+/*
+ at Function  streamReadVar
+ at Title     Read a variable
 
-void cdfDefTime(stream_t* streamptr)
-{
-  int time_varid;
-  int time_dimid;
-  int time_bndsid = -1;
-  static const char default_name[] = "time";
+ at Prototype void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-  if ( streamptr->basetime.ncvarid != UNDEFID ) return;
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
+{
+  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+}
 
-  int fileID = streamptr->fileID;
+/*
+ at Function  streamReadVarF
+ at Title     Read a variable
 
-  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+ at Prototype void streamReadVar(int streamID, int varID, float *data, size_t *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-  taxis_t *taxis = &streamptr->tsteps[0].taxis;
+ at Description
+The function streamReadVar reads all the values of one time step of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarF(int streamID, int varID, float *data, size_t *nmiss)
+{
+  if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVar(streamID, varID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
+}
 
-  const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ;
 
-  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
-  streamptr->basetime.ncdimid = time_dimid;
+static
+int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, size_t *nmiss)
+{
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  cdf_def_var(fileID, taxis_name, NC_DOUBLE, 1, &time_dimid, &time_varid);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-  streamptr->basetime.ncvarid = time_varid;
+  check_parg(data);
+  check_parg(nmiss);
 
-  {
-    static const char timeStr[] = "time";
-    cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr);
-  }
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
 
-  if ( taxis->longname && taxis->longname[0] )
-    cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);
+  *nmiss = 0;
 
-  if ( taxis->has_bounds )
+  switch (filetype)
     {
-      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
-      streamptr->basetime.ncvarboundsid = time_bndsid;
-    }
-
-  {
-    char unitstr[CDI_MAX_NAME];
-    cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis);
-    size_t len = strlen(unitstr);
-    if ( len )
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
-        cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
-        /*
-          if ( taxis->has_bounds )
-          cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr);
-        */
+        grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
       }
-  }
-
-  if ( taxis->calendar != -1 )
-    {
-      cdfDefCalendar(fileID, time_varid, taxis->calendar);
-      /*
-      if ( taxis->has_bounds )
-        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
-      */
-    }
-
-  if ( taxis->type == TAXIS_FORECAST )
-    {
-      int leadtimeid;
-
-      cdf_def_var(fileID, "leadtime", NC_DOUBLE, 1, &time_dimid, &leadtimeid);
-
-      streamptr->basetime.leadtimeid = leadtimeid;
-
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
       {
-        static const char stdname[] = "forecast_period";
-        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
       }
-
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
       {
-        static const char lname[] = "Time elapsed since the start of the forecast";
-        cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
+        cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        break;
       }
-
+#endif
+    default:
       {
-          char unitstr[CDI_MAX_NAME];
-          cdfDefForecastTimeUnits(unitstr, taxis->fc_unit);
-          size_t len = strlen(unitstr);
-          if ( len )
-            cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr);
+	Error("%s support not compiled in!", strfiletype(filetype));
+        status = 2;
+	break;
       }
     }
 
-  cdf_put_att_text(fileID, time_varid, "axis", 1, "T");
-
-  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+  return status;
 }
 
+/*
+ at Function  streamReadVarSlice
+ at Title     Read a horizontal slice of a variable
 
-void cdfDefTimestep(stream_t *streamptr, int tsID)
-{
-  int vlistID = streamptr->vlistID;
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  cdfDefTimeValue(streamptr, tsID);
-}
+ at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-static
-void cdfDefComplex(stream_t *streamptr, int gridID)
+ at Description
+The function streamReadVarSlice reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
 {
-  static const char axisname[] = "nc2";
-  int dimID = UNDEFID;
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int ngrids = vlistNgrids(vlistID);
-
-  for ( int index = 0; index < ngrids; index++ )
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
-        {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
-            {
-              dimID = streamptr->xdimID[index];
-              break;
-            }
-        }
+      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      memset(data, 0, elementCount * sizeof(*data));
     }
+}
 
-  if ( dimID == UNDEFID )
-    {
-      size_t dimlen = 2;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+/*
+ at Function  streamReadVarSliceF
+ at Title     Read a horizontal slice of a variable
 
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+ at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
+    @Item  varID     Variable identifier.
+    @Item  levelID   Level identifier.
+    @Item  data      Pointer to the location into which the data values are read.
+                     The caller must allocate space for the returned values.
+    @Item  nmiss     Number of missing values.
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+ at Description
+The function streamReadVarSliceF reads all the values of a horizontal slice of a variable
+from an open dataset.
+ at EndFunction
+*/
+void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
+{
+  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
     }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
 }
 
-static void
-cdfDefSPorFC(stream_t *streamptr, int gridID,
-             char *restrict axisname, int gridRefType)
+static
+int stream_read_record(int streamID, int memtype, void *data, size_t *nmiss)
 {
-  int index, iz = 0;
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
+  // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
+  // A value > 0 is returned in this case, otherwise it returns zero.
+  int status = 0;
 
-  int ngrids = vlistNgrids(vlistID);
+  check_parg(data);
+  check_parg(nmiss);
 
-  size_t dimlen = (size_t)gridInqSize(gridID)/2;
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  for ( index = 0; index < ngrids; index++ )
-    {
-      if ( streamptr->ydimID[index] != UNDEFID )
-        {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == gridRefType )
-            {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
-              if ( dimlen == dimlen0 )
-                {
-                  dimID = streamptr->ydimID[index];
-                  break;
-                }
-              else
-                iz++;
-            }
-        }
-    }
+  *nmiss = 0;
 
-  if ( dimID == UNDEFID )
+  switch (streamptr->filetype)
     {
-      int fileID  = streamptr->fileID;
-      if ( iz == 0 ) axisname[3] = '\0';
-      else           sprintf(&axisname[3], "%1d", iz+1);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+#if  defined  (HAVE_LIBGRIB)
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
+      grb_read_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case CDI_FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case CDI_FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case CDI_FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegReadRecord(streamptr, (double *)data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
+      cdf_read_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
+      }
     }
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->ydimID[gridindex] = dimID;
+  return status;
 }
 
-static
-void cdfDefSP(stream_t *streamptr, int gridID)
+
+void streamReadRecord(int streamID, double *data, size_t *nmiss)
 {
-  /*
-  char longname[] = "Spherical harmonic coefficient";
-  */
-  char axisname[5] = "nspX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_SPECTRAL);
+  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
 }
 
 
-static
-void cdfDefFC(stream_t *streamptr, int gridID)
+void streamReadRecordF(int streamID, float *data, size_t *nmiss)
 {
-  char axisname[5] = "nfcX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_FOURIER);
+  if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
+    {
+      // In case the file format does not support single precision reading,
+      // we fall back to double precision reading, converting the data on the fly.
+      stream_t *streamptr = stream_to_pointer(streamID);
+      int tsID   = streamptr->curTsID;
+      int vrecID = streamptr->tsteps[tsID].curRecID;
+      int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
+      int varID  = streamptr->tsteps[tsID].records[recID].varID;
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
+      streamReadRecord(streamID, conversionBuffer, nmiss);
+      for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
+      Free(conversionBuffer);
+    }
 }
+#ifndef _VARSCAN_H
+#define _VARSCAN_H
 
-static const struct cdfDefGridAxisInqs {
-  int (*axisSize)(int gridID);
-  void (*axisName)(int gridID, char *dimname);
-  const char *(*axisNamePtr)(int gridID);
-  void (*axisStdname)(int gridID, char *dimstdname);
-  void (*axisLongname)(int gridID, char *dimlongname);
-  void (*axisUnits)(int gridID, char *dimunits);
-  double (*axisVal)(int gridID, int index);
-  const double *(*axisValsPtr)(int gridID);
-  const double *(*axisBoundsPtr)(int gridID);
-} gridInqsX = {
-  .axisSize = gridInqXsize,
-  .axisName = gridInqXname,
-  .axisNamePtr = gridInqXnamePtr,
-  .axisStdname = gridInqXstdname,
-  .axisLongname = gridInqXlongname,
-  .axisUnits = gridInqXunits,
-  .axisVal = gridInqXval,
-  .axisValsPtr = gridInqXvalsPtr,
-  .axisBoundsPtr = gridInqXboundsPtr,
-}, gridInqsY = {
-  .axisSize = gridInqYsize,
-  .axisName = gridInqYname,
-  .axisNamePtr = gridInqYnamePtr,
-  .axisStdname = gridInqYstdname,
-  .axisLongname = gridInqYlongname,
-  .axisUnits = gridInqYunits,
-  .axisVal = gridInqYval,
-  .axisValsPtr = gridInqYvalsPtr,
-  .axisBoundsPtr = gridInqYboundsPtr,
-}, gridInqsZ = {
-  .axisStdname = zaxisInqStdname,
-  .axisLongname = zaxisInqLongname,
-  .axisUnits = zaxisInqUnits,
-};
+#ifndef _GRID_H
+#endif
 
-static void
-cdfPutGridStdAtts(int fileID, int ncvarid,
-                  int gridID, const struct cdfDefGridAxisInqs *inqs)
-{
-  size_t len;
-  {
-    char stdname[CDI_MAX_NAME];
-    inqs->axisStdname(gridID, stdname);
-    if ( (len = strlen(stdname)) )
-      cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
-  }
-  {
-    char longname[CDI_MAX_NAME];
-    inqs->axisLongname(gridID, longname);
-    if ( (len = strlen(longname)) )
-      cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
-  }
-  {
-    char units[CDI_MAX_NAME];
-    inqs->axisUnits(gridID, units);
-    if ( (len = strlen(units)) )
-      cdf_put_att_text(fileID, ncvarid, "units", len, units);
-  }
-}
 
-static void
-cdfDefTrajLatLon(stream_t *streamptr, int gridID,
-                 const struct cdfDefGridAxisInqs *inqs,
-                 int *dimID, const char *sizeName)
-{
-  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
+void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
+		  int level1, int level2, int level_sf, int level_unit, int prec,
+		  int *pvarID, int *plevelID, int tsteptype, int numavg, int ltype1, int ltype2,
+		  const char *name, const char *stdname, const char *longname, const char *units,
+                  const var_tile_t *tiles, int *tile_index);
 
-  int vlistID = streamptr->vlistID;
-  int dimlen = inqs->axisSize(gridID);
-  if ( dimlen != 1 )
-    Error("%s isn't 1 for %s grid!", sizeName, gridNamePtr(gridInqType(gridID)));
+void varDefVCT(size_t vctsize, double *vctptr);
+void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int ncvarid = dimID[gridindex];
+int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, size_t clength, bool lbounds,
+		 const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+		 const char *longname, const char *units, int prec, int mode, int ltype);
 
-  if ( ncvarid == UNDEFID )
-    {
-      int dimNcID = streamptr->basetime.ncvarid;
-      int fileID  = streamptr->fileID;
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+void varDefMissval(int varID, double missval);
+void varDefCompType(int varID, int comptype);
+void varDefCompLevel(int varID, int complevel);
+void varDefInst(int varID, int instID);
+int  varInqInst(int varID);
+void varDefModel(int varID, int modelID);
+int  varInqModel(int varID);
+void varDefTable(int varID, int tableID);
+int  varInqTable(int varID);
+void varDefEnsembleInfo(int varID, int ens_idx, int ens_count, int forecast_type);
 
-      const char *axisname = inqs->axisNamePtr(gridID);
-      cdf_def_var(fileID, axisname, xtype, 1, &dimNcID, &ncvarid);
-      cdfPutGridStdAtts(fileID, ncvarid, gridID, inqs);
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
+void varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
+void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
 
-  dimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
-}
 
-static
-void cdfDefTrajLon(stream_t *streamptr, int gridID)
-{
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsX, streamptr->xdimID, "Xsize");
-}
+void varDefOptGribInt(int varID, int tile_index, long lval, const char *keyword);
+void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keyword);
+int varOptGribNentries(int varID);
 
+bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype);
 
-static
-void cdfDefTrajLat(stream_t *streamptr, int gridID)
-{
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsY, streamptr->ydimID, "Ysize");
-}
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-static
-int checkDimName(int fileID, size_t dimlen, char *dimname)
-{
-  /* check whether the dimenion name is already defined with the same length */
-  unsigned iz = 0;
-  int dimid = UNDEFID;
-  char name[CDI_MAX_NAME];
+#ifdef HAVE_LIBNETCDF
 
-  size_t len = strlen(dimname);
-  memcpy(name, dimname, len + 1);
+//#define TEST_GROUPS 1
 
-  do
-    {
-      if ( iz ) sprintf(name + len, "_%u", iz+1);
+#include <ctype.h>
+#include <limits.h>
 
-      int dimid0, status = nc_inq_dimid(fileID, name, &dimid0);
-      if ( status != NC_NOERR )
-        break;
-      size_t dimlen0;
-      cdf_inq_dimlen(fileID, dimid0, &dimlen0);
-      if ( dimlen0 == dimlen )
-        {
-          dimid = dimid0;
-          break;
-        }
-      iz++;
-    }
-  while ( iz <= 99 );
 
 
-  if ( iz ) sprintf(dimname + len, "_%u", iz+1);
+#define  X_AXIS  1
+#define  Y_AXIS  2
+#define  Z_AXIS  3
+#define  T_AXIS  4
 
-  return dimid;
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
+
+typedef struct {
+  int     ncvarid;
+  int     dimtype;
+  size_t  len;
+  char    name[CDI_MAX_NAME];
+}
+ncdim_t;
+#define  MAX_COORDVARS  4
+#define  MAX_AUXVARS    4
+
+typedef struct {
+  int      ncid;
+  int      isvar;
+  bool     ignore;
+  bool     isx;
+  bool     isy;
+  bool     isc;
+  bool     islon;
+  bool     islat;
+  bool     islev;
+  bool     istime;
+  bool     warn;
+  bool     calendar;
+  bool     climatology;
+  bool     lformulaterms;
+  int      param;
+  int      code;
+  int      tabnum;
+  int      bounds;
+  int      gridID;
+  int      zaxisID;
+  int      timetype;
+  int      gridtype;
+  int      zaxistype;
+  int      xdim;
+  int      ydim;
+  int      zdim;
+  int      xvarid;
+  int      yvarid;
+  int      zvarid;
+  int      cvarids[MAX_COORDVARS];
+  int      tvarid;
+  int      psvarid;
+  int      p0varid;
+  int      ncoordvars;
+  int      coordvarids[MAX_COORDVARS];
+  int      nauxvars;
+  int      auxvarids[MAX_AUXVARS];
+  int      cellarea;
+  int      tableID;
+  int      truncation;
+  int      position;
+  bool     defmissval;
+  bool     deffillval;
+  int      xtype;
+  int      gmapid;
+  int      positive;
+  int      ndims;
+  int      dimids[8];
+  int      dimtype[8];
+  size_t   chunks[8];
+  int      chunked;
+  int      chunktype;
+  int      natts;
+  int      deflate;
+  bool     lunsigned;
+  bool     lvalidrange;
+  int     *atts;
+  size_t   vctsize;
+  double  *vct;
+  double   missval;
+  double   fillval;
+  double   addoffset;
+  double   scalefactor;
+  double   validrange[2];
+  char     name[CDI_MAX_NAME];
+  char     longname[CDI_MAX_NAME];
+  char     stdname[CDI_MAX_NAME];
+  char     units[CDI_MAX_NAME];
+  char     extra[CDI_MAX_NAME];
+  ensinfo_t   *ensdata;    /* Ensemble information */
 }
+ncvar_t;
+
 
 static
-void checkGridName(char *axisname, int fileID, int vlistID, int gridID, int ngrids, int mode)
+void scanTimeString(const char *ptu, int *rdate, int *rtime)
 {
-  int ncdimid;
-  char axisname2[CDI_MAX_NAME];
+  int year = 1, month = 1, day = 1;
+  int hour = 0, minute = 0, second = 0;
+  int v1 = 1, v2 = 1, v3 = 1;
 
-  /* check that the name is not already defined */
-  unsigned iz = 0;
+  *rdate = 0;
+  *rtime = 0;
 
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
+  if ( *ptu )
     {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
-
-      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
-
-      if ( status != NC_NOERR )
+      v1 = atoi(ptu);
+      if ( v1 < 0 ) ptu++;
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu )
         {
-          if ( iz )
+          v2 = atoi(++ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu )
             {
-              /* check that the name does not exist for other grids */
-              for ( int index = 0; index < ngrids; index++ )
-                {
-                  int gridID0 = vlistGrid(vlistID, index);
-                  if ( gridID != gridID0 )
-                    {
-                       /* mode X or Y */
-                      const char *(*query)(int)
-                        = mode == 'X' ? gridInqXnamePtr : gridInqYnamePtr;
-                      const char *axisname0 = query(gridID0);
-                      if ( strcmp(axisname0, axisname2) == 0 ) goto nextSuffix;
-                    }
-                }
+              v3 = atoi(++ptu);
+              while ( isdigit((int) *ptu) ) ptu++;
             }
-          break;
         }
-      nextSuffix:
-      ++iz;
     }
-  while ( iz <= 99 );
-
 
-  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
-}
-
-static
-int checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
-{
-  char axisname2[CDI_MAX_NAME];
+  if ( v3 > 999 && v1 < 32 )
+    { year = v3; month = v2; day = v1; }
+  else
+    { year = v1; month = v2; day = v3; }
 
-  /* check that the name is not already defined */
-  unsigned iz = 0;
+  while ( isspace((int) *ptu) ) ptu++;
 
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
+  if ( *ptu )
     {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
-
-      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
+      while ( ! isdigit((int) *ptu) ) ptu++;
 
-      if ( status != NC_NOERR )
+      hour = atoi(ptu);
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu == ':' )
         {
-          if ( iz )
+          ptu++;
+          minute = atoi(ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu == ':' )
             {
-              /* check that the name does not exist for other zaxes */
-              for ( int index = 0; index < nzaxis; index++ )
-                {
-                  int zaxisID0 = vlistZaxis(vlistID, index);
-                  if ( zaxisID != zaxisID0 )
-                    {
-                      const char *axisname0 = zaxisInqNamePtr(zaxisID0);
-                      if ( strcmp(axisname0, axisname2) == 0 ) goto nextSuffix;
-                    }
-                }
+              ptu++;
+              second = atoi(ptu);
             }
-          break;
         }
-      nextSuffix:
-      ++iz;
     }
-  while (iz <= 99);
-
 
-  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
-
-  return (int)iz;
+  *rdate = cdiEncodeDate(year, month, day);
+  *rtime = cdiEncodeTime(hour, minute, second);
 }
 
-static void
-cdfDefAxisCommon(stream_t *streamptr, int gridID, int ndims,
-                 const struct cdfDefGridAxisInqs *gridAxisInq,
-                 int *axisDimIDs, int dimKey, char axisLetter,
-                 void (*finishCyclicBounds)(double *pbounds, size_t dimlen,
-                                            const double *pvals),
-                 int *ncAxisVarIDs)
-{
-  int dimID = UNDEFID;
-  int ngrids = 0;
-  int ncvarid = UNDEFID, ncbvarid = UNDEFID;
-  int nvdimID = UNDEFID;
-  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  if ( ndims ) ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridAxisInq->axisSize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-
-  const char *axisname = gridAxisInq->axisNamePtr(gridID);
-  size_t axisnameLen = strlen(axisname);
-
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
-
-  for ( int index = 0; index < ngrids; index++ )
-    {
-      if ( axisDimIDs[index] != UNDEFID )
-        {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_GAUSSIAN    ||
-               gridtype0 == GRID_LONLAT      ||
-               gridtype0 == GRID_CURVILINEAR ||
-               gridtype0 == GRID_GENERIC )
-            {
-              size_t dimlen0 = (size_t)gridAxisInq->axisSize(gridID0);
-              if ( dimlen == dimlen0 )
-                {
-                  double (*inqVal)(int gridID, int index)
-                    = gridAxisInq->axisVal;
-                  if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) &&
-                       IS_EQUAL(inqVal(gridID0, (int)dimlen-1), inqVal(gridID, (int)dimlen-1)) )
-                  {
-                    dimID = axisDimIDs[index];
-                    break;
-                  }
-                }
-            }
-        }
-    }
+static
+int scanTimeUnit(const char *unitstr)
+{
+  size_t len = strlen(unitstr);
+  int timeunit = get_timeunit(len, unitstr);
+  if ( timeunit == -1 )
+    Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  if ( dimID == UNDEFID )
-    {
-      const double *pvals = gridAxisInq->axisValsPtr(gridID);
+  return timeunit;
+}
 
-      /* enough to append _ plus up to 100 decimal and trailing \0 */
-      char extendedAxisname[axisnameLen + 4 + 1];
-      memcpy(extendedAxisname, axisname, axisnameLen + 1);
-      checkGridName(extendedAxisname, fileID, vlistID, gridID, ngrids, axisLetter);
-      size_t extendedAxisnameLen
-        = axisnameLen + strlen(extendedAxisname + axisnameLen);
+static
+void setForecastTime(const char *timestr, taxis_t *taxis)
+{
+  size_t len = strlen(timestr);
+  if ( len != 0 )
+    scanTimeString(timestr, &taxis->fdate, &taxis->ftime);
+  else
+    taxis->fdate = taxis->ftime = 0;
+}
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+static
+int setBaseTime(const char *timeunits, taxis_t *taxis)
+{
+  int taxistype = TAXIS_ABSOLUTE;
+  int rdate = -1, rtime = -1;
 
-      if ( ndims )
-        {
-          char dimname[CDI_MAX_NAME+3];
-          dimname[0] = 0;
+  size_t len = strlen(timeunits);
+  while ( isspace(*timeunits) && len ) { timeunits++; len--; }
 
-          if ( pvals == NULL )
-            cdiGridInqString(gridID, dimKey, CDI_MAX_NAME, dimname);
+  char *restrict tu = (char *)Malloc((len+1) * sizeof(char));
 
-          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
-          dimID = checkDimName(fileID, dimlen, dimname);
+  for ( size_t i = 0; i < len; i++ ) tu[i] = (char)tolower((int)timeunits[i]);
+  tu[len] = 0;
 
-          if ( dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
-        }
+  int timeunit = get_timeunit(len, tu);
+  if ( timeunit == -1 )
+    {
+      Message("Unsupported TIMEUNIT: %s!", timeunits);
+      return 1;
+    }
 
-      bool gen_bounds = false;
-      int grid_is_cyclic = gridIsCircular(gridID);
-      double *pbounds = NULL;
-      if ( pvals )
-        {
-          cdf_def_var(fileID, extendedAxisname, xtype, ndims, &dimID, &ncvarid);
+  size_t pos = 0;
+  while ( pos < len && !isspace(tu[pos]) ) ++pos;
+  if ( tu[pos] )
+    {
+      while ( isspace(tu[pos]) ) ++pos;
 
-          cdfPutGridStdAtts(fileID, ncvarid, gridID, gridAxisInq);
-          {
-            char axisStr[2] = { axisLetter, '\0' };
-            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
-          }
+      if ( str_is_equal(tu+pos, "since") )
+        taxistype = TAXIS_RELATIVE;
 
-          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
+      while ( pos < len && !isspace(tu[pos]) ) ++pos;
+      if ( tu[pos] )
+        {
+          while ( isspace(tu[pos]) ) ++pos;
 
-          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+          if ( taxistype == TAXIS_ABSOLUTE )
             {
-              gen_bounds = true;
-              pbounds = (double*) Malloc(2*dimlen*sizeof(double));
-              for ( size_t i = 0; i < dimlen-1; ++i )
+              if ( timeunit == TUNIT_DAY )
                 {
-                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
-                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                  if ( !str_is_equal(tu+pos, "%y%m%d.%f") )
+                    {
+                      Message("Unsupported format %s for TIMEUNIT day!", tu+pos);
+                      timeunit = -1;
+                    }
+                }
+              else if ( timeunit == TUNIT_MONTH )
+                {
+                  if ( !str_is_equal(tu+pos, "%y%m.%f") )
+                    {
+                      Message("Unsupported format %s for TIMEUNIT month!", tu+pos);
+                      timeunit = -1;
+                    }
                 }
-              finishCyclicBounds(pbounds, dimlen, pvals);
-            }
-          if ( pbounds )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
             }
-          if ( pbounds && nvdimID != UNDEFID )
+          else if ( taxistype == TAXIS_RELATIVE )
             {
-              char boundsname[extendedAxisnameLen + 1 + sizeof (bndsName)];
-              memcpy(boundsname, axisname, extendedAxisnameLen);
-              boundsname[extendedAxisnameLen] = '_';
-              memcpy(boundsname + extendedAxisnameLen + 1, bndsName, sizeof bndsName);
-              int dimIDs[2] = { dimID, nvdimID };
-              cdf_def_var(fileID, boundsname, xtype, 2, dimIDs, &ncbvarid);
-              cdf_put_att_text(fileID, ncvarid, "bounds", extendedAxisnameLen + sizeof (bndsName), boundsname);
+              scanTimeString(tu+pos, &rdate, &rtime);
+
+              taxis->rdate = rdate;
+              taxis->rtime = rtime;
+
+              if ( CDI_Debug )
+                Message("rdate = %d  rtime = %d", rdate, rtime);
             }
         }
+    }
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+  taxis->type = taxistype;
+  taxis->unit = timeunit;
 
-      if ( ncvarid  != UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
-      if ( ncbvarid != UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
-      if ( gen_bounds ) Free(pbounds);
+  Free(tu);
 
-      if ( ndims == 0 ) ncAxisVarIDs[gridindex] = ncvarid;
-    }
+  if ( CDI_Debug )
+    Message("taxistype = %d  unit = %d", taxistype, timeunit);
 
-  axisDimIDs[gridindex] = dimID;
+  return 0;
 }
 
-static void
-finishCyclicXBounds(double *pbounds, size_t dimlen, const double *pvals)
+static
+bool xtypeIsText(int xtype)
 {
-  pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)*0.5;
-  pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)*0.5;
+  bool isText = ( xtype == NC_CHAR )
+#if  defined  (HAVE_NETCDF4)
+    || ( xtype == NC_STRING )
+#endif
+    ;
+  return isText;
 }
 
 static
-void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
+bool xtypeIsFloat(nc_type xtype)
 {
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsX, streamptr->xdimID,
-                   CDI_GRID_XDIMNAME, 'X', finishCyclicXBounds,
-                   streamptr->ncxvarID);
-}
+  bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
 
-static void
-finishCyclicYBounds(double *pbounds, size_t dimlen, const double *pvals)
-{
-  pbounds[0] = copysign(90.0, pvals[0]);
-  pbounds[2*dimlen-1] = copysign(90.0, pvals[dimlen-1]);
+  return isFloat;
 }
 
 static
-void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
+bool xtypeIsInt(nc_type xtype)
 {
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsY, streamptr->ydimID,
-                   CDI_GRID_YDIMNAME, 'Y', finishCyclicYBounds,
-                   streamptr->ncyvarID);
+  bool isInt = xtype == NC_SHORT || xtype == NC_INT
+            || xtype == NC_BYTE
+#if  defined  (HAVE_NETCDF4)
+            || xtype == NC_USHORT || xtype == NC_UINT
+            || xtype == NC_UBYTE
+#endif
+             ;
+
+  return isInt;
 }
 
 static
-void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
+int cdfInqDatatype(int xtype, bool lunsigned)
 {
+  int datatype = -1;
+
 #if  defined  (HAVE_NETCDF4)
-  if ( gridsize > 1 && comptype == COMPRESS_ZIP && (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) )
-    {
-      nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
-      cdfDefVarDeflate(fileID, ncvarid, 1);
-    }
+  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
 #endif
+
+  if      ( xtype == NC_BYTE   )  datatype = CDI_DATATYPE_INT8;
+  else if ( xtype == NC_CHAR   )  datatype = CDI_DATATYPE_UINT8;
+  else if ( xtype == NC_SHORT  )  datatype = CDI_DATATYPE_INT16;
+  else if ( xtype == NC_INT    )  datatype = CDI_DATATYPE_INT32;
+  else if ( xtype == NC_FLOAT  )  datatype = CDI_DATATYPE_FLT32;
+  else if ( xtype == NC_DOUBLE )  datatype = CDI_DATATYPE_FLT64;
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_UBYTE  )  datatype = CDI_DATATYPE_UINT8;
+  else if ( xtype == NC_LONG   )  datatype = CDI_DATATYPE_INT32;
+  else if ( xtype == NC_USHORT )  datatype = CDI_DATATYPE_UINT16;
+  else if ( xtype == NC_UINT   )  datatype = CDI_DATATYPE_UINT32;
+  else if ( xtype == NC_INT64  )  datatype = CDI_DATATYPE_FLT64;
+  else if ( xtype == NC_UINT64 )  datatype = CDI_DATATYPE_FLT64;
+#endif
+
+  return datatype;
 }
 
 static
-void cdfDefCurvilinear(stream_t *streamptr, int gridID)
+void cdfGetAttInt(int fileID, int ncvarid, const char *attname, size_t attlen, int *attint)
 {
-  int xdimID = UNDEFID;
-  int ydimID = UNDEFID;
-  int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
-  int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
-  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
+  *attint = 0;
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  nc_type atttype;
+  size_t nc_attlen;
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-  int ngrids = vlistNgrids(vlistID);
+  if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
+    {
+      bool lalloc = nc_attlen > attlen;
+      int *pintatt = lalloc ? (int *)(Malloc(nc_attlen*sizeof(int))) : attint;
+      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+      if ( lalloc )
+        {
+          memcpy(attint, pintatt, attlen*sizeof(int));
+          Free(pintatt);
+        }
+    }
+}
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
-  size_t xdimlen = (size_t)gridInqXsize(gridID);
-  size_t ydimlen = (size_t)gridInqYsize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
+static
+void cdfGetAttDouble(int fileID, int ncvarid, char *attname, size_t attlen, double *attdouble)
+{
+  *attdouble = 0;
+
+  nc_type atttype;
+  size_t nc_attlen;
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-  for ( int index = 0; index < ngrids; index++ )
+  if ( xtypeIsFloat(atttype) || xtypeIsInt(atttype) )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
+      bool lalloc = nc_attlen > attlen;
+      double *pdoubleatt = lalloc ? (double*)Malloc(nc_attlen*sizeof(double)) : attdouble;
+      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
+      if ( lalloc )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_CURVILINEAR )
-            {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0);
-              if ( dimlen == dimlen0 )
-                if ( IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) &&
-                     IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), gridInqXval(gridID, (int)dimlen-1)) &&
-                     IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) &&
-                     IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), gridInqYval(gridID, (int)dimlen-1)) )
-                  {
-                    xdimID = streamptr->xdimID[index];
-                    ydimID = streamptr->ydimID[index];
-                    ncxvarid = streamptr->ncxvarID[index];
-                    ncyvarid = streamptr->ncyvarID[index];
-                    break;
-                  }
-            }
+          memcpy(attdouble, pdoubleatt, attlen*sizeof(double));
+          Free(pdoubleatt);
         }
     }
+}
+
+static
+bool cdfCheckAttText(int fileID, int ncvarid, const char *attname)
+{
+  bool status = false;
+  nc_type atttype;
+
+  int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);
+
+  if ( status_nc == NC_NOERR
+       && (atttype == NC_CHAR
+#if  defined  (HAVE_NETCDF4)
+           || atttype == NC_STRING
+#endif
+           ) )
+    {
+      status = true;
+    }
+
+  return status;
+}
+
+static
+void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char *atttext)
+{
+  nc_type atttype;
+  size_t nc_attlen;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-  if ( xdimID == UNDEFID || ydimID == UNDEFID )
+  if ( atttype == NC_CHAR )
     {
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-      {
-        char xdimname[CDI_MAX_NAME+3];
-        xdimname[0] = 0;
-        cdiGridInqString(gridID, CDI_GRID_XDIMNAME, CDI_MAX_NAME, xdimname);
-        if ( xdimname[0] == 0 ) { xdimname[0] = 'x'; xdimname[1] = 0; }
-        xdimID = checkDimName(fileID, xdimlen, xdimname);
-        if ( xdimID == UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID);
-      }
-      {
-        char ydimname[CDI_MAX_NAME+3];
-        ydimname[0] = 0;
-        cdiGridInqString(gridID, CDI_GRID_YDIMNAME, CDI_MAX_NAME, ydimname);
-        if ( ydimname[0] == 0 ) { ydimname[0] = 'y'; ydimname[1] = 0; }
-        ydimID = checkDimName(fileID, ydimlen, ydimname);
-        if ( ydimID == UNDEFID ) cdf_def_dim(fileID, ydimname, ydimlen, &ydimID);
-      }
+      char attbuf[65636];
+      if ( nc_attlen < sizeof(attbuf) )
+        {
+          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
+
+          if ( nc_attlen > (attlen-1) ) nc_attlen = (attlen-1);
 
-      int nvdimID = UNDEFID;
-      int dimIDs[3];
-      if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
+          attbuf[nc_attlen++] = 0;
+          memcpy(atttext, attbuf, nc_attlen);
+        }
+      else
         {
-          char vdimname[CDI_MAX_NAME+3];
-          vdimname[0] = 0;
-          cdiGridInqString(gridID, CDI_GRID_VDIMNAME, CDI_MAX_NAME, vdimname);
-          if ( vdimname[0] == 0 ) strcpy(vdimname, "nv4");
-          size_t nvertex = 4;
-          nvdimID = checkDimName(fileID, nvertex, vdimname);
-          if ( nvdimID == UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
+          atttext[0] = 0;
         }
+    }
+#if  defined  (HAVE_NETCDF4)
+  else if ( atttype == NC_STRING )
+    {
+      if ( nc_attlen == 1 )
+        {
+          char *attbuf = NULL;
+          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
 
-      dimIDs[0] = ydimID;
-      dimIDs[1] = xdimID;
-      dimIDs[2] = nvdimID;
+          size_t ssize = strlen(attbuf) + 1;
 
-      if ( gridInqXvalsPtr(gridID) )
+          if ( ssize > attlen ) ssize = attlen;
+          memcpy(atttext, attbuf, ssize);
+          atttext[ssize - 1] = 0;
+          Free(attbuf);
+        }
+      else
         {
-          char xaxisname[CDI_MAX_NAME];
-          gridInqXname(gridID, xaxisname);
-          checkGridName(xaxisname, fileID, vlistID, gridID, ngrids, 'X');
+          atttext[0] = 0;
+        }
+    }
+#endif
+}
+
+
+void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
+{
+  bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+  bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+
+  if ( laddoffset && lscalefactor )
+    {
+      for (size_t i = 0; i < size; ++i )
+        data[i] = data[i] * scalefactor + addoffset;
+    }
+  else if (lscalefactor)
+    {
+      for (size_t i = 0; i < size; ++i )
+        data[i] *= scalefactor;
+    }
+  else if (laddoffset)
+    {
+      for (size_t i = 0; i < size; ++i )
+        data[i] += addoffset;
+    }
+}
+
+static
+void cdfCreateRecords(stream_t *streamptr, int tsID)
+{
+  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
 
-          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
-          cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
 
-          cdfPutGridStdAtts(fileID, ncxvarid, gridID, &gridInqsX);
+  int vlistID  = streamptr->vlistID;
 
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
+  tsteps_t* sourceTstep = streamptr->tsteps;
+  tsteps_t* destTstep = sourceTstep + tsID;
 
-          if ( gridInqXboundsPtr(gridID) && nvdimID != UNDEFID )
-            {
-              size_t xaxisnameLen = strlen(xaxisname);
-              xaxisname[xaxisnameLen] = '_';
-              memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName));
-              cdf_def_var(fileID, xaxisname, xtype, 3, dimIDs, &ncbxvarid);
-              cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+  int nvars = vlistNvars(vlistID);
+  int nrecs = vlistNrecs(vlistID);
+
+  if ( nrecs <= 0 ) return;
+
+  if ( tsID == 0 )
+    {
+      int nvrecs = nrecs; /* use all records at first timestep */
+
+      streamptr->nrecs += nrecs;
+
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
+      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
+
+      record_t *records = destTstep->records;
 
-              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
+        {
+          int zaxisID = vlistInqVarZaxis(vlistID, varID);
+          int nlev    = zaxisInqSize(zaxisID);
+          for ( int levelID = 0; levelID < nlev; levelID++ )
+            {
+              recordInitEntry(&records[recID]);
+              records[recID].varID   = (short)varID;
+              records[recID].levelID = (short)levelID;
+              recID++;
             }
         }
-
-      if ( gridInqYvalsPtr(gridID) )
+    }
+  else if ( tsID == 1 )
+    {
+      int nvrecs = 0;
+      for ( int varID = 0; varID < nvars; varID++ )
         {
-          char yaxisname[CDI_MAX_NAME];
-          gridInqYname(gridID, yaxisname);
-          checkGridName(yaxisname, fileID, vlistID, gridID, ngrids, 'Y');
+          if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
+            {
+              int zaxisID = vlistInqVarZaxis(vlistID, varID);
+              nvrecs += zaxisInqSize(zaxisID);
+            }
+        }
 
-          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
-          cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+      streamptr->nrecs += nvrecs;
 
-          cdfPutGridStdAtts(fileID, ncyvarid, gridID, &gridInqsY);
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
 
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
 
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
+      if ( nvrecs )
+        {
+          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
+          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
             {
-              size_t yaxisnameLen = strlen(yaxisname);
-              yaxisname[yaxisnameLen] = '_';
-              memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName));
-              cdf_def_var(fileID, yaxisname, xtype, 3, dimIDs, &ncbyvarid);
-              cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
-
-              cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+              int varID = destTstep->records[recID].varID;
+              if ( vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT )
+                {
+                  destTstep->recIDs[vrecID++] = recID;
+                }
             }
         }
+    }
+  else
+    {
+      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      if ( gridInqAreaPtr(gridID) )
-        {
-          static const char yaxisname_[] = "cell_area";
-          static const char units[] = "m2";
-          static const char longname[] = "area of grid cell";
-          static const char stdname[] = "cell_area";
+      int nvrecs = streamptr->tsteps[1].nrecs;
 
-          cdf_def_var(fileID, yaxisname_, xtype, 2, dimIDs, &ncavarid);
+      streamptr->nrecs += nvrecs;
 
-          cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
-          cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
-          cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units);
-        }
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
 
-      if ( ncxvarid  != UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
-      if ( ncbxvarid != UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
-      if ( ncyvarid  != UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
-      if ( ncbyvarid != UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
-      if ( ncavarid  != UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
-    }
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
 
-  streamptr->xdimID[gridindex] = xdimID;
-  streamptr->ydimID[gridindex] = ydimID;
-  streamptr->ncxvarID[gridindex] = ncxvarid;
-  streamptr->ncyvarID[gridindex] = ncyvarid;
-  streamptr->ncavarID[gridindex] = ncavarid;
+      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
+    }
 }
 
 static
-void cdfDefRgrid(stream_t *streamptr, int gridID)
+int cdf_time_dimid(int fileID, int ndims, int nvars)
 {
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  char dimname[80];
+  for ( int dimid = 0; dimid < ndims; ++dimid )
+    {
+      dimname[0] = 0;
+      cdf_inq_dimname(fileID, dimid, dimname);
+      if ( str_is_equal(dimname, "time") || str_is_equal(dimname, "Time") ) return dimid;
+    }
 
-  int iz = 0;
-  for ( int index = 0; index < ngrids; index++ )
+  for ( int varid = 0; varid < nvars; ++varid )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
+      nc_type xtype;
+      int nvdims, nvatts, dimids[9];
+      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
+      if ( nvdims == 1 )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
+          char sbuf[CDI_MAX_NAME];
+          for ( int iatt = 0; iatt < nvatts; ++iatt )
             {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0);
-
-              if ( dimlen == dimlen0 )
+              sbuf[0] = 0;
+              cdf_inq_attname(fileID, varid, iatt, sbuf);
+              if ( strncmp(sbuf, "units", 5) == 0 )
                 {
-                  dimID = streamptr->xdimID[index];
-                  break;
+                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
+                  str_tolower(sbuf);
+
+                  if ( is_time_units(sbuf) ) return dimids[0];
                 }
-              iz++;
             }
         }
     }
 
-  if ( dimID == UNDEFID )
+  return CDI_UNDEFID;
+}
+
+static
+void init_ncdims(long ndims, ncdim_t *ncdims)
+{
+  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      ncdims[ncdimid].ncvarid      = CDI_UNDEFID;
+      ncdims[ncdimid].dimtype      = CDI_UNDEFID;
+      ncdims[ncdimid].len          = 0;
+      ncdims[ncdimid].name[0]      = 0;
+    }
+}
+
+static
+void init_ncvars(long nvars, ncvar_t *ncvars)
+{
+  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
     {
-      int fileID  = streamptr->fileID;
-      static bool lwarn = true;
-      if ( lwarn )
+      ncvars[ncvarid].ncid            = CDI_UNDEFID;
+      ncvars[ncvarid].isvar           = CDI_UNDEFID;
+      ncvars[ncvarid].ignore          = false;
+      ncvars[ncvarid].isx             = false;
+      ncvars[ncvarid].isy             = false;
+      ncvars[ncvarid].isc             = false;
+      ncvars[ncvarid].islon           = false;
+      ncvars[ncvarid].islat           = false;
+      ncvars[ncvarid].islev           = false;
+      ncvars[ncvarid].istime          = false;
+      ncvars[ncvarid].warn            = false;
+      ncvars[ncvarid].calendar        = false;
+      ncvars[ncvarid].climatology     = false;
+      ncvars[ncvarid].lformulaterms   = false;
+      ncvars[ncvarid].timetype        = TIME_CONSTANT;
+      ncvars[ncvarid].param           = CDI_UNDEFID;
+      ncvars[ncvarid].code            = CDI_UNDEFID;
+      ncvars[ncvarid].tabnum          = 0;
+      ncvars[ncvarid].bounds          = CDI_UNDEFID;
+      ncvars[ncvarid].gridID          = CDI_UNDEFID;
+      ncvars[ncvarid].zaxisID         = CDI_UNDEFID;
+      ncvars[ncvarid].gridtype        = CDI_UNDEFID;
+      ncvars[ncvarid].zaxistype       = CDI_UNDEFID;
+      ncvars[ncvarid].xdim            = CDI_UNDEFID;
+      ncvars[ncvarid].ydim            = CDI_UNDEFID;
+      ncvars[ncvarid].zdim            = CDI_UNDEFID;
+      ncvars[ncvarid].xvarid          = CDI_UNDEFID;
+      ncvars[ncvarid].yvarid          = CDI_UNDEFID;
+      ncvars[ncvarid].zvarid          = CDI_UNDEFID;
+      ncvars[ncvarid].tvarid          = CDI_UNDEFID;
+      ncvars[ncvarid].psvarid         = CDI_UNDEFID;
+      ncvars[ncvarid].p0varid         = CDI_UNDEFID;
+      ncvars[ncvarid].ncoordvars      = 0;
+      for ( int i = 0; i < MAX_COORDVARS; ++i )
         {
-          Warning("Creating a NetCDF file with data on a gaussian reduced grid.");
-          Warning("The further processing of the resulting file is unsupported!");
-          lwarn = false;
+          ncvars[ncvarid].coordvarids[i]  = CDI_UNDEFID;
+          ncvars[ncvarid].cvarids[i]      = CDI_UNDEFID;
         }
+      ncvars[ncvarid].nauxvars      = 0;
+      for ( int i = 0; i < MAX_AUXVARS; ++i )
+        ncvars[ncvarid].auxvarids[i]  = CDI_UNDEFID;
+      ncvars[ncvarid].cellarea        = CDI_UNDEFID;
+      ncvars[ncvarid].tableID         = CDI_UNDEFID;
+      ncvars[ncvarid].xtype           = 0;
+      ncvars[ncvarid].ndims           = 0;
+      ncvars[ncvarid].gmapid          = CDI_UNDEFID;
+      ncvars[ncvarid].vctsize         = 0;
+      ncvars[ncvarid].vct             = NULL;
+      ncvars[ncvarid].truncation      = 0;
+      ncvars[ncvarid].position        = 0;
+      ncvars[ncvarid].positive        = 0;
+      ncvars[ncvarid].chunked         = 0;
+      ncvars[ncvarid].chunktype       = CDI_UNDEFID;
+      ncvars[ncvarid].defmissval      = false;
+      ncvars[ncvarid].deffillval      = false;
+      ncvars[ncvarid].missval         = 0;
+      ncvars[ncvarid].fillval         = 0;
+      ncvars[ncvarid].addoffset       = 0;
+      ncvars[ncvarid].scalefactor     = 1;
+      ncvars[ncvarid].natts           = 0;
+      ncvars[ncvarid].atts            = NULL;
+      ncvars[ncvarid].deflate         = 0;
+      ncvars[ncvarid].lunsigned       = false;
+      ncvars[ncvarid].lvalidrange     = false;
+      ncvars[ncvarid].validrange[0]   = VALIDMISS;
+      ncvars[ncvarid].validrange[1]   = VALIDMISS;
+      ncvars[ncvarid].ensdata         = NULL;
+      memset(ncvars[ncvarid].name, 0, CDI_MAX_NAME);
+      memset(ncvars[ncvarid].longname, 0, CDI_MAX_NAME);
+      memset(ncvars[ncvarid].stdname, 0, CDI_MAX_NAME);
+      memset(ncvars[ncvarid].units, 0, CDI_MAX_NAME);
+      memset(ncvars[ncvarid].extra, 0, CDI_MAX_NAME);
+    }
+}
 
-      char axisname[7] = "rgridX";
-      if ( iz == 0 ) axisname[5] = '\0';
-      else           sprintf(&axisname[5], "%1d", iz+1);
+static
+void cdf_set_var(ncvar_t *ncvars, int ncvarid, short isvar)
+{
+  if ( ncvars[ncvarid].isvar != CDI_UNDEFID &&
+       ncvars[ncvarid].isvar != isvar   &&
+       ncvars[ncvarid].warn  == false )
+    {
+      if ( ! ncvars[ncvarid].ignore )
+        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      ncvars[ncvarid].warn = true;
+      isvar = FALSE;
+    }
 
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+  ncvars[ncvarid].isvar = isvar;
+}
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+static
+void cdf_set_dim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
+{
+  if ( ncvars[ncvarid].dimtype[dimid] != CDI_UNDEFID &&
+       ncvars[ncvarid].dimtype[dimid] != dimtype )
+    {
+      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
+              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
     }
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
+  ncvars[ncvarid].dimtype[dimid] = dimtype;
 }
 
 static
-void cdfDefGdim(stream_t *streamptr, int gridID)
+void scan_hybrid_formulaterms(int ncid, int ncfvarid, int *avarid, int *bvarid, int *psvarid, int *p0varid)
 {
-  int iz = 0;
-  int dimID = UNDEFID;
+  *avarid  = -1;
+  *bvarid  = -1;
+  *psvarid = -1;
+  *p0varid = -1;
 
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
+  char attstring[1024];
+  cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
+  char *pstring = attstring;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  bool lstop = false;
+  for ( int i = 0; i < 4; i++ )
+    {
+      while ( isspace((int) *pstring) ) pstring++;
+      if ( *pstring == 0 ) break;
+      char *tagname = pstring;
+      while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+      if ( *pstring == 0 ) lstop = true;
+      *pstring++ = 0;
 
-  if ( gridInqYsize(gridID) == 0 )
-    for ( int index = 0; index < ngrids; index++ )
-      {
-        if ( streamptr->xdimID[index] != UNDEFID )
-          {
-            int gridID0 = vlistGrid(vlistID, index);
-            int gridtype0 = gridInqType(gridID0);
-            if ( gridtype0 == GRID_GENERIC )
-              {
-                size_t dimlen0 = (size_t)gridInqSize(gridID0);
-                if ( dimlen == dimlen0 )
-                  {
-                    dimID = streamptr->xdimID[index];
-                    break;
-                  }
-                else
-                  iz++;
-              }
-          }
-      }
+      while ( isspace((int) *pstring) ) pstring++;
+      if ( *pstring == 0 ) break;
+      char *varname = pstring;
+      while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+      if ( *pstring == 0 ) lstop = true;
+      *pstring++ = 0;
 
-  if ( gridInqXsize(gridID) == 0 )
-    for ( int index = 0; index < ngrids; index++ )
-      {
-        if ( streamptr->ydimID[index] != UNDEFID )
-          {
-            int gridID0 = vlistGrid(vlistID, index);
-            int gridtype0 = gridInqType(gridID0);
-            if ( gridtype0 == GRID_GENERIC )
-              {
-                size_t dimlen0 = (size_t)gridInqSize(gridID0);
-                if ( dimlen == dimlen0 )
-                  {
-                    dimID = streamptr->ydimID[index];
-                    break;
-                  }
-                else
-                  iz++;
-              }
-          }
-      }
+      int dimvarid;
+      int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
+      if ( status_nc == NC_NOERR )
+        {
+          if      ( strcmp(tagname, "ap:") == 0 ) *avarid  = dimvarid;
+          else if ( strcmp(tagname, "a:")  == 0 ) *avarid  = dimvarid;
+          else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
+          else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
+          else if ( strcmp(tagname, "p0:") == 0 ) *p0varid = dimvarid;
+        }
+      else if ( strcmp(tagname, "ps:") != 0 )
+        {
+          Warning("%s - %s", nc_strerror(status_nc), varname);
+        }
+
+      if ( lstop ) break;
+    }
+}
+
+static
+bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
+{
+  bool status = false;
+  ncvar_t *ncvar = &ncvars[ncvarid];
 
-  if ( dimID == UNDEFID )
+  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
     {
-      int fileID  = streamptr->fileID;
-      char dimname[CDI_MAX_NAME];
-      strcpy(dimname, "gsize");
+      cdiConvention = CDI_CONVENTION_CF;
 
-      dimID = checkDimName(fileID, dimlen, dimname);
+      status = true;
+      ncvar->zaxistype = ZAXIS_HYBRID;
+      //int ndims = ncvar->ndims;
+      int dimid = ncvar->dimids[0];
+      size_t dimlen = ncdims[dimid].len;
+      int avarid1 = -1, bvarid1 = -1, psvarid1 = -1, p0varid1 = -1;
+      int ncfvarid = ncvarid;
+      if ( ncvars[ncfvarid].lformulaterms )
+        scan_hybrid_formulaterms(ncid, ncfvarid, &avarid1, &bvarid1, &psvarid1, &p0varid1);
+      // printf("avarid1, bvarid1, psvarid1, p0varid1 %d %d %d %d\n", avarid1, bvarid1, psvarid1, p0varid1);
+      if ( avarid1  != -1 ) ncvars[avarid1].isvar = FALSE;
+      if ( bvarid1  != -1 ) ncvars[bvarid1].isvar = FALSE;
+      if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
+      if ( p0varid1 != -1 ) ncvar->p0varid = p0varid1;
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      if ( ncvar->bounds != CDI_UNDEFID && ncvars[ncvar->bounds].lformulaterms )
+        {
+          ncfvarid = ncvar->bounds;
+          int avarid2 = -1, bvarid2 = -1, psvarid2 = -1, p0varid2 = -1;
+          if ( ncvars[ncfvarid].lformulaterms )
+            scan_hybrid_formulaterms(ncid, ncfvarid, &avarid2, &bvarid2, &psvarid2, &p0varid2);
+          // printf("avarid2, bvarid2, psvarid2, p0varid2 %d %d %d %d\n", avarid2, bvarid2, psvarid2, p0varid2);
+          if ( avarid2 != -1 && bvarid2 != -1 )
+            {
+              ncvars[avarid2].isvar = FALSE;
+              ncvars[bvarid2].isvar = FALSE;
 
-      if ( dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+              int ndims2 = ncvars[avarid2].ndims;
+              int dimid2 = ncvars[avarid2].dimids[0];
+              size_t dimlen2 = ncdims[dimid2].len;
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+              if ( (ndims2 == 2 && dimid == ncvars[avarid2].dimids[0] ) ||
+                   (ndims2 == 1 && dimlen == dimlen2-1 ) )
+                {
+                  double px = 1;
+                  if ( p0varid1 != -1 && p0varid1 == p0varid2 )
+                    cdf_get_var_double(ncid, p0varid2, &px);
+
+                  double abuf[dimlen*2], bbuf[dimlen*2];
+                  cdf_get_var_double(ncid, avarid2, abuf);
+                  cdf_get_var_double(ncid, bvarid2, bbuf);
+
+                  size_t vctsize = (dimlen+1)*2;
+                  double *vct = (double *) Malloc(vctsize*sizeof(double));
+                  if ( ndims2 == 2 )
+                    {
+                      for ( size_t i = 0; i < dimlen; ++i )
+                        {
+                          vct[i] = abuf[i*2];
+                          vct[i+dimlen+1] = bbuf[i*2];
+                        }
+                      vct[dimlen]     = abuf[dimlen*2-1];
+                      vct[dimlen*2+1] = bbuf[dimlen*2-1];
+                    }
+                  else
+                    {
+                       for ( size_t i = 0; i < dimlen2; ++i )
+                        {
+                          vct[i] = abuf[i];
+                          vct[i+dimlen+1] = bbuf[i];
+                        }
+                    }
+
+                  if ( p0varid1 != -1 && IS_NOT_EQUAL(px, 1) )
+                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
+
+                  ncvar->vct = vct;
+                  ncvar->vctsize = vctsize;
+                }
+            }
+        }
     }
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
+  return status;
 }
 
 static
-void cdfDefGridReference(stream_t *streamptr, int gridID)
+void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID)
 {
-  int fileID  = streamptr->fileID;
-  int number = gridInqNumber(gridID);
+  nc_type atttype;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+
+  cdf_inq_attname(ncid, ncvarid, attnum, attname);
+  cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+  cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
+  if ( xtypeIsInt(atttype) )
+    {
+      int attint[attlen];
+      cdfGetAttInt(ncid, ncvarid, attname, attlen, attint);
+      int datatype = (atttype == NC_SHORT)  ? CDI_DATATYPE_INT16 :
+                     (atttype == NC_BYTE)   ? CDI_DATATYPE_INT8 :
+#if  defined  (HAVE_NETCDF4)
+                     (atttype == NC_UBYTE)  ? CDI_DATATYPE_UINT8 :
+                     (atttype == NC_USHORT) ? CDI_DATATYPE_UINT16 :
+                     (atttype == NC_UINT)   ? CDI_DATATYPE_UINT32 :
+#endif
+                     CDI_DATATYPE_INT32;
+      cdiDefAttInt(cdiID, varID, attname, datatype, (int)attlen, attint);
+    }
+  else if ( xtypeIsFloat(atttype) )
+    {
+      double attflt[attlen];
+      cdfGetAttDouble(ncid, ncvarid, attname, attlen, attflt);
+      int datatype = (atttype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
+      cdiDefAttFlt(cdiID, varID, attname, datatype, (int)attlen, attflt);
+    }
+  else if ( xtypeIsText(atttype) )
+    {
+      char attstring[8192];
+      cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
+      cdiDefAttTxt(cdiID, varID, attname, (int)attlen, attstring);
+    }
+}
+
+static
+void cdf_print_vars(const ncvar_t *ncvars, int nvars, const char *oname)
+{
+  char axis[7];
+  static const char iaxis[] = {'t', 'z', 'y', 'x'};
+
+  fprintf(stderr, "%s:\n", oname);
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ndim = 0;
+      if ( ncvars[ncvarid].isvar )
+        {
+          axis[ndim++] = 'v';
+          axis[ndim++] = ':';
+          for ( int i = 0; i < ncvars[ncvarid].ndims; i++ )
+            {/*
+              if      ( ncvars[ncvarid].tvarid != -1 ) axis[ndim++] = iaxis[0];
+              else if ( ncvars[ncvarid].zvarid != -1 ) axis[ndim++] = iaxis[1];
+              else if ( ncvars[ncvarid].yvarid != -1 ) axis[ndim++] = iaxis[2];
+              else if ( ncvars[ncvarid].xvarid != -1 ) axis[ndim++] = iaxis[3];
+              else
+             */
+              if      ( ncvars[ncvarid].dimtype[i] == T_AXIS ) axis[ndim++] = iaxis[0];
+              else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) axis[ndim++] = iaxis[1];
+              else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) axis[ndim++] = iaxis[2];
+              else if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) axis[ndim++] = iaxis[3];
+              else                                             axis[ndim++] = '?';
+            }
+        }
+      else
+        {
+          axis[ndim++] = 'c';
+          axis[ndim++] = ':';
+          if      ( ncvars[ncvarid].istime ) axis[ndim++] = iaxis[0];
+          else if ( ncvars[ncvarid].islev  ) axis[ndim++] = iaxis[1];
+          else if ( ncvars[ncvarid].islat  ) axis[ndim++] = iaxis[2];
+          else if ( ncvars[ncvarid].isy    ) axis[ndim++] = iaxis[2];
+          else if ( ncvars[ncvarid].islon  ) axis[ndim++] = iaxis[3];
+          else if ( ncvars[ncvarid].isx    ) axis[ndim++] = iaxis[3];
+          else                               axis[ndim++] = '?';
+        }
 
-  if ( number > 0 )
-    {
-      cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
-    }
+      axis[ndim++] = 0;
 
-  const char *gridfile = gridInqReferencePtr(gridID);
-  if ( gridfile && gridfile[0] != 0 )
-    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
+      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
+    }
 }
 
 static
-void cdfDefGridUUID(stream_t *streamptr, int gridID)
+void cdf_scan_attr_axis(ncvar_t *ncvars, ncdim_t *ncdims, int ncvarid, const char *attstring, size_t attlen,
+                        int nvdims, int *dimidsp, const char *name)
 {
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  int i;
+  for ( i = 0; i < (int)attlen; ++i )
+    {
+      if ( attstring[i] != '-' && attstring[i] != 't' && attstring[i] != 'z' &&
+           attstring[i] != 'y' && attstring[i] != 'x' )
+        {
+          Warning("Unexpected character in axis attribute for %s, ignored!", name);
+          break;
+        }
+    }
 
-  gridInqUUID(gridID, uuidOfHGrid);
-  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+  if ( i == (int) attlen && (int) attlen == nvdims )
     {
-      char uuidOfHGridStr[37];
-      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
-      if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
+      while ( attlen-- )
         {
-          int fileID  = streamptr->fileID;
-          //if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-          cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfHGrid", 36, uuidOfHGridStr);
-          //if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+          if ( (int) attstring[attlen] == 't' )
+            {
+              if ( attlen != 0 ) Warning("axis attribute 't' not on first position");
+              cdf_set_dim(ncvars, ncvarid, (int)attlen, T_AXIS);
+            }
+          else if ( (int) attstring[attlen] == 'z' )
+            {
+              ncvars[ncvarid].zdim = dimidsp[attlen];
+              cdf_set_dim(ncvars, ncvarid, (int)attlen, Z_AXIS);
+
+              if ( ncvars[ncvarid].ndims == 1 )
+                {
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
+                }
+            }
+          else if ( (int) attstring[attlen] == 'y' )
+            {
+              ncvars[ncvarid].ydim = dimidsp[attlen];
+              cdf_set_dim(ncvars, ncvarid, (int)attlen, Y_AXIS);
+
+              if ( ncvars[ncvarid].ndims == 1 )
+                {
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Y_AXIS;
+                }
+            }
+          else if ( (int) attstring[attlen] == 'x' )
+            {
+              ncvars[ncvarid].xdim = dimidsp[attlen];
+              cdf_set_dim(ncvars, ncvarid, (int)attlen, X_AXIS);
+
+              if ( ncvars[ncvarid].ndims == 1 )
+                {
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = X_AXIS;
+                }
+            }
         }
     }
 }
 
 static
-void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
-{
-  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
-  zaxisInqUUID(zaxisID, uuidOfVGrid);
-
-  if ( uuidOfVGrid[0] != 0 )
+int cdf_get_cell_varid(char *attstring, int ncid)
+{
+  int nc_cell_id = CDI_UNDEFID;
+
+  char *pstring = attstring;
+  while ( isspace((int) *pstring) ) pstring++;
+  char *cell_measures = pstring;
+  while ( isalnum((int) *pstring) ) pstring++;
+  *pstring++ = 0;
+  while ( isspace((int) *pstring) ) pstring++;
+  char *cell_var = pstring;
+  while ( ! isspace((int) *pstring) && *pstring != 0 ) pstring++;
+  *pstring++ = 0;
+  /*
+    printf("cell_measures >%s<\n", cell_measures);
+    printf("cell_var >%s<\n", cell_var);
+  */
+  if ( str_is_equal(cell_measures, "area") )
     {
-      char uuidOfVGridStr[37];
-      cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
-      if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 )
-        {
-          int fileID  = streamptr->fileID;
-          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-          cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfVGrid", 36, uuidOfVGridStr);
-          if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-        }
+      int nc_var_id;
+      int status = nc_inq_varid(ncid, cell_var, &nc_var_id);
+      if ( status == NC_NOERR )
+        nc_cell_id = nc_var_id;
+      /*
+      else
+        Warning("%s - %s", nc_strerror(status), cell_var);
+      */
     }
+
+  return nc_cell_id;
 }
 
 static
-void cdfDefUnstructured(stream_t *streamptr, int gridID)
+void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, int modelID, int format)
 {
-  int dimID = UNDEFID;
-  int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
-  int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
-  int nvdimID = UNDEFID;
-  nc_type xtype = NC_DOUBLE;
+  int ncdimid;
+  int nvdims, nvatts;
+  int iatt;
+  nc_type xtype, atttype;
+  size_t attlen;
+  char name[CDI_MAX_NAME];
+  char attname[CDI_MAX_NAME];
+  char attstring[8192];
 
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
+  int nchecked_vars = 0;
+  enum { max_check_vars = 9 };
+  char *checked_vars[max_check_vars];
+  for ( int i = 0; i < max_check_vars; ++i ) checked_vars[i] = NULL;
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ncid    = ncvars[ncvarid].ncid;
+      int *dimidsp = ncvars[ncvarid].dimids;
 
-  int ngrids = vlistNgrids(vlistID);
+      cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
+      strcpy(ncvars[ncvarid].name, name);
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
+      for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
+        ncvars[ncvarid].dimtype[ncdimid] = -1;
 
-  for ( int index = 0; index < ngrids; index++ )
-    {
-      if ( streamptr->xdimID[index] != UNDEFID )
+      ncvars[ncvarid].xtype = xtype;
+      ncvars[ncvarid].ndims = nvdims;
+
+#if  defined  (HAVE_NETCDF4)
+      if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_UNSTRUCTURED )
+          int shuffle, deflate, deflate_level;
+          size_t chunks[nvdims];
+          int storage_in;
+          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
+          if ( deflate > 0 ) ncvars[ncvarid].deflate = 1;
+          /*
+          size_t cache_size, nelems;
+          float preemption;
+          nc_get_chunk_cache(&cache_size, &nelems, &preemption);
+          printf("cache_size %lu nelems %lu preemption %g\n", cache_size, nelems, preemption);
+          nc_get_var_chunk_cache(ncid, ncvarid, &cache_size, &nelems, &preemption);
+          printf("varid %d cache_size %lu nelems %lu preemption %g\n", ncvarid, cache_size, nelems, preemption);
+          */
+          if ( nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR )
             {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0);
-              if ( dimlen == dimlen0 )
-		if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) &&
-		     IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) &&
-                     IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1), gridInqXval(gridID, (int)dimlen-1)) &&
-		     IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) &&
-                     IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1), gridInqYval(gridID, (int)dimlen-1)) )
-		  {
-		    dimID = streamptr->xdimID[index];
-                    ncxvarid = streamptr->ncxvarID[index];
-                    ncyvarid = streamptr->ncyvarID[index];
-                    ncavarid = streamptr->ncavarID[index];
-		    break;
-		  }
+              if ( storage_in == NC_CHUNKED )
+                {
+                  ncvars[ncvarid].chunked = 1;
+                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = chunks[i];
+                  if ( CDI_Debug )
+                    {
+                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
+                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%zu ", chunks[i]);
+                      fprintf(stderr, "\n");
+                    }
+                  {
+                    char *buf = ncvars[ncvarid].extra;
+                    size_t pos = strlen(buf);
+                    static const char prefix[] = "chunks=";
+                    memcpy(buf + pos, prefix, sizeof (prefix));
+                    pos += sizeof (prefix) - 1;
+                    for ( int i = nvdims-1; i >= 0; --i )
+                      {
+                        pos += (size_t)(sprintf(buf + pos, "%zu%s", chunks[i], i > 0 ? "x" : ""));
+                      }
+                    buf[pos] = ' '; buf[pos + 1] = 0;
+                  }
+                }
             }
         }
-    }
-
-  if ( dimID == UNDEFID )
-    {
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-      {
-        char xdimname[CDI_MAX_NAME+3];
-        xdimname[0] = 0;
-        cdiGridInqString(gridID, CDI_GRID_XDIMNAME, CDI_MAX_NAME, xdimname);
-        if ( xdimname[0] == 0 ) strcpy(xdimname, "ncells");
-        dimID = checkDimName(fileID, dimlen, xdimname);
-        if ( dimID == UNDEFID ) cdf_def_dim(fileID, xdimname, dimlen, &dimID);
-      }
+#endif
 
-      size_t nvertex = (size_t)gridInqNvertex(gridID);
-      if ( nvertex > 0 )
+      if ( nvdims > 0 )
         {
-          char vdimname[CDI_MAX_NAME+3];
-          vdimname[0] = 0;
-          cdiGridInqString(gridID, CDI_GRID_VDIMNAME, CDI_MAX_NAME, vdimname);
-          if ( vdimname[0] == 0 ) strcpy(vdimname, "vertices");
-          nvdimID = checkDimName(fileID, nvertex, vdimname);
-          if ( nvdimID == UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
+          if ( timedimid == dimidsp[0] )
+            {
+              ncvars[ncvarid].timetype = TIME_VARYING;
+              cdf_set_dim(ncvars, ncvarid, 0, T_AXIS);
+            }
+          else
+            {
+              for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
+                {
+                  if ( timedimid == dimidsp[ncdimid] )
+                    {
+                      Warning("Time must be the first dimension! Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
+                      ncvars[ncvarid].isvar = FALSE;
+                    }
+                }
+            }
         }
 
-      cdfDefGridReference(streamptr, gridID);
-
-      cdfDefGridUUID(streamptr, gridID);
-
-      if ( gridInqXvalsPtr(gridID) )
+      for ( iatt = 0; iatt < nvatts; iatt++ )
         {
-          char xaxisname[CDI_MAX_NAME];
-          gridInqXname(gridID, xaxisname);
-          checkGridName(xaxisname, fileID, vlistID, gridID, ngrids, 'X');
-          cdf_def_var(fileID, xaxisname, xtype, 1, &dimID, &ncxvarid);
-          cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
+          int nc_cell_id = CDI_UNDEFID;
 
-          cdfPutGridStdAtts(fileID, ncxvarid, gridID, &gridInqsX);
+          cdf_inq_attname(ncid, ncvarid, iatt, attname);
+          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
+          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
 
-          if ( gridInqXboundsPtr(gridID) && nvdimID != UNDEFID )
+          size_t attstringsize = sizeof(attstring);
+          bool isText = xtypeIsText(atttype);
+          bool isNumber = xtypeIsFloat(atttype) || xtypeIsInt(atttype);
+          if ( isText )
             {
-              int dimIDs[2] = { dimID, nvdimID };
-              size_t xaxisnameLen = strlen(xaxisname);
-              xaxisname[xaxisnameLen] = '_';
-              memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName));
-              cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncbxvarid);
-              cdfGridCompress(fileID, ncbxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
-
-              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+              cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
+              attstringsize = strlen(attstring) + 1;
+              if ( attstringsize > CDI_MAX_NAME ) attstringsize = CDI_MAX_NAME;
             }
-        }
 
-      if ( gridInqYvalsPtr(gridID) )
-        {
-          char yaxisname[CDI_MAX_NAME];
-          gridInqYname(gridID, yaxisname);
-          checkGridName(yaxisname, fileID, vlistID, gridID, ngrids, 'Y');
-          cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid);
-          cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
+          if ( isText && strcmp(attname, "long_name") == 0 )
+            {
+              memcpy(ncvars[ncvarid].longname, attstring, attstringsize);
+            }
+          else if ( isText && strcmp(attname, "standard_name") == 0 )
+            {
+              memcpy(ncvars[ncvarid].stdname, attstring, attstringsize);
+            }
+          else if ( isText && strcmp(attname, "units") == 0 )
+            {
+              memcpy(ncvars[ncvarid].units, attstring, attstringsize);
+            }
+          else if ( strcmp(attname, "calendar") == 0 )
+            {
+              ncvars[ncvarid].calendar = true;
+            }
+          else if ( isText && strcmp(attname, "param") == 0 )
+            {
+	      int pnum = 0, pcat = 255, pdis = 255;
+	      sscanf(attstring, "%d.%d.%d", &pnum, &pcat, &pdis);
+	      ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isNumber && strcmp(attname, "code") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isNumber && strcmp(attname, "table") == 0 )
+            {
+              int tablenum;
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum);
+              if ( tablenum > 0 )
+                {
+                  ncvars[ncvarid].tabnum = tablenum;
+                  ncvars[ncvarid].tableID = tableInq(modelID, tablenum, NULL);
+                  if ( ncvars[ncvarid].tableID == CDI_UNDEFID )
+                    ncvars[ncvarid].tableID = tableDef(modelID, tablenum, NULL);
+                }
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "trunc_type") == 0 )
+            {
+              if ( str_is_equal(attstring, "Triangular") )
+                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
+            }
+          else if ( isText && (strcmp(attname, "grid_type") == 0 || strcmp(attname, "CDI_grid_type") == 0) )
+            {
+              str_tolower(attstring);
+              set_gridtype(attstring, &ncvars[ncvarid].gridtype);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "level_type") == 0 )
+            {
+              str_tolower(attstring);
+              set_zaxistype(attstring, &ncvars[ncvarid].zaxistype);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isNumber && strcmp(attname, "trunc_count") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( isNumber && strcmp(attname, "truncation") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( isNumber && strcmp(attname, "number_of_grid_in_reference") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
+            }
+          else if ( isNumber && strcmp(attname, "add_offset") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset);
+	      /*
+		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
+		if ( ncvars[ncvarid].addoffset != 0 )
+		Warning("attribute add_offset not supported for atttype %d", atttype);
+	      */
+	      /* (also used for lon/lat) cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( isNumber && strcmp(attname, "scale_factor") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor);
+	      /*
+		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
+		if ( ncvars[ncvarid].scalefactor != 1 )
+		Warning("attribute scale_factor not supported for atttype %d", atttype);
+	      */
+	      /* (also used for lon/lat) cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( isText && strcmp(attname, "climatology") == 0 )
+            {
+              int ncboundsid;
+              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
+              if ( status == NC_NOERR )
+                {
+                  ncvars[ncvarid].climatology = true;
+                  ncvars[ncvarid].bounds = ncboundsid;
+                  cdf_set_var(ncvars, ncvars[ncvarid].bounds, FALSE);
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
+            }
+          else if ( isText && strcmp(attname, "bounds") == 0 )
+            {
+              int ncboundsid;
+              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
+              if ( status == NC_NOERR )
+                {
+                  ncvars[ncvarid].bounds = ncboundsid;
+                  cdf_set_var(ncvars, ncvars[ncvarid].bounds, FALSE);
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
+            }
+          else if ( isText &&  strcmp(attname, "formula_terms") == 0 )
+            {
+              ncvars[ncvarid].lformulaterms = true;
+            }
+          else if ( isText && strcmp(attname, "cell_measures") == 0 && (nc_cell_id=cdf_get_cell_varid(attstring, ncid)) != CDI_UNDEFID )
+            {
+              ncvars[ncvarid].cellarea = nc_cell_id;
+              ncvars[nc_cell_id].isvar = FALSE;
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          /*
+          else if ( strcmp(attname, "coordinates") == 0 )
+            {
+              char *pstring, *xvarname = NULL, *yvarname = NULL;
+              pstring = attstring;
 
-          cdfPutGridStdAtts(fileID, ncyvarid, gridID, &gridInqsY);
+              while ( isspace((int) *pstring) ) pstring++;
+              xvarname = pstring;
+              while ( isgraph((int) *pstring) ) pstring++;
+              *pstring++ = 0;
+              while ( isspace((int) *pstring) ) pstring++;
+              yvarname = pstring;
+              while ( isgraph((int) *pstring) ) pstring++;
+              *pstring++ = 0;
 
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
-            {
-              int dimIDs[2] = { dimID, nvdimID };
-              size_t yaxisnameLen = strlen(yaxisname);
-              yaxisname[yaxisnameLen] = '_';
-              memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName));
-              cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncbyvarid);
-              cdfGridCompress(fileID, ncbyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
+              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
+              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
 
-              cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+              cdf_set_var(ncvars, ncvars[ncvarid].xvarid, FALSE);
+              cdf_set_var(ncvars, ncvars[ncvarid].yvarid, FALSE);
+              cdf_set_var(ncvars, ncvarid, TRUE);
             }
-        }
-
-      if ( gridInqAreaPtr(gridID) )
-        {
-          static const char yaxisname_[] = "cell_area";
-          static const char units[] = "m2";
-          static const char longname[] = "area of grid cell";
-          static const char stdname[] = "cell_area";
+          */
+          else if ( isText && (strcmp(attname, "associate")  == 0 || strcmp(attname, "coordinates") == 0) )
+            {
+              bool lstop = false;
+              char *pstring = attstring;
 
-          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &ncavarid);
+              for ( int i = 0; i < MAX_COORDVARS; i++ )
+                {
+                  while ( isspace((int) *pstring) ) pstring++;
+                  if ( *pstring == 0 ) break;
+                  char *varname = pstring;
+                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+                  if ( *pstring == 0 ) lstop = true;
+                  if ( *(pstring-1) == ',' ) *(pstring-1) = 0;
+                  *pstring++ = 0;
 
-          cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
-          cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
-          cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units);
-        }
+                  int dimvarid;
+                  int status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdf_set_var(ncvars, dimvarid, FALSE);
+                      if ( !cdiIgnoreAttCoordinates )
+                        {
+                          ncvars[ncvarid].coordvarids[i] = dimvarid;
+                          ncvars[ncvarid].ncoordvars++;
+                        }
+                    }
+                  else
+                    {
+                      int k;
+                      for ( k = 0; k < nchecked_vars; ++k )
+                        if ( strcmp(checked_vars[k], varname) == 0 ) break;
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+                      if ( k == nchecked_vars )
+                        {
+                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
+                          Warning("%s - >%s<", nc_strerror(status), varname);
+                        }
+                    }
 
-      if ( ncxvarid  != UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
-      if ( ncbxvarid != UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
-      if ( ncyvarid  != UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
-      if ( ncbyvarid != UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
-      if ( ncavarid  != UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
-    }
+                  if ( lstop ) break;
+                }
 
-  streamptr->xdimID[gridindex] = dimID;
-  streamptr->ncxvarID[gridindex] = ncxvarid;
-  streamptr->ncyvarID[gridindex] = ncyvarid;
-  streamptr->ncavarID[gridindex] = ncavarid;
-}
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "auxiliary_variable") == 0 )
+            {
+              bool lstop = false;
+              char *pstring = attstring;
 
-struct attTxtTab2
-{
-  const char *attName, *attVal;
-  size_t valLen;
-};
+              for ( int i = 0; i < MAX_AUXVARS; i++ )
+                {
+                  while ( isspace((int) *pstring) ) pstring++;
+                  if ( *pstring == 0 ) break;
+                  char *varname = pstring;
+                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
+                  if ( *pstring == 0 ) lstop = true;
+                  *pstring++ = 0;
 
-static
-void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
-{
-  int type = zaxisInqType(zaxisID);
+                  int dimvarid;
+                  int status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdf_set_var(ncvars, dimvarid, FALSE);
+                      //  if ( !cdiIgnoreAttCoordinates )
+                        {
+                          ncvars[ncvarid].auxvarids[i] = dimvarid;
+                          ncvars[ncvarid].nauxvars++;
+                        }
+                    }
+                  else
+                    Warning("%s - %s", nc_strerror(status), varname);
 
-  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
-    {
-      int ilev = zaxisInqVctSize(zaxisID)/2;
-      if ( ilev == 0 ) return;
+                  if ( lstop ) break;
+                }
 
-      int mlev = ilev - 1;
-      size_t start;
-      size_t count = 1;
-      int ncdimid, ncdimid2;
-      int hyaiid, hybiid, hyamid, hybmid;
-      double mval;
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "grid_mapping") == 0 )
+            {
+              int nc_gmap_id;
+              int status = nc_inq_varid(ncid, attstring, &nc_gmap_id);
+              if ( status == NC_NOERR )
+                {
+                  ncvars[ncvarid].gmapid = nc_gmap_id;
+                  cdf_set_var(ncvars, ncvars[ncvarid].gmapid, FALSE);
+                }
+              else
+                Warning("%s - %s", nc_strerror(status), attstring);
 
-      if ( streamptr->vct.ilev > 0 )
-        {
-          if ( streamptr->vct.ilev != ilev )
-            Error("more than one VCT for each file unsupported!");
-          return;
-        }
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "positive") == 0 )
+            {
+              str_tolower(attstring);
 
-      int fileID = streamptr->fileID;
+              if      ( str_is_equal(attstring, "down") ) ncvars[ncvarid].positive = POSITIVE_DOWN;
+              else if ( str_is_equal(attstring, "up")   ) ncvars[ncvarid].positive = POSITIVE_UP;
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+              if ( ncvars[ncvarid].ndims == 1 )
+                {
+                  cdf_set_var(ncvars, ncvarid, FALSE);
+                  cdf_set_dim(ncvars, ncvarid, 0, Z_AXIS);
+                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
+                }
+            }
+          else if ( isNumber && strcmp(attname, "_FillValue") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
+	      ncvars[ncvarid].deffillval = true;
+	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( isNumber && strcmp(attname, "missing_value") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval);
+	      ncvars[ncvarid].defmissval = true;
+	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( isNumber && strcmp(attname, "valid_range") == 0 && attlen == 2 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
+                  if ( !cdiIgnoreValidRange && lignore == false )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 2, ncvars[ncvarid].validrange);
+                      ncvars[ncvarid].lvalidrange = true;
+                      if ( ((int)ncvars[ncvarid].validrange[0]) == 0 && ((int)ncvars[ncvarid].validrange[1]) == 255 )
+                        ncvars[ncvarid].lunsigned = true;
+                      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_range, ignored!", name);
+                    }
+                }
+            }
+          else if ( isNumber && strcmp(attname, "valid_min") == 0 && attlen == 1 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
+                  if ( !cdiIgnoreValidRange && lignore == false )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[0]);
+                      ncvars[ncvarid].lvalidrange = true;
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_min, ignored!", name);
+                    }
+                }
+            }
+          else if ( isNumber && strcmp(attname, "valid_max") == 0 && attlen == 1 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  bool lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
+                  if ( !cdiIgnoreValidRange && lignore == false )
+                    {
+                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[1]);
+                      ncvars[ncvarid].lvalidrange = true;
+                    }
+                  else if ( lignore )
+                    {
+                      Warning("Inconsistent data type for attribute %s:valid_max, ignored!", name);
+                    }
+                }
+            }
+          else if ( isText && strcmp(attname, "_Unsigned") == 0 )
+            {
+              str_tolower(attstring);
 
-      cdf_def_dim(fileID, "nhym", (size_t)mlev, &ncdimid);
-      cdf_def_dim(fileID, "nhyi", (size_t)ilev, &ncdimid2);
+              if ( str_is_equal(attstring, "true") )
+                {
+                  ncvars[ncvarid].lunsigned = true;
+                  /*
+                  ncvars[ncvarid].lvalidrange = true;
+                  ncvars[ncvarid].validrange[0] = 0;
+                  ncvars[ncvarid].validrange[1] = 255;
+                  */
+                }
+	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( isText && strcmp(attname, "cdi") == 0 )
+            {
+	      str_tolower(attstring);
 
-      streamptr->vct.mlev   = mlev;
-      streamptr->vct.ilev   = ilev;
-      streamptr->vct.mlevID = ncdimid;
-      streamptr->vct.ilevID = ncdimid2;
+	      if ( str_is_equal(attstring, "ignore") )
+		{
+		  ncvars[ncvarid].ignore = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		}
+            }
+          else if ( isText && strcmp(attname, "axis") == 0 )
+            {
+	      attlen = strlen(attstring);
 
-      cdf_def_var(fileID, "hyai", NC_DOUBLE, 1, &ncdimid2, &hyaiid);
-      cdf_def_var(fileID, "hybi", NC_DOUBLE, 1, &ncdimid2, &hybiid);
-      cdf_def_var(fileID, "hyam", NC_DOUBLE, 1, &ncdimid,  &hyamid);
-      cdf_def_var(fileID, "hybm", NC_DOUBLE, 1, &ncdimid,  &hybmid);
+	      if ( (int) attlen > nvdims && nvdims > 0 && attlen > 1 )
+		{
+		    Warning("Unexpected axis attribute length for %s, ignored!", name);
+		}
+              else if ( nvdims == 0 && attlen == 1 )
+                {
+                  if ( attstring[0] == 'z' || attstring[0] == 'Z' )
+                    {
+                      cdf_set_var(ncvars, ncvarid, FALSE);
+                      ncvars[ncvarid].islev = true;
+                    }
+                }
+	      else
+		{
+		  str_tolower(attstring);
+                  cdf_scan_attr_axis(ncvars, ncdims, ncvarid, attstring, attlen, nvdims, dimidsp, name);
+		}
+	    }
+	  else if ( isNumber &&
+                    (strcmp(attname, "realization") == 0       ||
+                     strcmp(attname, "ensemble_members") == 0  ||
+                     strcmp(attname, "forecast_init_type") == 0) )
+	    {
+	      int temp;
 
-      {
-        static const char lname_n[] = "long_name",
-          lname_v_ai[] = "hybrid A coefficient at layer interfaces",
-          units_n[] = "units",
-          units_v_ai[] = "Pa",
-          lname_v_bi[] = "hybrid B coefficient at layer interfaces",
-          units_v_bi[] = "1",
-          lname_v_am[] = "hybrid A coefficient at layer midpoints",
-          units_v_am[] = "Pa",
-          lname_v_bm[] = "hybrid B coefficient at layer midpoints",
-          units_v_bm[] = "1";
-        static const struct attTxtTab2 tab[]
-          = {
-          { lname_n, lname_v_ai, sizeof (lname_v_ai) - 1 },
-          { units_n, units_v_ai, sizeof (units_v_ai) - 1 },
-          { lname_n, lname_v_bi, sizeof (lname_v_bi) - 1 },
-          { units_n, units_v_bi, sizeof (units_v_bi) - 1 },
-          { lname_n, lname_v_am, sizeof (lname_v_am) - 1 },
-          { units_n, units_v_am, sizeof (units_v_am) - 1 },
-          { lname_n, lname_v_bm, sizeof (lname_v_bm) - 1 },
-          { units_n, units_v_bm, sizeof (units_v_bm) - 1 },
-        };
-        enum { tabLen = sizeof (tab) / sizeof (tab[0]) };
-        int ids[tabLen] = { hyaiid, hyaiid, hybiid, hybiid,
-                            hyamid, hyamid, hybmid, hybmid };
-        for ( size_t i = 0; i < tabLen; ++i )
-          cdf_put_att_text(fileID, ids[i], tab[i].attName, tab[i].valLen, tab[i].attVal);
-      }
+	      if( ncvars[ncvarid].ensdata == NULL )
+		ncvars[ncvarid].ensdata = (ensinfo_t *) Malloc( sizeof( ensinfo_t ) );
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
 
-      const double *vctptr = zaxisInqVctPtr(zaxisID);
+	      if( strcmp(attname, "realization") == 0 )
+		ncvars[ncvarid].ensdata->ens_index = temp;
+	      else if( strcmp(attname, "ensemble_members") == 0 )
+		ncvars[ncvarid].ensdata->ens_count = temp;
+	      else if( strcmp(attname, "forecast_init_type") == 0 )
+		ncvars[ncvarid].ensdata->forecast_init_type = temp;
 
-      cdf_put_var_double(fileID, hyaiid, vctptr);
-      cdf_put_var_double(fileID, hybiid, vctptr+ilev);
+	      cdf_set_var(ncvars, ncvarid, TRUE);
+	    }
+	  else
+	    {
+	      if ( ncvars[ncvarid].natts == 0 )
+		ncvars[ncvarid].atts = (int*) Malloc((size_t)nvatts*sizeof(int));
 
-      for ( int i = 0; i < mlev; i++ )
-        {
-          start = (size_t)i;
-          mval = (vctptr[i] + vctptr[i+1]) * 0.5;
-          cdf_put_vara_double(fileID, hyamid, &start, &count, &mval);
-          mval = (vctptr[ilev+i] + vctptr[ilev+i+1]) * 0.5;
-          cdf_put_vara_double(fileID, hybmid, &start, &count, &mval);
-        }
+	      ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
+	      /*
+	      int attrint;
+	      double attrflt;
+	      nc_type atttype;
+	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+	      cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
+	      if ( attlen == 1 && (atttype == NC_INT || atttype == NC_SHORT) )
+		{
+		  cdfGetAttInt(ncid, ncvarid, attname, 1, &attrint);
+		  printf("int: %s.%s = %d\n", ncvars[ncvarid].name, attname, attrint);
+		}
+	      else if ( attlen == 1 && (atttype == NC_FLOAT || atttype == NC_DOUBLE) )
+		{
+		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
+		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
+		}
+	      else if ( atttype == NC_CHAR )
+		{
+		  attstring[attlen] = 0;
+		  printf("txt: %s.%s = %s\n", ncvars[ncvarid].name, attname, attstring);
+		}
+	      else
+		printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
+              */
+	    }
+	}
     }
+
+  for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
 }
 
 static
-void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
+void cdf_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
 {
-  int type = zaxisInqType(zaxisID);
-
-  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      int ilev = zaxisInqVctSize(zaxisID)/2;
-      if ( ilev == 0 ) return;
-
-      int mlev = ilev - 1;
-      int hyaiid = 0, hybiid = 0, hyamid, hybmid;
-
-      if ( streamptr->vct.ilev > 0 )
-        {
-          if ( streamptr->vct.ilev != ilev )
-            Error("more than one VCT for each file unsupported!");
-          return;
-        }
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      int ncdimid = ncvars[ncvarid].dimids[i];
+              int dimtype = ncdims[ncdimid].dimtype;
+	      if ( dimtype >= X_AXIS && dimtype <= T_AXIS )
+                cdf_set_dim(ncvars, ncvarid, i, dimtype);
+	    }
 
-      int fileID = streamptr->fileID;
+	  if ( CDI_Debug )
+	    {
+	      Message("var %d %s", ncvarid, ncvars[ncvarid].name);
+	      for ( int i = 0; i < ndims; i++ )
+		printf("  dim%d type=%d  ", i, ncvars[ncvarid].dimtype[i]);
+	      printf("\n");
+	    }
+          }
+      }
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+          int lcdim = 0;
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+              int dimtype = ncvars[ncvarid].dimtype[i];
+              lxdim = lxdim | (dimtype == X_AXIS);
+	      lydim = lydim | (dimtype == Y_AXIS);
+	      lzdim = lzdim | (dimtype == Z_AXIS);
+              if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++;
+	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
 
-      int dimIDs[2];
-      dimIDs[0] = nclevID;
-      dimIDs[1] = ncbndsID;
+          int allcdims = lcdim;
 
-      streamptr->vct.mlev   = mlev;
-      streamptr->vct.ilev   = ilev;
-      streamptr->vct.mlevID = nclevID;
-      streamptr->vct.ilevID = nclevID;
+          if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
+            }
 
-      cdf_def_var(fileID, "ap", NC_DOUBLE, 1, dimIDs,  &hyamid);
-      cdf_def_var(fileID, "b",  NC_DOUBLE, 1, dimIDs,  &hybmid);
+          if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
+            }
 
-      {
-        static const char lname[] = "vertical coordinate formula term: ap(k)";
-        cdf_put_att_text(fileID, hyamid, "long_name", sizeof (lname) - 1, lname);
-      }
-      {
-        static const char units[] = "Pa";
-        cdf_put_att_text(fileID, hyamid, "units", sizeof (units) - 1, units);
-      }
-      {
-        static const char lname[] = "vertical coordinate formula term: b(k)";
-        cdf_put_att_text(fileID, hybmid, "long_name", sizeof (lname) - 1, lname);
-      }
-      {
-        static const char units[] = "1";
-        cdf_put_att_text(fileID, hybmid, "units", sizeof (units) - 1, units);
-      }
+          if ( lxdim && (lydim || ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED) )
+            for ( int i = ndims-1; i >= 0; i-- )
+              {
+                if ( ncvars[ncvarid].dimtype[i] == -1 )
+                  {
+                    if ( !lzdim )
+                      {
+                        if ( lcdim )
+                          {
+                            int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
+                            ncvars[ncvarid].zvarid = cdimvar;
+                            lcdim--;
+		            ncvars[cdimvar].zaxistype = ZAXIS_CHAR;
+                          }
+                        cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+                        lzdim = true;
+                        int ncdimid = ncvars[ncvarid].dimids[i];
+                        if ( ncdims[ncdimid].dimtype == CDI_UNDEFID )
+                          ncdims[ncdimid].dimtype = Z_AXIS;
+                      }
+                  }
+              }
+	}
+    }
 
-      if ( ncbndsID != -1 )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ndims = ncvars[ncvarid].ndims;
+      for ( int i = 0; i < ndims; i++ )
         {
-          cdf_def_var(fileID, "ap_bnds", NC_DOUBLE, 2, dimIDs, &hyaiid);
-          cdf_def_var(fileID, "b_bnds",  NC_DOUBLE, 2, dimIDs, &hybiid);
-          {
-            static const char lname[] = "vertical coordinate formula term: ap(k+1/2)";
-            cdf_put_att_text(fileID, hyaiid, "long_name", sizeof (lname) - 1, lname);
-          }
-          {
-            static const char units[] = "Pa";
-            cdf_put_att_text(fileID, hyaiid, "units", sizeof (units) - 1, units);
-          }
-          {
-            static const char lname[] = "vertical coordinate formula term: b(k+1/2)";
-            cdf_put_att_text(fileID, hybiid, "long_name", sizeof (lname) - 1, lname);
-          }
-          {
-            static const char units[] = "1";
-            cdf_put_att_text(fileID, hybiid, "units", sizeof (units) - 1, units);
-          }
+          if ( ncvars[ncvarid].dimtype[i] == CDI_UNDEFID )
+            {
+              int ncdimid = ncvars[ncvarid].dimids[i];
+              if ( ncdims[ncdimid].dimtype == Z_AXIS )
+                {
+                  ncvars[ncvarid].islev = true;
+                  cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+                }
+            }
         }
+    }
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+          int lcdim = 0;
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = true;
+	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = true;
+	      else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = true;
+              else if ( ncvars[ncvarid].cvarids[i] != CDI_UNDEFID ) lcdim++;
+	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
 
-      const double *vctptr = zaxisInqVctPtr(zaxisID);
-      double tarray[ilev*2];
+          int allcdims = lcdim;
 
-      if ( ncbndsID != -1 )
-        {
-          for ( int i = 0; i < mlev; ++i )
+          if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
             {
-              tarray[2*i  ] = vctptr[i];
-              tarray[2*i+1] = vctptr[i+1];
+              if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
             }
-          cdf_put_var_double(fileID, hyaiid, tarray);
 
-          for ( int i = 0; i < mlev; ++i )
+          if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
             {
-              tarray[2*i  ] = vctptr[ilev+i];
-              tarray[2*i+1] = vctptr[ilev+i+1];
+              if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
             }
-          cdf_put_var_double(fileID, hybiid, tarray);
-        }
-
-      for ( int i = 0; i < mlev; ++i )
-        tarray[i] = (vctptr[i] + vctptr[i+1]) * 0.5;
-      cdf_put_var_double(fileID, hyamid, tarray);
 
-      for ( int i = 0; i < mlev; ++i )
-        tarray[i] = (vctptr[ilev+i] + vctptr[ilev+i+1]) * 0.5;
-      cdf_put_var_double(fileID, hybmid, tarray);
+          //   if ( ndims > 1 )
+            for ( int i = ndims-1; i >= 0; i-- )
+              {
+                if ( ncvars[ncvarid].dimtype[i] == -1 )
+                  {
+                    if ( !lxdim )
+                      {
+                        if ( lcdim && ncvars[ncvarid].xvarid == CDI_UNDEFID )
+                          {
+                            int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
+                            ncvars[ncvarid].xvarid = cdimvar;
+                            lcdim--;
+                          }
+                        cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
+                        lxdim = true;
+                      }
+                    else if ( !lydim && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
+                      {
+                        if ( lcdim && ncvars[ncvarid].yvarid == CDI_UNDEFID )
+                          {
+                            int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
+                            ncvars[ncvarid].yvarid = cdimvar;
+                            lcdim--;
+                          }
+                        cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
+                        lydim = true;
+                      }
+                    else if ( !lzdim )
+                      {
+                        if ( lcdim > 0 )
+                          {
+                            int cdimvar = ncvars[ncvarid].cvarids[allcdims-lcdim];
+                            ncvars[ncvarid].zvarid = cdimvar;
+                            lcdim--;
+		            ncvars[cdimvar].zaxistype = ZAXIS_CHAR;
+                          }
+                        cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+                        lzdim = true;
+                      }
+                  }
+              }
+	}
     }
 }
 
-struct attTxtTab { const char *txt; size_t txtLen; };
-
+/* verify coordinate vars - first scan (dimname == varname) */
 static
-void cdf_def_zaxis_hybrid_echam(stream_t *streamptr, int type, int ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
+void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncvars, int timedimid, bool *lhybrid_cf)
 {
-  int fileID  = streamptr->fileID;
-
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  cdf_def_dim(fileID, axisname, dimlen, dimID);
-  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
-
-  {
-    static const char sname[] = "hybrid_sigma_pressure";
-    cdf_put_att_text(fileID, ncvarid, "standard_name", sizeof (sname) - 1, sname);
-  }
-  {
-    static const char *attName[] = {
-      "long_name",
-      "formula",
-      "formula_terms"
-    };
-    enum { nAtt = sizeof (attName) / sizeof (attName[0]) };
-    static const char lname_m[] = "hybrid level at layer midpoints",
-      formula_m[] = "hyam hybm (mlev=hyam+hybm*aps)",
-      fterms_m[] = "ap: hyam b: hybm ps: aps",
-      lname_i[] = "hybrid level at layer interfaces",
-      formula_i[] = "hyai hybi (ilev=hyai+hybi*aps)",
-      fterms_i[] = "ap: hyai b: hybi ps: aps";
-    static const struct attTxtTab tab[2][nAtt] = {
-      {
-        { lname_i, sizeof (lname_i) - 1 },
-        { formula_i, sizeof (formula_i) - 1 },
-        { fterms_i, sizeof (fterms_i) - 1 }
-      },
-      {
-        { lname_m, sizeof (lname_m) - 1 },
-        { formula_m, sizeof (formula_m) - 1 },
-        { fterms_m, sizeof (fterms_m) - 1 }
-      }
-    };
-
-    size_t tabSelect = type == ZAXIS_HYBRID;
-    for (size_t i = 0; i < nAtt; ++i)
-      cdf_put_att_text(fileID, ncvarid, attName[i],
-                       tab[tabSelect][i].txtLen, tab[tabSelect][i].txt);
-  }
-
-  {
-    static const char units[] = "level";
-    cdf_put_att_text(fileID, ncvarid, "units", sizeof (units) - 1, units);
-  }
-  {
-    static const char direction[] = "down";
-    cdf_put_att_text(fileID, ncvarid, "positive", sizeof (direction) - 1, direction);
-  }
+  for ( int ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      int ncvarid = ncdims[ncdimid].ncvarid;
+      if ( ncvarid != -1 )
+	{
+	  if ( ncvars[ncvarid].dimids[0] == timedimid )
+	    {
+              ncvars[ncvarid].istime = true;
+	      ncdims[ncdimid].dimtype = T_AXIS;
+	      continue;
+	    }
 
-  cdf_enddef(fileID);
-  streamptr->ncmode = 2;
+          if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) )
+            {
+              *lhybrid_cf = true;
+              continue;
+            }
 
-  cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
+	  if ( ncvars[ncvarid].units[0] != 0 )
+	    {
+	      if ( is_lon_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islon = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
+		  ncdims[ncdimid].dimtype = X_AXIS;
+		}
+	      else if ( is_lat_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islat = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
+		  ncdims[ncdimid].dimtype = Y_AXIS;
+		}
+	      else if ( is_x_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].isx = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
+		  ncdims[ncdimid].dimtype = X_AXIS;
+		}
+	      else if ( is_y_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].isy = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
+		  ncdims[ncdimid].dimtype = Y_AXIS;
+		}
+	      else if ( is_pressure_units(ncvars[ncvarid].units) )
+		{
+		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
+		}
+	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
+		{
+		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
+		}
+	      else if ( is_DBL_axis(ncvars[ncvarid].longname) )
+                {
+                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
+		}
+	      else if ( is_height_units(ncvars[ncvarid].units) )
+		{
+		  if ( is_depth_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
+		  else if ( is_height_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
+		}
+	    }
+          else
+            {
+              if ( (strcmp(ncvars[ncvarid].longname, "generalized_height") == 0 ||
+                    strcmp(ncvars[ncvarid].longname, "generalized height") == 0) &&
+                   strcmp(ncvars[ncvarid].stdname, "height") == 0 )
+                  ncvars[ncvarid].zaxistype = ZAXIS_REFERENCE;
+            }
 
-  cdf_def_vct_echam(streamptr, zaxisID);
+	  if ( !ncvars[ncvarid].islon && ncvars[ncvarid].longname[0] != 0 &&
+               !ncvars[ncvarid].islat && ncvars[ncvarid].longname[1] != 0 )
+	    {
+	      if ( str_is_equal(ncvars[ncvarid].longname+1, "ongitude") )
+		{
+		  ncvars[ncvarid].islon = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, X_AXIS);
+		  ncdims[ncdimid].dimtype = X_AXIS;
+		  continue;
+		}
+	      else if ( str_is_equal(ncvars[ncvarid].longname+1, "atitude") )
+		{
+		  ncvars[ncvarid].islat = true;
+		  cdf_set_var(ncvars, ncvarid, FALSE);
+		  cdf_set_dim(ncvars, ncvarid, 0, Y_AXIS);
+		  ncdims[ncdimid].dimtype = Y_AXIS;
+		  continue;
+		}
+	    }
 
-  if ( *dimID == UNDEFID )
-    {
-      if ( type == ZAXIS_HYBRID )
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
-      else
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+	  if ( ncvars[ncvarid].zaxistype != CDI_UNDEFID )
+	    {
+              ncvars[ncvarid].islev = true;
+	      cdf_set_var(ncvars, ncvarid, FALSE);
+	      cdf_set_dim(ncvars, ncvarid, 0, Z_AXIS);
+	      ncdims[ncdimid].dimtype = Z_AXIS;
+	    }
+	}
     }
 }
 
+/* verify coordinate vars - second scan (all other variables) */
 static
-void cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
+void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
 {
-  char psname[CDI_MAX_NAME];
-  psname[0] = 0;
-  zaxisInqPsName(zaxisID, psname);
-  if ( psname[0] == 0 ) strcpy(psname, "ps");
-
-  int fileID = streamptr->fileID;
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  strcpy(axisname, "lev");
-
-  cdf_def_dim(fileID, axisname, dimlen, dimID);
-  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
-
-  {
-    static const char sname[] = "standard_name",
-      sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate",
-      lname[] = "long_name",
-      lname_v[] = "hybrid sigma pressure coordinate",
-      formula[] = "formula",
-      formula_v[] = "p = ap + b*ps",
-      fterms[] = "formula_terms",
-      fterms_v[] = "ap: ap b: b ps: ",
-      units[] = "units",
-      units_v[] = "1",
-      axis[] = "axis",
-      axis_v[] = "Z",
-      direction[] = "positive",
-      direction_v[] = "down";
-    struct attTxtTab2 tab[] = {
-      { sname, sname_v, sizeof (sname_v) - 1 },
-      { lname, lname_v, sizeof (lname_v) - 1 },
-      { formula, formula_v, sizeof (formula_v) - 1 },
-      { fterms, fterms_v, sizeof (fterms_v) - 1 },
-      { units, units_v, sizeof (units_v) - 1 },
-      { axis, axis_v, sizeof (axis_v) - 1 },
-      { direction, direction_v, sizeof (direction_v) - 1 },
-    };
-    enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
-    for (size_t i = 0; i < nAtt; ++i)
-      cdf_put_att_text(fileID, ncvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
-  }
-
-  int ncbvarid = UNDEFID;
-  int nvdimID = UNDEFID;
-
-  double lbounds[dimlen], ubounds[dimlen], levels[dimlen];
-
-  zaxisInqLevels(zaxisID, levels);
-
-  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-    {
-      zaxisInqLbounds(zaxisID, lbounds);
-      zaxisInqUbounds(zaxisID, ubounds);
-    }
-  else
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      for ( size_t i = 0; i < dimlen; ++i ) lbounds[i] = levels[i];
-      for ( size_t i = 0; i < dimlen-1; ++i ) ubounds[i] = levels[i+1];
-      ubounds[dimlen-1] = levels[dimlen-1] + 1;
+      if ( ncvars[ncvarid].isvar == 0 )
+	{
+	  if ( ncvars[ncvarid].units[0] != 0 )
+	    {
+	      if ( is_lon_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islon = true;
+		  continue;
+		}
+	      else if ( is_lat_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].islat = true;
+		  continue;
+		}
+	      else if ( is_x_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].isx = true;
+		  continue;
+		}
+	      else if ( is_y_axis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
+		{
+		  ncvars[ncvarid].isy = true;
+		  continue;
+		}
+	      else if ( ncvars[ncvarid].zaxistype == CDI_UNDEFID &&
+                        (strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0) )
+		{
+		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
+		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
+		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
+		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
+		  continue;
+		}
+	      else if ( ncvars[ncvarid].zaxistype == CDI_UNDEFID && is_pressure_units(ncvars[ncvarid].units) )
+		{
+		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
+		  continue;
+		}
+	      else if ( is_DBL_axis(ncvars[ncvarid].longname) )
+		{
+                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
+		  continue;
+		}
+	      else if ( is_height_units(ncvars[ncvarid].units) )
+		{
+		  if ( is_depth_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
+		  else if ( is_height_axis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
+		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
+		  continue;
+		}
+            }
+          else if ( strcmp(ncvars[ncvarid].stdname, "region") == 0  ||
+                    strcmp(ncvars[ncvarid].stdname, "area_type") == 0 ||
+                    cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == CDI_DATATYPE_UINT8 )
+            {
+              ncvars[ncvarid].isc = true;
+            }
+
+	  /* not needed anymore for rotated grids */
+	  if ( !ncvars[ncvarid].islon && ncvars[ncvarid].longname[0] != 0 &&
+               !ncvars[ncvarid].islat && ncvars[ncvarid].longname[1] != 0 )
+	    {
+	      if ( str_is_equal(ncvars[ncvarid].longname+1, "ongitude") )
+		{
+		  ncvars[ncvarid].islon = true;
+		  continue;
+		}
+	      else if ( str_is_equal(ncvars[ncvarid].longname+1, "atitude") )
+		{
+		  ncvars[ncvarid].islat = true;
+		  continue;
+		}
+	    }
+	}
     }
+}
 
-  //if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+static
+void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+{
+  if ( ncvar->chunked )
     {
-      size_t nvertex = 2;
-      if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
-        cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
+      int ndims = ncvar->ndims;
 
-      if ( nvdimID != UNDEFID )
+      if ( grid->type == GRID_UNSTRUCTURED )
         {
-          size_t axisnameLen = strlen(axisname);
-          axisname[axisnameLen] = '_';
-          memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
-          axisnameLen += sizeof (bndsName);
-          int dimIDs[2] = { *dimID, nvdimID };
-          cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
-          cdf_put_att_text(fileID, ncvarid, "bounds", axisnameLen, axisname);
-          {
-            static const char sname[] = "standard_name",
-              sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate",
-              formula[] = "formula",
-              formula_v[] = "p = ap + b*ps";
-            struct attTxtTab2 tab[] = {
-              { sname, sname_v, sizeof (sname_v) - 1 },
-              { formula, formula_v, sizeof (formula_v) - 1 },
-            };
-            enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
-            for (size_t i = 0; i < nAtt; ++i)
-              cdf_put_att_text(fileID, ncbvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
-          }
-          {
-            char txt[CDI_MAX_NAME];
-            size_t len = (size_t)(sprintf(txt, "%s%s", "ap: ap_bnds b: b_bnds ps: ", psname));
-            cdf_put_att_text(fileID, ncbvarid, "formula_terms", len, txt);
-          }
-          {
-            static const char units[] = "1";
-            cdf_put_att_text(fileID, ncbvarid, "units", sizeof (units) - 1, units);
-          }
+          ncvar->chunktype = ncvar->chunks[ndims-1] == grid->size
+            ? CDI_CHUNK_GRID : CDI_CHUNK_AUTO;
         }
-    }
-
-  cdf_enddef(fileID);
-  streamptr->ncmode = 2;
-
-  cdf_put_var_double(fileID, ncvarid, levels);
-
-  if ( ncbvarid != UNDEFID )
-    {
-      double zbounds[2*dimlen];
-      for ( size_t i = 0; i < dimlen; ++i )
+      else
         {
-          zbounds[2*i  ] = lbounds[i];
-          zbounds[2*i+1] = ubounds[i];
+          if ( grid->x.size > 1 && grid->y.size > 1 && ndims > 1 &&
+               grid->x.size == ncvar->chunks[ndims-1] &&
+               grid->y.size == ncvar->chunks[ndims-2] )
+            ncvar->chunktype = CDI_CHUNK_GRID;
+          else if ( grid->x.size > 1 && grid->x.size == ncvar->chunks[ndims-1] )
+            ncvar->chunktype = CDI_CHUNK_LINES;
+          else
+            ncvar->chunktype = CDI_CHUNK_AUTO;
         }
-      cdf_put_var_double(fileID, ncbvarid, zbounds);
     }
+}
 
-  cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID);
-
-  if ( *dimID == UNDEFID )
+/* define all input grids */
+static
+void cdf_load_vals(size_t size, int ndims, int varid, ncvar_t *ncvar, double **gridvals, struct xyValGet *valsGet,
+                   int ntdims, size_t *start, size_t *count)
+{
+  if ( CDI_netcdf_lazy_grid_load )
+    {
+      *valsGet = (struct xyValGet){
+        .scalefactor = ncvar->scalefactor,
+        .addoffset = ncvar->addoffset,
+        .start = { start[0], start[1], start[2] },
+        .count = { count[0], count[1], count[2] },
+        .size = size,
+        .datasetNCId = ncvar->ncid,
+        .varNCId = varid,
+        .ndims = (short)ndims,
+      };
+      *gridvals = cdfPendingLoad;
+    }
+  else
     {
-      if ( type == ZAXIS_HYBRID )
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
+      *gridvals = (double*) Malloc(size*sizeof(double));
+      if ( ntdims == 1 )
+        cdf_get_vara_double(ncvar->ncid, varid, start, count, *gridvals);
       else
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+        cdf_get_var_double(ncvar->ncid, varid, *gridvals);
+      cdf_scale_add(size, *gridvals, ncvar->addoffset, ncvar->scalefactor);
     }
 }
 
 static
-void cdf_def_zaxis_hybrid(stream_t *streamptr, int type, int ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
+void cdf_load_cvals(size_t size, int varid, ncvar_t *ncvar, char ***gridvals, size_t dimlength)
 {
-  if ( (!CDI_cmor_mode && cdiConvention == CDI_CONVENTION_ECHAM) || type == ZAXIS_HYBRID_HALF )
-    cdf_def_zaxis_hybrid_echam(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname);
-  else
-    cdf_def_zaxis_hybrid_cf(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname);
+  size_t startc[] = {0, 0};
+  size_t countc[] = {1, size/dimlength};
+  *gridvals = (char **) Malloc(dimlength * sizeof(char *));
+  for ( size_t i = 0; i < dimlength; i++ )
+    {
+      (*gridvals)[i] = (char*) Malloc((size/dimlength) * sizeof(char));
+      cdf_get_vara_text(ncvar->ncid, varid, startc, countc, (*gridvals)[i]);
+      startc[0] = i+1;
+    }
 }
 
 static
-void cdfDefZaxis(stream_t *streamptr, int zaxisID)
+void cdf_load_bounds(size_t size, ncvar_t *ncvar, double **gridbounds, struct cdfLazyGridIds *cellBoundsGet)
 {
-  /*  char zaxisname0[CDI_MAX_NAME]; */
-  char axisname[CDI_MAX_NAME];
-  int dimID = UNDEFID;
-  int dimIDs[2];
-  int ncvarid = UNDEFID, ncbvarid = UNDEFID;
-  int nvdimID = UNDEFID;
-  int xtype = NC_DOUBLE;
-
-  if ( zaxisInqPrec(zaxisID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-
-  int nzaxis = vlistNzaxis(vlistID);
-
-  size_t dimlen = (size_t)zaxisInqSize(zaxisID);
-  int type   = zaxisInqType(zaxisID);
-
-  int is_scalar = FALSE;
-  if ( dimlen == 1 )
+  if ( CDI_netcdf_lazy_grid_load )
     {
-      is_scalar = zaxisInqScalar(zaxisID);
-      if ( !is_scalar && CDI_cmor_mode )
-        {
-          is_scalar = TRUE;
-          zaxisDefScalar(zaxisID);
-        }
+      cellBoundsGet->datasetNCId = ncvar->ncid;
+      cellBoundsGet->varNCId  = ncvar->bounds;
+      *gridbounds = cdfPendingLoad;
     }
-
-  int ndims = 1;
-  if ( is_scalar ) ndims = 0;
-
-  if ( dimlen == 1 )
-    switch (type)
-      {
-      case ZAXIS_SURFACE:
-      case ZAXIS_CLOUD_BASE:
-      case ZAXIS_CLOUD_TOP:
-      case ZAXIS_ISOTHERM_ZERO:
-      case ZAXIS_TOA:
-      case ZAXIS_SEA_BOTTOM:
-      case ZAXIS_ATMOSPHERE:
-      case ZAXIS_MEANSEA:
-      case ZAXIS_LAKE_BOTTOM:
-      case ZAXIS_SEDIMENT_BOTTOM:
-      case ZAXIS_SEDIMENT_BOTTOM_TA:
-      case ZAXIS_SEDIMENT_BOTTOM_TW:
-      case ZAXIS_MIX_LAYER:
-        return;
-      }
-
-  zaxisInqName(zaxisID, axisname);
-
-  if ( dimID == UNDEFID )
+  else
     {
-      checkZaxisName(axisname, fileID, vlistID, zaxisID, nzaxis);
-
-      char dimname[CDI_MAX_NAME+3];
-      dimname[0] = 0;
-      //cdiZaxisInqString(zaxisID, CDI_ZAXIS_DIMNAME, CDI_MAX_NAME, dimname);
-      if ( dimname[0] == 0 ) strcpy(dimname, axisname);
-
-      if ( type == ZAXIS_REFERENCE ) cdfDefZaxisUUID(streamptr, zaxisID);
-
-      if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
-        {
-          cdf_def_zaxis_hybrid(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, &dimID, axisname);
-        }
-      else
-        {
-          dimID = checkDimName(fileID, dimlen, dimname);
-
-          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-          if ( ndims && dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
-
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
-
-          cdfPutGridStdAtts(fileID, ncvarid, zaxisID, &gridInqsZ);
-
-          {
-            int positive = zaxisInqPositive(zaxisID);
-            static const char positive_up[] = "up",
-              positive_down[] = "down";
-            static const struct attTxtTab tab[2] = {
-              { positive_up, sizeof (positive_up) - 1 },
-              { positive_down, sizeof (positive_down) - 1 },
-            };
-            if ( positive == POSITIVE_UP || positive == POSITIVE_DOWN )
-              {
-                size_t select = positive == POSITIVE_DOWN;
-                cdf_put_att_text(fileID, ncvarid, "positive",
-                                 tab[select].txtLen, tab[select].txt);
-              }
-          }
-          cdf_put_att_text(fileID, ncvarid, "axis", 1, "Z");
-
-	  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-            {
-              size_t nvertex = 2;
-	      if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
-		cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
-
-	      if ( nvdimID != UNDEFID )
-		{
-                  size_t axisnameLen = strlen(axisname);
-                  axisname[axisnameLen] = '_';
-                  memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
-		  dimIDs[0] = dimID;
-		  dimIDs[ndims] = nvdimID;
-		  cdf_def_var(fileID, axisname, (nc_type) xtype, ndims+1, dimIDs, &ncbvarid);
-		  cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
-		}
-	    }
-
-          cdf_enddef(fileID);
-          streamptr->ncmode = 2;
-
-          cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
-
-          if ( ncbvarid != UNDEFID )
-	    {
-              double lbounds[dimlen], ubounds[dimlen], zbounds[2*dimlen];
-	      zaxisInqLbounds(zaxisID, lbounds);
-	      zaxisInqUbounds(zaxisID, ubounds);
-	      for ( size_t i = 0; i < dimlen; ++i )
-		{
-		  zbounds[2*i  ] = lbounds[i];
-		  zbounds[2*i+1] = ubounds[i];
-		}
-
-	      cdf_put_var_double(fileID, ncbvarid, zbounds);
-	    }
+      *gridbounds = (double*) Malloc(size*sizeof(double));
+      cdf_get_var_double(ncvar->ncid, ncvar->bounds, *gridbounds);
+    }
+}
 
-          if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
-        }
+static
+void cdf_load_cellarea(size_t size, ncvar_t *ncvar, double **gridarea, struct cdfLazyGridIds *cellAreaGet)
+{
+  if ( CDI_netcdf_lazy_grid_load )
+    {
+      cellAreaGet->datasetNCId = ncvar->ncid;
+      cellAreaGet->varNCId = ncvar->cellarea;
+      *gridarea = cdfPendingLoad;
+    }
+  else
+    {
+      *gridarea = (double*) Malloc(size*sizeof(double));
+      cdf_get_var_double(ncvar->ncid, ncvar->cellarea, *gridarea);
     }
-
-  if ( dimID != UNDEFID )
-    streamptr->zaxisID[zaxisindex] = dimID;
 }
 
 static
-void cdfDefPole(stream_t *streamptr, int gridID)
+void cdf_copy_axis_attr(ncvar_t *ncvar, struct gridaxis_t *gridaxis)
 {
-  int ncvarid = UNDEFID;
-  static const char varname[] = "rotated_pole";
-  static const char mapname[] = "rotated_latitude_longitude";
-
-  int fileID  = streamptr->fileID;
+  strcpy(gridaxis->name, ncvar->name);
+  strcpy(gridaxis->longname, ncvar->longname);
+  strcpy(gridaxis->units, ncvar->units);
+  if ( gridaxis->cvals )
+    gridaxis->stdname = ncvar->stdname;
+}
 
-  double ypole = gridInqYpole(gridID);
-  double xpole = gridInqXpole(gridID);
-  double angle = gridInqAngle(gridID);
+static
+int cdf_get_xydimid(int ndims, int *dimids, int *dimtype, int *xdimid, int *ydimid)
+{
+  int nxdims = 0, nydims = 0;
+  int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
 
-  cdf_redef(fileID);
+  for ( int i = 0; i < ndims; i++ )
+    {
+      if ( dimtype[i] == X_AXIS && nxdims < 2 )
+        {
+          xdimids[nxdims] = dimids[i];
+          nxdims++;
+        }
+      else if ( dimtype[i] == Y_AXIS && nydims < 2 )
+        {
+          ydimids[nydims] = dimids[i];
+          nydims++;
+        }
+    }
 
-  int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-  if ( ncerrcode == NC_NOERR )
+  if ( nxdims == 2 )
     {
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping_name", sizeof (mapname) - 1, mapname);
-      cdf_put_att_double(fileID, ncvarid, "grid_north_pole_latitude", NC_DOUBLE, 1, &ypole);
-      cdf_put_att_double(fileID, ncvarid, "grid_north_pole_longitude", NC_DOUBLE, 1, &xpole);
-      if ( IS_NOT_EQUAL(angle, 0) )
-        cdf_put_att_double(fileID, ncvarid, "north_pole_grid_longitude", NC_DOUBLE, 1, &angle);
+      *xdimid = xdimids[1];
+      *ydimid = xdimids[0];
+    }
+  else if ( nydims == 2 )
+    {
+      *xdimid = ydimids[1];
+      *ydimid = ydimids[0];
+    }
+  else
+    {
+      *xdimid = xdimids[0];
+      *ydimid = ydimids[0];
     }
 
-  cdf_enddef(fileID);
+  return nydims;
 }
 
+static
+void cdf_check_gridtype(int *gridtype, bool islon, bool islat, size_t xsize, size_t ysize, grid_t *grid)
+{
+  if ( islat && (islon || xsize == 0) )
+    {
+      double yinc = 0;
+      if ( islon && ysize > 1 )
+        {
+          yinc = fabs(grid->y.vals[0] - grid->y.vals[1]);
+          for ( size_t i = 2; i < ysize; i++ )
+            if ( (fabs(grid->y.vals[i-1] - grid->y.vals[i]) - yinc) > (yinc/1000) )
+              {
+                yinc = 0;
+                break;
+              }
+        }
+      if ( ysize < 10000 && isGaussGrid(ysize, yinc, grid->y.vals) )
+        {
+          *gridtype = GRID_GAUSSIAN;
+          grid->np = (int)(ysize/2);
+        }
+      else
+        *gridtype = GRID_LONLAT;
+    }
+  else if ( islon && !islat && ysize == 0 )
+    {
+      *gridtype = GRID_LONLAT;
+    }
+  else
+    *gridtype = GRID_GENERIC;
+}
 
 static
-void cdfDefMapping(stream_t *streamptr, int gridID)
+bool cdf_read_xcoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncvar_t *ncvar, int xvarid, ncvar_t *axisvar,
+                     size_t *xsize, size_t ysize, int ntdims, size_t *start, size_t *count, bool *islon)
 {
-  int ncvarid = UNDEFID;
-  int fileID  = streamptr->fileID;
+  grid_t *grid = &lazyGrid->base;
+  bool skipvar = true;
+  *islon = axisvar->islon;
+  int ndims = axisvar->ndims;
+  size_t size = 0;
+  int datatype = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned);
 
-  if ( gridInqType(gridID) == GRID_SINUSOIDAL )
+  if ( (ndims - ntdims) == 2 )
     {
-      static const char varname[] = "sinusoidal";
-      static const char mapname[] = "sinusoidal";
-
-      cdf_redef(fileID);
+      /* Check size of 2 dimensional coordinate variables */
+      int dimid = axisvar->dimids[ndims-2];
+      size_t dimsize1 = ncdims[dimid].len;
+      dimid = axisvar->dimids[ndims-1];
+      size_t dimsize2 = ncdims[dimid].len;
 
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
+      if ( datatype == CDI_DATATYPE_UINT8 )
         {
-          cdf_put_att_text(fileID, ncvarid, "grid_mapping_name", strlen(mapname), mapname);
-          /*
-          cdf_put_att_double(fileID, ncvarid, "grid_north_pole_latitude", NC_DOUBLE, 1, &ypole);
-          cdf_put_att_double(fileID, ncvarid, "grid_north_pole_longitude", NC_DOUBLE, 1, &xpole);
-          */
+          ncvar->gridtype = GRID_CHARXY;
+          size = dimsize1*dimsize2;
+          skipvar = dimsize1 != *xsize;
+        }
+      else
+        {
+          ncvar->gridtype = GRID_CURVILINEAR;
+          size = (*xsize)*ysize;
+          skipvar = dimsize1*dimsize2 != size;
         }
+    }
+  else if ( (ndims - ntdims) == 1 )
+    {
+      size = *xsize;
+      /* Check size of 1 dimensional coordinate variables */
+      int dimid = axisvar->dimids[ndims-1];
+      size_t dimsize = ncdims[dimid].len;
+      skipvar = dimsize != size;
+    }
+  else if ( ndims == 0 && *xsize == 0 )
+    {
+      size = *xsize = 1;
+      skipvar = false;
+    }
 
-      cdf_enddef(fileID);
+  if ( skipvar )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
     }
-  else if ( gridInqType(gridID) == GRID_LAEA )
+
+  if ( datatype != -1 )  grid->datatype = datatype;
+
+  if ( datatype == CDI_DATATYPE_UINT8 && !CDI_netcdf_lazy_grid_load )
     {
-      static const char varname[] = "laea";
-      static const char mapname[] = "lambert_azimuthal_equal_area";
+      cdf_load_cvals(size, xvarid, axisvar, &grid->x.cvals, *xsize);
+      grid->x.clength = size / (*xsize) ;
+    }
+  else
+    cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count);
 
-      cdf_redef(fileID);
+  cdf_copy_axis_attr(axisvar, &grid->x);
 
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          double a, lon_0, lat_0;
+  return false;
+}
+
+static
+bool cdf_read_ycoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncvar_t *ncvar, int yvarid, ncvar_t *axisvar,
+                     size_t xsize, size_t *ysize, int ntdims, size_t *start, size_t *count, bool *islat)
+{
+  grid_t *grid = &lazyGrid->base;
+  bool skipvar = true;
+  *islat = axisvar->islat;
+  int ndims = axisvar->ndims;
+  size_t size = 0;
+  int datatype = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned);
 
-          gridInqLaea(gridID, &a, &lon_0, &lat_0);
+  if ( (ndims - ntdims) == 2 )
+    {
+      /* Check size of 2 dimensional coordinate variables */
+      int dimid = axisvar->dimids[ndims-2];
+      size_t dimsize1 = ncdims[dimid].len;
+      dimid = axisvar->dimids[ndims-1];
+      size_t dimsize2 = ncdims[dimid].len;
 
-          cdf_put_att_text(fileID, ncvarid, "grid_mapping_name", strlen(mapname), mapname);
-          cdf_put_att_double(fileID, ncvarid, "earth_radius", NC_DOUBLE, 1, &a);
-          cdf_put_att_double(fileID, ncvarid, "longitude_of_projection_origin", NC_DOUBLE, 1, &lon_0);
-          cdf_put_att_double(fileID, ncvarid, "latitude_of_projection_origin", NC_DOUBLE, 1, &lat_0);
+      if ( datatype == CDI_DATATYPE_UINT8 )
+        {
+          ncvar->gridtype = GRID_CHARXY;
+          size = dimsize1*dimsize2;
+          skipvar = dimsize1 != *ysize;
         }
+      else
+        {
+          ncvar->gridtype = GRID_CURVILINEAR;
+          size = xsize*(*ysize);
+          skipvar = dimsize1*dimsize2 != size;
+        }
+    }
+  else if ( (ndims - ntdims) == 1 )
+    {
+      if ( *ysize == 0 ) size = xsize;
+      else               size = *ysize;
 
-      cdf_enddef(fileID);
+      int dimid = axisvar->dimids[ndims-1];
+      size_t dimsize = ncdims[dimid].len;
+      skipvar = dimsize != size;
     }
-  else if ( gridInqType(gridID) == GRID_LCC2 )
+  else if ( ndims == 0 && *ysize == 0 )
     {
-      static const char varname[] = "Lambert_Conformal";
-      static const char mapname[] = "lambert_conformal_conic";
+      size = *ysize = 1;
+      skipvar = false;
+    }
 
-      cdf_redef(fileID);
+  if ( skipvar )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
+    }
 
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          double radius, lon_0, lat_0, lat_1, lat_2;
+  if ( datatype != -1 )  grid->datatype = datatype;
 
-          gridInqLcc2(gridID, &radius, &lon_0, &lat_0, &lat_1, &lat_2);
+  if ( datatype == CDI_DATATYPE_UINT8 && !CDI_netcdf_lazy_grid_load )
+    {
+      cdf_load_cvals(size, yvarid, axisvar, &grid->y.cvals, *ysize);
+      grid->y.clength = size / (*ysize) ;
+    }
+  else
+    cdf_load_vals(size, ndims, yvarid, axisvar, &grid->y.vals, &lazyGrid->yValsGet, ntdims, start, count);
 
-          cdf_put_att_text(fileID, ncvarid, "grid_mapping_name", strlen(mapname), mapname);
-          if ( radius > 0 )
-            cdf_put_att_double(fileID, ncvarid, "earth_radius", NC_DOUBLE, 1, &radius);
-          cdf_put_att_double(fileID, ncvarid, "longitude_of_central_meridian", NC_DOUBLE, 1, &lon_0);
-          cdf_put_att_double(fileID, ncvarid, "latitude_of_projection_origin", NC_DOUBLE, 1, &lat_0);
-          if ( IS_EQUAL(lat_1, lat_2) )
-            cdf_put_att_double(fileID, ncvarid, "standard_parallel", NC_DOUBLE, 1, &lat_1);
-          else
-            {
-              double lat_1_2[2];
-              lat_1_2[0] = lat_1;
-              lat_1_2[1] = lat_2;
-              cdf_put_att_double(fileID, ncvarid, "standard_parallel", NC_DOUBLE, 2, lat_1_2);
-            }
-        }
+  cdf_copy_axis_attr(axisvar, &grid->y);
 
-      cdf_enddef(fileID);
-    }
+  return false;
 }
 
-
 static
-void cdfDefGrid(stream_t *streamptr, int gridID)
+bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar, ncvar_t *ncvars, ncdim_t *ncdims,
+                          int timedimid, int xvarid, int yvarid, size_t xsize, size_t ysize, int *vdimid)
 {
-  int vlistID = streamptr->vlistID;
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  if ( streamptr->xdimID[gridindex] != UNDEFID ) return;
-
-  int gridtype = gridInqType(gridID);
-  int size     = gridInqSize(gridID);
+  grid_t *grid = &lazyGrid->base;
+  size_t size = 0;
 
-  if ( CDI_Debug )
-    Message("gridtype = %d  size = %d", gridtype, size);
+  grid->datatype = CDI_DATATYPE_FLT64;
 
-  if ( gridtype == GRID_GAUSSIAN ||
-       gridtype == GRID_LONLAT   ||
-       gridtype == GRID_GENERIC )
+  if ( ncvar->gridtype == GRID_TRAJECTORY )
     {
-      if ( gridtype == GRID_GENERIC )
+      if ( ncvar->xvarid == CDI_UNDEFID ) Error("Longitude coordinate undefined for %s!", ncvar->name);
+      if ( ncvar->yvarid == CDI_UNDEFID ) Error("Latitude coordinate undefined for %s!", ncvar->name);
+    }
+  else
+    {
+      static bool ltwarn = true;
+      size_t start[3], count[3];
+      int ntdims = 0;
+
+      if ( xvarid != CDI_UNDEFID && yvarid != CDI_UNDEFID )
         {
-          if ( size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0 )
+          int ndims = ncvars[xvarid].ndims;
+          if ( ndims != ncvars[yvarid].ndims && !ncvars[xvarid].isc && !ncvars[yvarid].isc )
             {
-              /* no grid information */
+              Warning("Inconsistent grid structure for variable %s!", ncvar->name);
+              ncvar->xvarid = xvarid = CDI_UNDEFID;
+              ncvar->yvarid = yvarid = CDI_UNDEFID;
             }
-          else
+          if ( ndims > 1 )
             {
-              int lx = 0, ly = 0;
-              if ( gridInqXsize(gridID) > 0 /*&& gridInqXvals(gridID, NULL) > 0*/ )
+              if ( ndims <= 3 )
                 {
-                  cdfDefXaxis(streamptr, gridID, 1);
-                  lx = 1;
+                  if ( ncvars[xvarid].dimids[0] == timedimid && ncvars[yvarid].dimids[0] == timedimid )
+                    {
+                      size_t ntsteps = 0;
+                      cdf_inq_dimlen(ncvar->ncid, timedimid, &ntsteps);
+                      if ( ltwarn && ntsteps > 1 ) Warning("Time varying grids unsupported, using grid at time step 1!");
+                      ltwarn = false;
+                      ntdims = 1;
+                      start[0] = start[1] = start[2] = 0;
+                      count[0] = 1; count[1] = ysize; count[ndims-1] = xsize;
+                    }
                 }
-
-              if ( gridInqYsize(gridID) > 0 /*&& gridInqYvals(gridID, NULL) > 0*/ )
+              else
                 {
-                  cdfDefYaxis(streamptr, gridID, 1);
-                  ly = 1;
+                  Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvar->name);
+                  ncvar->xvarid = xvarid = CDI_UNDEFID;
+                  ncvar->yvarid = yvarid = CDI_UNDEFID;
                 }
-
-              if ( lx == 0 && ly == 0 ) cdfDefGdim(streamptr, gridID);
             }
         }
-      else
+
+      if ( xvarid != CDI_UNDEFID )
         {
-          int ndims = 1;
-          if ( gridtype == GRID_LONLAT && size == 1 && gridInqHasDims(gridID) == FALSE )
-            ndims = 0;
+          if ( (ncvars[xvarid].ndims - ntdims) > 2 )
+            {
+              Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[xvarid].name, ncvars[xvarid].ndims);
+              //ncvar->xvarid = CDI_UNDEFID;
+              xvarid = CDI_UNDEFID;
+            }
+        }
 
-          if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, ndims);
-          if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, ndims);
+      if ( yvarid != CDI_UNDEFID )
+        {
+          if ( (ncvars[yvarid].ndims - ntdims) > 2 )
+            {
+              Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[yvarid].name, ncvars[yvarid].ndims);
+              //ncvar->yvarid = CDI_UNDEFID;
+              yvarid = CDI_UNDEFID;
+            }
         }
 
-      if ( gridIsRotated(gridID) ) cdfDefPole(streamptr, gridID);
+      bool islon = false, islat = false;
+
+      if ( xvarid != CDI_UNDEFID )
+        if ( cdf_read_xcoord(lazyGrid, ncdims, ncvar, xvarid, &ncvars[xvarid],
+                             &xsize, ysize, ntdims, start, count, &islon) )
+          return true;
+
+      if ( yvarid != CDI_UNDEFID )
+        if ( cdf_read_ycoord(lazyGrid, ncdims, ncvar, yvarid, &ncvars[yvarid],
+                             xsize, &ysize, ntdims, start, count, &islat) )
+          return true;
+
+      if      ( ysize == 0 ) size = xsize;
+      else if ( xsize == 0 ) size = ysize;
+      else if ( ncvar->gridtype == GRID_UNSTRUCTURED ) size = xsize;
+      else                         size = xsize*ysize;
+
+      if ( ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC )
+        cdf_check_gridtype(&ncvar->gridtype, islon, islat, xsize, ysize, grid);
     }
-  else if ( gridtype == GRID_CURVILINEAR )
+
+  int gridtype = grid->type;
+  if ( gridtype != GRID_PROJECTION ) gridtype = ncvar->gridtype;
+  else if ( gridtype == GRID_PROJECTION && ncvar->gridtype == GRID_LONLAT )
     {
-      cdfDefCurvilinear(streamptr, gridID);
+      int gmapvarid = ncvar->gmapid;
+      if ( gmapvarid != CDI_UNDEFID && cdfCheckAttText(ncvar->ncid, gmapvarid, "grid_mapping_name") )
+        {
+          char attstring[CDI_MAX_NAME];
+          cdfGetAttText(ncvar->ncid, gmapvarid, "grid_mapping_name", CDI_MAX_NAME, attstring);
+          if ( strcmp(attstring, "latitude_longitude") == 0 ) gridtype = ncvar->gridtype;
+        }
     }
-  else if ( gridtype == GRID_UNSTRUCTURED )
+
+  switch (gridtype)
     {
-      cdfDefUnstructured(streamptr, gridID);
+    case GRID_GENERIC:
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_UNSTRUCTURED:
+    case GRID_CURVILINEAR:
+    case GRID_PROJECTION:
+      {
+        grid->size  = size;
+        grid->x.size = xsize;
+        grid->y.size = ysize;
+        if ( xvarid != CDI_UNDEFID )
+          {
+            grid->x.flag = 1;
+            int bvarid = ncvars[xvarid].bounds;
+            if ( bvarid != CDI_UNDEFID )
+              {
+                int nbdims = ncvars[bvarid].ndims;
+                if ( nbdims == 2 || nbdims == 3 )
+                  {
+                    *vdimid = ncvars[bvarid].dimids[nbdims-1];
+                    grid->nvertex = (int)ncdims[*vdimid].len;
+                    cdf_load_bounds(size*(size_t)grid->nvertex, &ncvars[xvarid], &grid->x.bounds, &lazyGrid->xBoundsGet);
+                  }
+              }
+          }
+        if ( yvarid != CDI_UNDEFID )
+          {
+            grid->y.flag = 1;
+            int bvarid = ncvars[yvarid].bounds;
+            if ( bvarid != CDI_UNDEFID )
+              {
+                int nbdims = ncvars[bvarid].ndims;
+                if ( nbdims == 2 || nbdims == 3 )
+                  {
+                    if ( *vdimid == CDI_UNDEFID )
+                      {
+                        *vdimid = ncvars[bvarid].dimids[nbdims-1];
+                        grid->nvertex = (int)ncdims[*vdimid].len;
+                      }
+                    cdf_load_bounds(size*(size_t)grid->nvertex, &ncvars[yvarid], &grid->y.bounds, &lazyGrid->yBoundsGet);
+                  }
+              }
+          }
+
+        if ( ncvar->cellarea != CDI_UNDEFID )
+          cdf_load_cellarea(size, ncvar, &grid->area, &lazyGrid->cellAreaGet);
+
+        break;
+      }
+    case GRID_SPECTRAL:
+      {
+        grid->size = size;
+        grid->lcomplex = 1;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_FOURIER:
+      {
+        grid->size = size;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_TRAJECTORY:
+      {
+        grid->size = 1;
+        break;
+      }
+    case GRID_CHARXY:
+      {
+        grid->size = size;
+        grid->x.size = xsize;
+        grid->y.size = ysize;
+        break;
+      }
     }
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+
+  // if ( grid->type != GRID_PROJECTION && grid->type != ncvar->gridtype )
+  if ( grid->type != gridtype )
     {
-      cdfDefRgrid(streamptr, gridID);
+      // int gridtype = ncvar->gridtype;
+      grid->type = gridtype;
+      cdiGridTypeInit(grid, gridtype, grid->size);
     }
-  else if ( gridtype == GRID_SPECTRAL )
+
+  if ( grid->size == 0 )
     {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefSP(streamptr, gridID);
+      int ndims = ncvar->ndims;
+      int *dimtype = ncvar->dimtype;
+      if ( ndims == 0 ||
+           (ndims == 1 && dimtype[0] == T_AXIS) ||
+           (ndims == 1 && dimtype[0] == Z_AXIS) ||
+           (ndims == 2 && dimtype[0] == T_AXIS && dimtype[1] == Z_AXIS) )
+        {
+          grid->type  = GRID_GENERIC;
+          grid->size  = 1;
+          grid->x.size = 0;
+          grid->y.size = 0;
+        }
+      else
+        {
+          Warning("Unsupported grid, skipped variable %s!", ncvar->name);
+          ncvar->isvar = -1;
+          return true;
+        }
     }
-  else if ( gridtype == GRID_FOURIER )
+
+  return false;
+}
+
+static
+bool cdf_set_unstructured_par(ncvar_t *ncvar, grid_t *grid, int *xdimid, int *ydimid, int number_of_grid_used, unsigned char *uuidOfHGrid)
+{
+  int ndims = ncvar->ndims;
+  int *dimtype = ncvar->dimtype;
+
+  int zdimid = CDI_UNDEFID;
+  int xdimidx = CDI_UNDEFID, ydimidx = CDI_UNDEFID;
+
+  for ( int i = 0; i < ndims; i++ )
     {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefFC(streamptr, gridID);
+      if      ( dimtype[i] == X_AXIS ) xdimidx = i;
+      else if ( dimtype[i] == Y_AXIS ) ydimidx = i;
+      else if ( dimtype[i] == Z_AXIS ) zdimid = ncvar->dimids[i];
     }
-  else if ( gridtype == GRID_TRAJECTORY )
+
+  if ( *xdimid != CDI_UNDEFID && *ydimid != CDI_UNDEFID && zdimid == CDI_UNDEFID )
     {
-      cdfDefTrajLon(streamptr, gridID);
-      cdfDefTrajLat(streamptr, gridID);
+      if ( grid->x.size > grid->y.size && grid->y.size < 1000 )
+        {
+          dimtype[ydimidx] = Z_AXIS;
+          *ydimid = CDI_UNDEFID;
+          grid->size  = grid->x.size;
+          grid->y.size = 0;
+        }
+      else if ( grid->y.size > grid->x.size && grid->x.size < 1000 )
+        {
+          dimtype[xdimidx] = Z_AXIS;
+          *xdimid = *ydimid;
+          *ydimid = CDI_UNDEFID;
+          grid->size  = grid->y.size;
+          grid->x.size = grid->y.size;
+          grid->y.size = 0;
+        }
     }
-  else if ( gridtype == GRID_SINUSOIDAL || gridtype == GRID_LAEA || gridtype == GRID_LCC2 )
-    {
-      cdfDefXaxis(streamptr, gridID, 1);
-      cdfDefYaxis(streamptr, gridID, 1);
 
-      cdfDefMapping(streamptr, gridID);
+  if ( grid->size != grid->x.size )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
     }
-  /*
-  else if ( gridtype == GRID_LCC )
+
+  if ( number_of_grid_used != CDI_UNDEFID ) grid->number = number_of_grid_used;
+  if ( ncvar->position > 0 ) grid->position = ncvar->position;
+  if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
+
+  return false;
+}
+
+static
+void cdf_read_mapping_atts(int ncid, int gmapvarid, int projID, const char *varname)
+{
+  if ( cdfCheckAttText(ncid, gmapvarid, "grid_mapping_name") )
     {
-      cdfDefLcc(streamptr, gridID);
+      char attstring[CDI_MAX_NAME];
+      cdfGetAttText(ncid, gmapvarid, "grid_mapping_name", CDI_MAX_NAME, attstring);
+      cdiGridDefKeyStr(projID, CDI_KEY_MAPNAME, (int)(strlen(attstring)+1), attstring);
     }
-  */
   else
     {
-      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+      Warning("Text attribute %s:grid_mapping_name missing!", varname);
     }
+
+  int nvatts;
+  cdf_inq_varnatts(ncid, gmapvarid, &nvatts);
+  for ( int attnum = 0; attnum < nvatts; ++attnum )
+    cdf_set_cdi_attr(ncid, gmapvarid, attnum, projID, CDI_GLOBAL);
 }
 
 static
-void scale_add(size_t size, double *data, double addoffset, double scalefactor)
+void cdf_set_grid_to_similar_vars(ncvar_t *ncvar1, ncvar_t *ncvar2, int gridtype, int xdimid, int ydimid)
 {
-  int laddoffset;
-  int lscalefactor;
+  if ( ncvar2->isvar == TRUE && ncvar2->gridID == CDI_UNDEFID )
+    {
+      int xdimid2 = CDI_UNDEFID, ydimid2 = CDI_UNDEFID, zdimid2 = CDI_UNDEFID;
+      int xdimidx = CDI_UNDEFID, ydimidx = CDI_UNDEFID;
+      int ndims2 = ncvar2->ndims;
+
+      int *dimtype2 = ncvar2->dimtype;
+      int *dimids2 = ncvar2->dimids;
+      for ( int i = 0; i < ndims2; i++ )
+        {
+          if      ( dimtype2[i] == X_AXIS ) { xdimid2 = dimids2[i]; xdimidx = i; }
+          else if ( dimtype2[i] == Y_AXIS ) { ydimid2 = dimids2[i]; ydimidx = i; }
+          else if ( dimtype2[i] == Z_AXIS ) { zdimid2 = dimids2[i]; }
+        }
 
-  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+      if ( ncvar2->gridtype == CDI_UNDEFID && gridtype == GRID_UNSTRUCTURED )
+        {
+          if ( xdimid == xdimid2 && ydimid2 != CDI_UNDEFID && zdimid2 == CDI_UNDEFID )
+            {
+              ncvar2->dimtype[ydimidx] = Z_AXIS;
+              ydimid2 = CDI_UNDEFID;
+            }
 
-  if ( laddoffset || lscalefactor )
-    {
-      for (size_t i = 0; i < size; ++i )
+          if ( xdimid == ydimid2 && xdimid2 != CDI_UNDEFID && zdimid2 == CDI_UNDEFID )
+            {
+              ncvar2->dimtype[xdimidx] = Z_AXIS;
+              xdimid2 = ydimid2;
+              ydimid2 = CDI_UNDEFID;
+            }
+        }
+
+      if ( xdimid == xdimid2 && (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == CDI_UNDEFID)) )
         {
-          if ( lscalefactor ) data[i] *= scalefactor;
-          if ( laddoffset )   data[i] += addoffset;
+          bool same_grid = ncvar1->xvarid == ncvar2->xvarid
+                        && ncvar1->yvarid == ncvar2->yvarid
+                        && ncvar1->position == ncvar2->position;
+          /*
+            if ( xvarid != -1 && ncvar2->xvarid != CDI_UNDEFID &&
+            xvarid != ncvar2->xvarid ) same_grid = false;
+
+            if ( yvarid != -1 && ncvar2->yvarid != CDI_UNDEFID &&
+            yvarid != ncvar2->yvarid ) same_grid = false;
+          */
+
+          if ( same_grid )
+            {
+              if ( CDI_Debug ) Message("Same gridID %d %s", ncvar1->gridID, ncvar2->name);
+              ncvar2->gridID = ncvar1->gridID;
+              ncvar2->chunktype = ncvar1->chunktype;
+            }
         }
     }
 }
 
 static
-void cdfCreateRecords(stream_t *streamptr, int tsID)
+int cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
+                         int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
 {
-  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
+  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
+    {
+      ncvar_t *ncvar = &ncvars[ncvarid];
+      if ( ncvar->isvar && ncvar->gridID == CDI_UNDEFID )
+	{
+          int ndims = ncvar->ndims;
+          int *dimtype = ncvar->dimtype;
+          int vdimid = CDI_UNDEFID;
+          struct addIfNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 },
+                             gridAdded = { .Id = CDI_UNDEFID, .isNew = 0 };
+	  int xdimid = CDI_UNDEFID, ydimid = CDI_UNDEFID;
+          int nydims = cdf_get_xydimid(ndims, ncvar->dimids, dimtype, &xdimid, &ydimid);
+
+          int xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
+          int yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
+          int xvarid = (ncvar->xvarid != CDI_UNDEFID) ? ncvar->xvarid : xaxisid;
+          int yvarid = (ncvar->yvarid != CDI_UNDEFID) ? ncvar->yvarid : yaxisid;
+
+	  size_t xsize = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].len : 0;
+	  size_t ysize = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].len : 0;
+
+	  if ( ydimid == CDI_UNDEFID && yvarid != CDI_UNDEFID )
+	    {
+	      if ( ncvars[yvarid].ndims == 1 )
+		{
+		  ydimid = ncvars[yvarid].dimids[0];
+		  ysize  = ncdims[ydimid].len;
+		}
+	    }
 
-  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
+          int gmapvarid = ncvar->gmapid;
+          bool lproj = gmapvarid != CDI_UNDEFID;
 
-  int vlistID  = streamptr->vlistID;
+          if ( !lproj && xaxisid != CDI_UNDEFID && xaxisid != xvarid && yaxisid != CDI_UNDEFID && yaxisid != yvarid )
+            {
+              lproj = true;
+            }
 
-  tsteps_t* sourceTstep = streamptr->tsteps;
-  tsteps_t* destTstep = sourceTstep + tsID;
+          bool lgrid = !(lproj && ncvar->xvarid == CDI_UNDEFID);
 
-  int nvars = vlistNvars(vlistID);
-  int nrecs = vlistNrecs(vlistID);
+          bool lunstructured = xdimid != CDI_UNDEFID && xdimid == ydimid && nydims == 0;
+	  if ( (ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC) && lunstructured )
+            ncvar->gridtype = GRID_UNSTRUCTURED;
 
-  if ( nrecs <= 0 ) return;
+          struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
 
-  if ( tsID == 0 )
-    {
-      int nvrecs = nrecs; /* use all records at first timestep */
+          {
+            int gridtype = !lgrid ? GRID_PROJECTION : ncvar->gridtype;
+            if ( CDI_netcdf_lazy_grid_load )
+              {
+                cdfLazyGridRenew(&lazyGrid, gridtype);
+                if ( lgrid && lproj ) cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
+              }
+            else
+              {
+                cdfBaseGridRenew(&lazyGrid, gridtype);
+                if ( lgrid && lproj ) cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
+              }
+          }
+          grid_t *grid = &lazyGrid->base;
+          grid_t *proj = ( lgrid && lproj ) ? &lazyProj->base : NULL;
 
-      streamptr->nrecs += nrecs;
+          xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
+          yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs*sizeof (int));;
-      for ( int recID = 0; recID < nvrecs; recID++ ) destTstep->recIDs[recID] = recID;
 
-      record_t *records = destTstep->records;
+          if ( cdf_read_coordinates(lazyGrid, ncvar, ncvars, ncdims,
+                                    timedimid, xvarid, yvarid, xsize, ysize, &vdimid) )
+            continue;
 
-      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
-        {
-          int zaxisID = vlistInqVarZaxis(vlistID, varID);
-          int nlev    = zaxisInqSize(zaxisID);
-          for ( int levelID = 0; levelID < nlev; levelID++ )
+	  if ( number_of_grid_used != CDI_UNDEFID &&
+               (grid->type == CDI_UNDEFID || grid->type == GRID_GENERIC) &&
+               xdimid != CDI_UNDEFID && xsize > 9999 )
+            grid->type = GRID_UNSTRUCTURED;
+
+          if ( grid->type == GRID_UNSTRUCTURED )
+            if ( cdf_set_unstructured_par(ncvar, grid, &xdimid, &ydimid, number_of_grid_used, uuidOfHGrid) )
+              continue;
+
+          if ( lproj && lgrid )
             {
-              recordInitEntry(&records[recID]);
-              records[recID].varID   = (short)varID;
-              records[recID].levelID = (short)levelID;
-              recID++;
-            }
-        }
-    }
-  else if ( tsID == 1 )
-    {
-      int nvrecs = 0;
-      for ( int varID = 0; varID < nvars; varID++ )
-        {
-          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+              int dumid;
+              cdf_read_coordinates(lazyProj, ncvar, ncvars, ncdims, timedimid,
+                                   xaxisid, yaxisid, xsize, ysize, &dumid);
+	    }
+
+	  if ( CDI_Debug )
+	    {
+	      Message("grid: type = %d, size = %zu, nx = %zu, ny = %zu",
+		      grid->type, grid->size, grid->x.size, grid->y.size);
+              if ( proj )
+                Message("proj: type = %d, size = %zu, nx = %zu, ny = %zu",
+                        proj->type, proj->size, proj->x.size, proj->y.size);
+	    }
+
+
+          if ( lgrid && lproj )
             {
-              int zaxisID = vlistInqVarZaxis(vlistID, varID);
-              nvrecs += zaxisInqSize(zaxisID);
+              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 2);
+              grid->proj = projAdded.Id;
             }
-        }
 
-      streamptr->nrecs += nvrecs;
+          gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
+          ncvar->gridID = gridAdded.Id;
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+          int gridID = ncvar->gridID;
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+          if ( lproj && gmapvarid != CDI_UNDEFID )
+            {
+              int projID = lgrid ? grid->proj : gridID;
+              int ncid = ncvars[gmapvarid].ncid;
+              const char *gmapname = ncvars[gmapvarid].name;
+              cdf_read_mapping_atts(ncid, gmapvarid, projID, gmapname);
+              cdiGridDefKeyStr(projID, CDI_KEY_MAPPING, (int)(strlen(gmapname)+1), gmapname);
+              gridVerifyProj(projID);
+            }
 
-      if ( nvrecs )
-        {
-          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
-          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
+          if ( grid->type == GRID_UNSTRUCTURED && gridfile[0] != 0 )
+            gridDefReference(gridID, gridfile);
+
+          if ( ncvar->chunked ) grid_set_chunktype(grid, ncvar);
+
+	  int gridindex = vlistGridIndex(vlistID, gridID);
+          ncgrid[gridindex].gridID = gridID;
+          ncgrid[gridindex].ncIDs[CDF_DIMID_X] = xdimid;
+          ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ydimid;
+          if ( grid->type == GRID_TRAJECTORY )
             {
-              int varID = destTstep->records[recID].varID;
-              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
-                {
-                  destTstep->recIDs[vrecID++] = recID;
-                }
+              ncgrid[gridindex].ncIDs[CDF_VARID_X] = xvarid;
+              ncgrid[gridindex].ncIDs[CDF_VARID_Y] = yvarid;
             }
-        }
-    }
-  else
-    {
-      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      int nvrecs = streamptr->tsteps[1].nrecs;
+          if ( xdimid == CDI_UNDEFID && ydimid == CDI_UNDEFID && grid->size == 1 )
+            gridDefHasDims(gridID, FALSE);
 
-      streamptr->nrecs += nvrecs;
+          if ( xdimid != CDI_UNDEFID ) cdiGridDefKeyStr(gridID, CDI_KEY_XDIMNAME, (int)(strlen(ncdims[xdimid].name)+1), ncdims[xdimid].name);
+          if ( ydimid != CDI_UNDEFID ) cdiGridDefKeyStr(gridID, CDI_KEY_YDIMNAME, (int)(strlen(ncdims[ydimid].name)+1), ncdims[ydimid].name);
+          if ( vdimid != CDI_UNDEFID ) cdiGridDefKeyStr(gridID, CDI_KEY_VDIMNAME, (int)(strlen(ncdims[vdimid].name)+1), ncdims[vdimid].name);
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+	  if ( CDI_Debug ) Message("gridID %d %d %s", gridID, ncvarid, ncvar->name);
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+            cdf_set_grid_to_similar_vars(ncvar, &ncvars[ncvarid2], grid->type, xdimid, ydimid);
 
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
+          if ( gridAdded.isNew ) lazyGrid = NULL;
+          if ( projAdded.isNew ) lazyProj = NULL;
 
-      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
+          if ( lazyGrid )
+            {
+              if ( CDI_netcdf_lazy_grid_load ) cdfLazyGridDestroy(lazyGrid);
+              if ( grid ) { grid_free(grid); Free(grid); }
+            }
+
+          if ( lazyProj )
+            {
+              if ( CDI_netcdf_lazy_grid_load ) cdfLazyGridDestroy(lazyProj);
+              if ( proj ) { grid_free(proj); Free(proj); }
+            }
+	}
     }
-}
 
+  return 0;
+}
 
+/* define all input zaxes */
 static
-int cdfTimeDimID(int fileID, int ndims, int nvars)
+int cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
+                         size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid)
 {
-  for ( int dimid = 0; dimid < ndims; dimid++ )
+  char *pname, *plongname, *punits;
+  size_t vctsize = vctsize_echam;
+  double *vct = vct_echam;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      char dimname[80];
-      cdf_inq_dimname(fileID, dimid, dimname);
-      if ( memcmp(dimname, "time", 4) == 0 )
-        return dimid;
-    }
+      ncvar_t *ncvar = &ncvars[ncvarid];
+      if ( ncvar->isvar == TRUE && ncvar->zaxisID == CDI_UNDEFID )
+	{
+          bool is_scalar = false;
+	  bool with_bounds = false;
+	  int zdimid = CDI_UNDEFID;
+	  int zvarid = CDI_UNDEFID;
+	  size_t zsize = 1;
+          int psvarid = -1;
+          int p0varid = -1;
 
+          int positive = 0;
+	  int ndims = ncvar->ndims;
 
-  for ( int varid = 0; varid < nvars; varid++ )
-    {
-      int nvdims, nvatts, dimids[9];
-      cdf_inq_var(fileID, varid, NULL, NULL, &nvdims, dimids, &nvatts);
-      if ( nvdims == 1 )
-        {
-          for ( int iatt = 0; iatt < nvatts; iatt++ )
+          if ( ncvar->zvarid != -1 && ncvars[ncvar->zvarid].ndims == 0 )
             {
-              char sbuf[CDI_MAX_NAME];
-              cdf_inq_attname(fileID, varid, iatt, sbuf);
-              if ( strncmp(sbuf, "units", 5) == 0 )
+              zvarid = ncvar->zvarid;
+              is_scalar = true;
+            }
+          else
+            {
+              for ( int i = 0; i < ndims; i++ )
                 {
-                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
-                  strtolower(sbuf);
+                  if ( ncvar->dimtype[i] == Z_AXIS )
+                    zdimid = ncvar->dimids[i];
+                }
 
-                  if ( isTimeUnits(sbuf) )
-                    return dimids[0];
+              if ( zdimid != CDI_UNDEFID )
+                {
+                  // zvarid = ncdims[zdimid].ncvarid;
+                  zvarid = (ncvar->zvarid != CDI_UNDEFID) ? ncvar->zvarid : ncdims[zdimid].ncvarid;
+                  zsize  = ncdims[zdimid].len;
                 }
             }
-        }
-    }
 
-  return UNDEFID;
-}
+	  if ( CDI_Debug ) Message("nlevs = %zu", zsize);
 
-static
-void init_ncdims(long ndims, ncdim_t *ncdims)
-{
-  for ( long ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      ncdims[ncdimid].ncvarid      = UNDEFID;
-      ncdims[ncdimid].dimtype      = UNDEFID;
-      ncdims[ncdimid].len          = 0;
-      ncdims[ncdimid].name[0]      = 0;
-    }
-}
+	  double *zvar = NULL;
+          char **zcvals = NULL;
+          size_t zclength = 0;
 
-static
-void init_ncvars(long nvars, ncvar_t *ncvars)
-{
-  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
-    {
-      ncvars[ncvarid].ncid            = UNDEFID;
-      ncvars[ncvarid].ignore          = FALSE;
-      ncvars[ncvarid].isvar           = UNDEFID;
-      ncvars[ncvarid].islon           = FALSE;
-      ncvars[ncvarid].islat           = FALSE;
-      ncvars[ncvarid].islev           = FALSE;
-      ncvars[ncvarid].istime          = FALSE;
-      ncvars[ncvarid].warn            = FALSE;
-      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
-      ncvars[ncvarid].param           = UNDEFID;
-      ncvars[ncvarid].code            = UNDEFID;
-      ncvars[ncvarid].tabnum          = 0;
-      ncvars[ncvarid].calendar        = FALSE;
-      ncvars[ncvarid].climatology     = FALSE;
-      ncvars[ncvarid].bounds          = UNDEFID;
-      ncvars[ncvarid].lformula        = FALSE;
-      ncvars[ncvarid].lformulaterms   = FALSE;
-      ncvars[ncvarid].gridID          = UNDEFID;
-      ncvars[ncvarid].zaxisID         = UNDEFID;
-      ncvars[ncvarid].gridtype        = UNDEFID;
-      ncvars[ncvarid].zaxistype       = UNDEFID;
-      ncvars[ncvarid].xdim            = UNDEFID;
-      ncvars[ncvarid].ydim            = UNDEFID;
-      ncvars[ncvarid].zdim            = UNDEFID;
-      ncvars[ncvarid].xvarid          = UNDEFID;
-      ncvars[ncvarid].yvarid          = UNDEFID;
-      ncvars[ncvarid].zvarid          = UNDEFID;
-      ncvars[ncvarid].tvarid          = UNDEFID;
-      ncvars[ncvarid].psvarid         = UNDEFID;
-      ncvars[ncvarid].p0varid         = UNDEFID;
-      ncvars[ncvarid].ncoordvars      = 0;
-      for ( int i = 0; i < MAX_COORDVARS; ++i )
-        ncvars[ncvarid].coordvarids[i]  = UNDEFID;
-      ncvars[ncvarid].nauxvars      = 0;
-      for ( int i = 0; i < MAX_AUXVARS; ++i )
-        ncvars[ncvarid].auxvarids[i]  = UNDEFID;
-      ncvars[ncvarid].cellarea        = UNDEFID;
-      ncvars[ncvarid].tableID         = UNDEFID;
-      ncvars[ncvarid].xtype           = 0;
-      ncvars[ncvarid].ndims           = 0;
-      ncvars[ncvarid].gmapid          = UNDEFID;
-      ncvars[ncvarid].vctsize         = 0;
-      ncvars[ncvarid].vct             = NULL;
-      ncvars[ncvarid].truncation      = 0;
-      ncvars[ncvarid].position        = 0;
-      ncvars[ncvarid].positive        = 0;
-      ncvars[ncvarid].chunked         = 0;
-      ncvars[ncvarid].chunktype       = UNDEFID;
-      ncvars[ncvarid].defmissval      = 0;
-      ncvars[ncvarid].deffillval      = 0;
-      ncvars[ncvarid].missval         = 0;
-      ncvars[ncvarid].fillval         = 0;
-      ncvars[ncvarid].addoffset       = 0;
-      ncvars[ncvarid].scalefactor     = 1;
-      ncvars[ncvarid].name[0]         = 0;
-      ncvars[ncvarid].longname[0]     = 0;
-      ncvars[ncvarid].stdname[0]      = 0;
-      ncvars[ncvarid].units[0]        = 0;
-      ncvars[ncvarid].extra[0]        = 0;
-      ncvars[ncvarid].natts           = 0;
-      ncvars[ncvarid].atts            = NULL;
-      ncvars[ncvarid].deflate         = 0;
-      ncvars[ncvarid].lunsigned       = 0;
-      ncvars[ncvarid].lvalidrange     = 0;
-      ncvars[ncvarid].validrange[0]   = VALIDMISS;
-      ncvars[ncvarid].validrange[1]   = VALIDMISS;
-      ncvars[ncvarid].ensdata         = NULL;
-    }
-}
+	  int zaxisType = CDI_UNDEFID;
+	  if ( zvarid != CDI_UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
+	  if ( zaxisType == CDI_UNDEFID ) zaxisType = ZAXIS_GENERIC;
 
-static
-void cdfSetVar(ncvar_t *ncvars, int ncvarid, short isvar)
-{
-  if ( ncvars[ncvarid].isvar != UNDEFID &&
-       ncvars[ncvarid].isvar != isvar   &&
-       ncvars[ncvarid].warn  == FALSE )
-    {
-      if ( ! ncvars[ncvarid].ignore )
-        Warning("Inconsistent variable definition for %s!", ncvars[ncvarid].name);
+	  int zdatatype = CDI_DATATYPE_FLT64;
+	  double *restrict lbounds = NULL;
+	  double *restrict ubounds = NULL;
 
-      ncvars[ncvarid].warn = TRUE;
-      isvar = FALSE;
-    }
+	  if ( zvarid != CDI_UNDEFID )
+	    {
+	      positive  = ncvars[zvarid].positive;
+	      pname     = ncvars[zvarid].name;
+	      plongname = ncvars[zvarid].longname;
+	      punits    = ncvars[zvarid].units;
+	      if ( ncvars[zvarid].xtype == NC_FLOAT ) zdatatype = CDI_DATATYPE_FLT32;
+	      /* don't change the name !!! */
+	      /*
+	      if ( (len = strlen(pname)) > 2 )
+		if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) )
+		  pname[len-2] = 0;
+	      */
+              if ( zaxisType == ZAXIS_CHAR )
+                {
+                  if ( ncvars[zvarid].ndims == 2 )
+                    {
+                      zdatatype = CDI_DATATYPE_UINT8;
+                      zclength = ncdims[ncvars[zvarid].dimids[1]].len;
+                      cdf_load_cvals(zsize*zclength, zvarid, ncvar, &zcvals, zsize);
+                    }
+                }
 
-  ncvars[ncvarid].isvar = isvar;
-}
+              if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
+                {
+                  vct = ncvars[zvarid].vct;
+                  vctsize = ncvars[zvarid].vctsize;
 
-static
-void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
-{
-  if ( ncvars[ncvarid].dimtype[dimid] != UNDEFID &&
-       ncvars[ncvarid].dimtype[dimid] != dimtype )
-    {
-      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
-              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
+                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
+                  if ( ncvars[zvarid].p0varid != -1 ) p0varid = ncvars[zvarid].p0varid;
+                }
+
+              if ( zaxisType != ZAXIS_CHAR )
+                {
+                  zvar = (double*) Malloc(zsize*sizeof(double));
+                  cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
+                }
+
+	      if ( ncvars[zvarid].bounds != CDI_UNDEFID )
+		{
+		  int nbdims = ncvars[ncvars[zvarid].bounds].ndims;
+		  if ( nbdims == 2 || is_scalar )
+		    {
+		      size_t nlevel  = is_scalar ? 1 : ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
+		      int nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1-is_scalar]].len;
+		      if ( nlevel == zsize && nvertex == 2 )
+			{
+			  with_bounds = true;
+			  lbounds = (double *) Malloc(4 * nlevel*sizeof(double));
+			  ubounds = lbounds + nlevel;
+			  double *restrict zbounds = lbounds + 2 * nlevel;
+			  cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds);
+			  for ( size_t i = 0; i < nlevel; ++i )
+			    {
+			      lbounds[i] = zbounds[i*2];
+			      ubounds[i] = zbounds[i*2+1];
+			    }
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+              pname     = (zdimid != CDI_UNDEFID) ? ncdims[zdimid].name : NULL;
+	      plongname = NULL;
+	      punits    = NULL;
+
+	      if ( zsize == 1 && zdimid == CDI_UNDEFID )
+		{
+                  zaxisType = (ncvar->zaxistype != CDI_UNDEFID) ? ncvar->zaxistype : ZAXIS_SURFACE;
+                  // if ( pname )
+                    {
+                      zvar = (double*) Malloc(sizeof(double));
+                      zvar[0] = 0;
+                    }
+                }
+	    }
+
+          if ( zsize > INT_MAX )
+            {
+              Warning("Size limit exceeded for z-axis dimension (limit=%d)!", INT_MAX);
+              return CDI_EDIMSIZE;
+            }
+
+      	  ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, (const char **)zcvals, zclength, with_bounds, lbounds, ubounds,
+                                       (int)vctsize, vct, pname, plongname, punits, zdatatype, 1, 0);
+
+          int zaxisID = ncvar->zaxisID;
+
+          if ( CDI_cmor_mode && zsize == 1 && zaxisType != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID);
+
+          if ( uuidOfVGrid[0] != 0 )
+            zaxisDefUUID(zaxisID, uuidOfVGrid);
+
+          if ( zaxisType == ZAXIS_HYBRID )
+            {
+              if ( psvarid != -1 )
+                cdiZaxisDefKeyStr(zaxisID, CDI_KEY_PSNAME, (int)(strlen(ncvars[psvarid].name)+1), ncvars[psvarid].name);
+              if ( p0varid != -1 )
+                {
+                  double px = 1;
+                  cdf_get_var_double(ncvars[p0varid].ncid, p0varid, &px);
+                  cdiZaxisDefKeyFlt(zaxisID, CDI_KEY_P0VALUE, px);
+                  cdiZaxisDefKeyStr(zaxisID, CDI_KEY_P0NAME, (int)(strlen(ncvars[p0varid].name)+1), ncvars[p0varid].name);
+                }
+            }
+
+          if ( positive > 0 ) zaxisDefPositive(zaxisID, positive);
+          if ( is_scalar ) zaxisDefScalar(zaxisID);
+
+          if ( zdimid != CDI_UNDEFID )
+            cdiZaxisDefKeyStr(zaxisID, CDI_KEY_DIMNAME, (int)(strlen(ncdims[zdimid].name)+1), ncdims[zdimid].name);
+          /*
+          if ( vdimid != -1 )
+            cdiZaxisDefKeyStr(zaxisID, CDI_KEY_VDIMNAME, strlen(ncdims[vdimid].name)+1, ncdims[vdimid].name);
+          */
+	  if ( zvar    ) Free(zvar);
+	  if ( zcvals  )
+            {
+              for ( size_t i = 0; i < zsize; i++ )
+                Free(zcvals[i]);
+              Free(zcvals);
+            }
+	  if ( lbounds ) Free(lbounds);
+
+          if ( zvarid != CDI_UNDEFID )
+            {
+              int ncid = ncvars[zvarid].ncid;
+              int nvatts = ncvars[zvarid].natts;
+              for ( int iatt = 0; iatt < nvatts; ++iatt )
+                {
+                  int attnum = ncvars[zvarid].atts[iatt];
+                  cdf_set_cdi_attr(ncid, zvarid, attnum, zaxisID, CDI_GLOBAL);
+                }
+            }
+
+          int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+	  streamptr->zaxisID[zaxisindex] = zdimid;
+
+	  if ( CDI_Debug )
+	    Message("zaxisID %d %d %s", zaxisID, ncvarid, ncvar->name);
+
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].zaxisID == CDI_UNDEFID /*&& ncvars[ncvarid2].zaxistype == CDI_UNDEFID*/ )
+	      {
+                int zvarid2 = CDI_UNDEFID;
+                if ( ncvars[ncvarid2].zvarid != CDI_UNDEFID && ncvars[ncvars[ncvarid2].zvarid].ndims == 0 )
+                  zvarid2 = ncvars[ncvarid2].zvarid;
+
+		int zdimid2 = CDI_UNDEFID;
+		ndims = ncvars[ncvarid2].ndims;
+		for ( int i = 0; i < ndims; i++ )
+		  {
+		    if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
+		      zdimid2 = ncvars[ncvarid2].dimids[i];
+		  }
+
+		if ( zdimid == zdimid2 /* && zvarid == zvarid2 */)
+		  {
+                    if ( (zdimid != CDI_UNDEFID && ncvars[ncvarid2].zaxistype == CDI_UNDEFID) ||
+                         (zdimid == CDI_UNDEFID && zvarid != CDI_UNDEFID && zvarid == zvarid2) ||
+                         (zdimid == CDI_UNDEFID && zaxisType == ncvars[ncvarid2].zaxistype) ||
+                         (zdimid == CDI_UNDEFID && zvarid2 == CDI_UNDEFID && ncvars[ncvarid2].zaxistype == CDI_UNDEFID) )
+                      {
+                        if ( CDI_Debug )
+                          Message("zaxisID %d %d %s", zaxisID, ncvarid2, ncvars[ncvarid2].name);
+                        ncvars[ncvarid2].zaxisID = zaxisID;
+                      }
+                  }
+	      }
+	}
     }
 
-  ncvars[ncvarid].dimtype[dimid] = dimtype;
+  return 0;
 }
 
-static
-bool isLonAxis(const char *units, const char *stdname)
-{
-  bool status = false;
-  char lc_units[16];
-
-  memcpy(lc_units, units, 15);
-  lc_units[15] = 0;
-  strtolower(lc_units);
-
-  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
-        (memcmp(stdname, "grid_longitude", 14) == 0 || memcmp(stdname, "longitude", 9) == 0)) )
-    {
-      status = true;
-    }
 
-  if ( status == false &&
-       memcmp(stdname, "grid_latitude", 13) && memcmp(stdname, "latitude", 8) &&
-       memcmp(lc_units, "degree", 6) == 0 )
-    {
-      int ioff = 6;
-      if ( lc_units[ioff] == 's' ) ioff++;
-      if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'e' ) status = true;
-    }
+struct cdf_varinfo
+{
+  int        varid;
+  const char *name;
+};
 
-  return status;
+static
+int cdf_cmp_varname(const void *s1, const void *s2)
+{
+  const struct cdf_varinfo *x = (const struct cdf_varinfo *)s1,
+                           *y = (const struct cdf_varinfo *)s2;
+  return strcmp(x->name, y->name);
 }
 
+/* define all input data variables */
 static
-bool isLatAxis(const char *units, const char *stdname)
+void cdf_define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int *varids, int nvars, int num_ncvars, ncvar_t *ncvars)
 {
-  bool status = false;
-  char lc_units[16];
-
-  memcpy(lc_units, units, 15);
-  lc_units[15] = 0;
-  strtolower(lc_units);
+  if ( CDI_Debug )
+    for ( int i = 0; i < nvars; i++ ) Message("varids[%d] = %d", i, varids[i]);
 
-  if ( ((memcmp(lc_units, "degree", 6) == 0 || memcmp(lc_units, "radian", 6) == 0) &&
-        (memcmp(stdname, "grid_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
+  if ( streamptr->sortname )
     {
-      status = true;
+      struct cdf_varinfo *varInfo
+        = (struct cdf_varinfo *) Malloc((size_t)nvars * sizeof(struct cdf_varinfo));
+
+      for ( int varID = 0; varID < nvars; varID++ )
+	{
+	  int ncvarid = varids[varID];
+	  varInfo[varID].varid = ncvarid;
+	  varInfo[varID].name = ncvars[ncvarid].name;
+	}
+      qsort(varInfo, (size_t)nvars, sizeof(varInfo[0]), cdf_cmp_varname);
+      for ( int varID = 0; varID < nvars; varID++ )
+	{
+	  varids[varID] = varInfo[varID].varid;
+	}
+      Free(varInfo);
+      if ( CDI_Debug )
+        for ( int i = 0; i < nvars; i++ ) Message("sorted varids[%d] = %d", i, varids[i]);
     }
 
-  if ( status == false &&
-       memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
-       memcmp(lc_units, "degree", 6) == 0 )
+  for ( int varID1 = 0; varID1 < nvars; varID1++ )
     {
-      int ioff = 6;
-      if ( lc_units[ioff] == 's' ) ioff++;
-      if ( lc_units[ioff] == '_' ) ioff++;
-      if ( lc_units[ioff] == 'n' || lc_units[ioff] == 's' ) status = true;
-    }
+      int ncvarid = varids[varID1];
+      int gridID  = ncvars[ncvarid].gridID;
+      int zaxisID = ncvars[ncvarid].zaxisID;
 
-  return status;
-}
+      stream_new_var(streamptr, gridID, zaxisID, CDI_UNDEFID);
+      int varID = vlistDefVar(vlistID, gridID, zaxisID, ncvars[ncvarid].timetype);
 
-static
-bool isDBLAxis(/*const char *units,*/ const char *longname)
-{
-  bool status = false;
+#if  defined  (HAVE_NETCDF4)
+      if ( ncvars[ncvarid].deflate )
+	vlistDefVarCompType(vlistID, varID, CDI_COMPRESS_ZIP);
 
-  if ( strcmp(longname, "depth below land")         == 0 ||
-       strcmp(longname, "depth_below_land")         == 0 ||
-       strcmp(longname, "levels below the surface") == 0 )
-    {
-      /*
-      if ( strcmp(ncvars[ncvarid].units, "cm") == 0 ||
-           strcmp(ncvars[ncvarid].units, "dm") == 0 ||
-           strcmp(ncvars[ncvarid].units, "m")  == 0 )
-      */
-        status = true;
-    }
+      if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != CDI_UNDEFID )
+        vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
+#endif
 
-  return status;
-}
+      streamptr->vars[varID1].defmiss = false;
+      streamptr->vars[varID1].ncvarid = ncvarid;
 
-static
-bool unitsIsHeight(const char *units)
-{
-  bool status = false;
-  int u0 = units[0];
+      vlistDefVarName(vlistID, varID, ncvars[ncvarid].name);
+      if ( ncvars[ncvarid].param != CDI_UNDEFID ) vlistDefVarParam(vlistID, varID, ncvars[ncvarid].param);
+      if ( ncvars[ncvarid].code != CDI_UNDEFID )  vlistDefVarCode(vlistID, varID, ncvars[ncvarid].code);
+      if ( ncvars[ncvarid].code != CDI_UNDEFID )
+	{
+	  int param = cdiEncodeParam(ncvars[ncvarid].code, ncvars[ncvarid].tabnum, 255);
+	  vlistDefVarParam(vlistID, varID, param);
+	}
+      if ( ncvars[ncvarid].longname[0] )  vlistDefVarLongname(vlistID, varID, ncvars[ncvarid].longname);
+      if ( ncvars[ncvarid].stdname[0] )   vlistDefVarStdname(vlistID, varID, ncvars[ncvarid].stdname);
+      if ( ncvars[ncvarid].units[0] )     vlistDefVarUnits(vlistID, varID, ncvars[ncvarid].units);
 
-  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
-       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
-    {
-      status = true;
-    }
+      if ( ncvars[ncvarid].lvalidrange )
+        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
 
-  return status;
-}
+      if ( IS_NOT_EQUAL(ncvars[ncvarid].addoffset, 0) )
+	vlistDefVarAddoffset(vlistID, varID, ncvars[ncvarid].addoffset);
+      if ( IS_NOT_EQUAL(ncvars[ncvarid].scalefactor, 1) )
+	vlistDefVarScalefactor(vlistID, varID, ncvars[ncvarid].scalefactor);
 
-static
-bool isDepthAxis(const char *stdname, const char *longname)
-{
-  bool status = false;
+      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
 
-  if ( strcmp(stdname, "depth") == 0 )
-    status = true;
-  else
-    if ( strcmp(longname, "depth_below_sea") == 0 ||
-         strcmp(longname, "depth below sea") == 0 )
-      {
-        status = true;
-      }
+      vlistDefVarInstitut(vlistID, varID, instID);
+      vlistDefVarModel(vlistID, varID, modelID);
+      if ( ncvars[ncvarid].tableID != CDI_UNDEFID )
+	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
 
-  return status;
-}
+      if ( ncvars[ncvarid].deffillval == false && ncvars[ncvarid].defmissval )
+        {
+          ncvars[ncvarid].deffillval = true;
+          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
+        }
 
-static
-bool isHeightAxis(const char *stdname, const char *longname)
-{
-  bool status = false;
+      if ( ncvars[ncvarid].deffillval )
+        vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
 
-  if ( strcmp(stdname, "height") == 0 )
-    status = true;
-  else
-    if ( strcmp(longname, "height") == 0 ||
-         strcmp(longname, "height above the surface") == 0 )
-      {
-        status = true;
-      }
+      if ( CDI_Debug )
+	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
+		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
 
-  return status;
-}
+      int gridindex = vlistGridIndex(vlistID, gridID);
+      int xdimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      int ydimid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
 
-static
-bool unitsIsPressure(const char *units)
-{
-  bool status = false;
+      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+      int zdimid = streamptr->zaxisID[zaxisindex];
 
-  if ( strncmp(units, "millibar", 8) == 0 ||
-       strncmp(units, "mb", 2)       == 0 ||
-       strncmp(units, "hectopas", 8) == 0 ||
-       strncmp(units, "hPa", 3)      == 0 ||
-       strncmp(units, "Pa", 2)       == 0 )
-    {
-      status = true;
-    }
+      int ndims = ncvars[ncvarid].ndims;
+      int iodim = 0;
+      int ixyz = 0;
+      static const int ipow10[4] = {1, 10, 100, 1000};
 
-  return status;
-}
+      if ( ncvars[ncvarid].timetype != TIME_CONSTANT ) iodim++;
 
-static
-int scan_hybrid_formula(int ncid, int ncfvarid, int *apvarid, int *bvarid, int *psvarid, int *avarid, int *p0varid)
-{
-  int status = 0;
-  *apvarid = -1;
-  *bvarid  = -1;
-  *psvarid = -1;
-  *avarid  = -1;
-  *p0varid = -1;
-  enum { attstringlen = 8192 }; char attstring[attstringlen];
-  cdfGetAttText(ncid, ncfvarid, "formula", attstringlen, attstring);
-  if ( strcmp(attstring, "p = ap + b*ps") == 0 )
-    {
-      status = 1;
-      int lstop = FALSE;
-      int dimvarid;
-      cdfGetAttText(ncid, ncfvarid, "formula_terms", attstringlen, attstring);
-      char *pstring = attstring;
+      const int *dimids = ncvars[ncvarid].dimids;
 
-      for ( int i = 0; i < 3; i++ )
+      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
         {
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *tagname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
-
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *varname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
-
-          int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
-          if ( status_nc == NC_NOERR )
-            {
-              if      ( strcmp(tagname, "ap:") == 0 ) *apvarid = dimvarid;
-              else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
-              else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
-            }
-          else if ( strcmp(tagname, "ps:") != 0 )
+          ixyz = (xdimid == dimids[ndims-1]) ? 321 : 213;
+        }
+      else
+        {
+          for ( int idim = iodim; idim < ndims; idim++ )
             {
-              Warning("%s - %s", nc_strerror(status_nc), varname);
+              if      ( xdimid == dimids[idim] ) ixyz += 1*ipow10[ndims-idim-1];
+              else if ( ydimid == dimids[idim] ) ixyz += 2*ipow10[ndims-idim-1];
+              else if ( zdimid == dimids[idim] ) ixyz += 3*ipow10[ndims-idim-1];
             }
-
-          if ( lstop ) break;
         }
-    }
-  else if ( strcmp(attstring, "xxxp = a*p0 + b*ps") == 0 )
-    {
-      status = 2;
-      int lstop = FALSE;
-      int dimvarid;
-      cdfGetAttText(ncid, ncfvarid, "formula_terms", attstringlen, attstring);
-      char *pstring = attstring;
 
-      for ( int i = 0; i < 4; i++ )
+      vlistDefVarXYZ(vlistID, varID, ixyz);
+      /*
+      printf("ixyz %d\n", ixyz);
+      printf("ndims %d\n", ncvars[ncvarid].ndims);
+      for ( int i = 0; i < ncvars[ncvarid].ndims; ++i )
+        printf("dimids: %d %d\n", i, dimids[i]);
+      printf("xdimid, ydimid %d %d\n", xdimid, ydimid);
+      */
+      if ( ncvars[ncvarid].ensdata != NULL )
         {
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *tagname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
-
-          while ( isspace((int) *pstring) ) pstring++;
-          if ( *pstring == 0 ) break;
-          char *varname = pstring;
-          while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-          if ( *pstring == 0 ) lstop = TRUE;
-          *pstring++ = 0;
-
-          int status_nc = nc_inq_varid(ncid, varname, &dimvarid);
-          if ( status_nc == NC_NOERR )
-            {
-              if      ( strcmp(tagname, "a:")  == 0 ) *avarid  = dimvarid;
-              else if ( strcmp(tagname, "b:")  == 0 ) *bvarid  = dimvarid;
-              else if ( strcmp(tagname, "ps:") == 0 ) *psvarid = dimvarid;
-              else if ( strcmp(tagname, "p0:") == 0 ) *p0varid = dimvarid;
-            }
-          else if ( strcmp(tagname, "ps:") != 0 )
-            {
-              Warning("%s - %s", nc_strerror(status_nc), varname);
-            }
+          vlistDefVarEnsemble( vlistID, varID, ncvars[ncvarid].ensdata->ens_index,
+                               ncvars[ncvarid].ensdata->ens_count,
+                               ncvars[ncvarid].ensdata->forecast_init_type );
+          Free(ncvars[ncvarid].ensdata);
+          ncvars[ncvarid].ensdata = NULL;
+        }
 
-          if ( lstop ) break;
+      if ( ncvars[ncvarid].extra[0] != 0 )
+        {
+          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
         }
     }
 
-  return status;
-}
-
-static
-bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
-{
-  bool status = false;
-  int ncfvarid = ncvarid;
-  ncvar_t *ncvar = &ncvars[ncvarid];
-
-  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
+  for ( int varID = 0; varID < nvars; varID++ )
     {
-      cdiConvention = CDI_CONVENTION_CF;
-
-      status = true;
-      ncvar->zaxistype = ZAXIS_HYBRID;
-      int dimid = ncvar->dimids[0];
-      size_t dimlen = ncdims[dimid].len;
+      int ncvarid = varids[varID];
+      int ncid = ncvars[ncvarid].ncid;
 
-      int ret;
-      int apvarid1 = -1, bvarid1 = -1, psvarid1 = -1, avarid1 = -1, p0varid1 = -1;
-      if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
-        ret = scan_hybrid_formula(ncid, ncfvarid, &apvarid1, &bvarid1, &psvarid1, &avarid1, &p0varid1);
-      if ( apvarid1 != -1 ) ncvars[apvarid1].isvar = FALSE;
-      if ( bvarid1  != -1 ) ncvars[bvarid1].isvar  = FALSE;
-      if ( psvarid1 != -1 ) ncvar->psvarid = psvarid1;
-      if ( avarid1  != -1 ) ncvars[avarid1].isvar = FALSE;
-      if ( p0varid1 != -1 ) ncvar->p0varid = p0varid1;
+      int nvatts = ncvars[ncvarid].natts;
+      for ( int iatt = 0; iatt < nvatts; ++iatt )
+        {
+          int attnum = ncvars[ncvarid].atts[iatt];
+          cdf_set_cdi_attr(ncid, ncvarid, attnum, vlistID, varID);
+        }
 
-      if ( ncvar->bounds != UNDEFID && ncvars[ncvar->bounds].lformula && ncvars[ncvar->bounds].lformulaterms )
+      if ( ncvars[ncvarid].atts )
         {
-          ncfvarid = ncvar->bounds;
-          int apvarid2 = -1, bvarid2 = -1, psvarid2 = -1, avarid2 = -1, p0varid2 = -1;
-          ret = 0;
-          if ( ncvars[ncfvarid].lformula && ncvars[ncfvarid].lformulaterms )
-            ret = scan_hybrid_formula(ncid, ncfvarid, &apvarid2, &bvarid2, &psvarid2, &avarid2, &p0varid2);
-          if ( ret == 1 ) avarid2 = apvarid2;
-          if ( avarid2 != -1 && bvarid2 != -1 )
-            {
-              ncvars[avarid2].isvar = FALSE;
-              ncvars[bvarid2].isvar  = FALSE;
+          Free(ncvars[ncvarid].atts);
+          ncvars[ncvarid].atts = NULL;
+        }
 
-              if ( dimid == ncvars[avarid2].dimids[0] && ncdims[ncvars[avarid2].dimids[1]].len == 2 )
-                {
-                  double px = 1;
-                  if ( ret == 2 && p0varid1 == p0varid2 )
-                    cdf_get_var_double(ncid, p0varid2, &px);
+      if ( ncvars[ncvarid].vct )
+        {
+          Free(ncvars[ncvarid].vct);
+          ncvars[ncvarid].vct = NULL;
+        }
+    }
 
-                  double abuf[dimlen*2], bbuf[dimlen*2];
-                  cdf_get_var_double(ncid, avarid2, abuf);
-                  cdf_get_var_double(ncid, bvarid2, bbuf);
-                  /*
-                  for ( int i = 0; i < dimlen; ++i )
-                    printf("%d  %g %g    %g %g\n", i, abuf[i*2], abuf[i*2+1], bbuf[i*2], bbuf[i*2+1]);
-                  */
-                  size_t vctsize = (dimlen+1)*2;
-                  double *vct = (double *) Malloc(vctsize * sizeof(double));
-                  for ( size_t i = 0; i < dimlen; ++i )
-                    {
-                      vct[i] = abuf[i*2];
-                      vct[i+dimlen+1] = bbuf[i*2];
-                    }
-                  vct[dimlen]     = abuf[dimlen*2-1];
-                  vct[dimlen*2+1] = bbuf[dimlen*2-1];
+  /* release mem of not freed attributes */
+  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
+    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
 
-                  if ( ret == 2 && IS_NOT_EQUAL(px, 1) )
-                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
+  if ( varids ) Free(varids);
 
-                  ncvar->vct = vct;
-                  ncvar->vctsize = vctsize;
-                }
-            }
-        }
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      if ( vlistInqVarCode(vlistID, varID) == -varID-1 )
+	{
+          char name[CDI_MAX_NAME]; name[0] = 0;
+	  vlistInqVarName(vlistID, varID, name);
+	  size_t len = strlen(name);
+	  if ( len > 3 && isdigit((int) name[3]) )
+	    {
+	      if ( str_is_equal(name, "var") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(name+3));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 4 && isdigit((int) name[4]) )
+	    {
+	      if ( str_is_equal(name, "code") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(name+4));
+		  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 5 && isdigit((int) name[5]) )
+	    {
+	      if ( str_is_equal(name, "param") )
+		{
+		  int pnum = -1, pcat = 255, pdis = 255;
+		  sscanf(name+5, "%d.%d.%d", &pnum, &pcat, &pdis);
+		  vlistDefVarParam(vlistID, varID, cdiEncodeParam(pnum, pcat, pdis));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	}
     }
 
-  return status;
-}
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int varInstID  = vlistInqVarInstitut(vlistID, varID);
+      int varModelID = vlistInqVarModel(vlistID, varID);
+      int varTableID = vlistInqVarTable(vlistID, varID);
+      int code = vlistInqVarCode(vlistID, varID);
+      if ( cdiDefaultTableID != CDI_UNDEFID )
+	{
+          char name[CDI_MAX_NAME]; name[0] = 0;
+          char longname[CDI_MAX_NAME]; longname[0] = 0;
+          char units[CDI_MAX_NAME]; units[0] = 0;
+          tableInqEntry(cdiDefaultTableID, code, -1, name, longname, units);
+	  if ( name[0] )
+	    {
+	      vlistDestroyVarName(vlistID, varID);
+	      vlistDestroyVarLongname(vlistID, varID);
+	      vlistDestroyVarUnits(vlistID, varID);
+
+	      if ( varTableID != CDI_UNDEFID )
+		{
+		  vlistDefVarName(vlistID, varID, name);
+		  if ( longname[0] ) vlistDefVarLongname(vlistID, varID, longname);
+		  if ( units[0] ) vlistDefVarUnits(vlistID, varID, units);
+		}
+	      else
+		{
+		  varTableID = cdiDefaultTableID;
+		}
+	    }
 
+	  if ( cdiDefaultModelID != CDI_UNDEFID ) varModelID = cdiDefaultModelID;
+	  if ( cdiDefaultInstID  != CDI_UNDEFID ) varInstID  = cdiDefaultInstID;
+	}
+      if ( varInstID  != CDI_UNDEFID ) vlistDefVarInstitut(vlistID, varID, varInstID);
+      if ( varModelID != CDI_UNDEFID ) vlistDefVarModel(vlistID, varID, varModelID);
+      if ( varTableID != CDI_UNDEFID ) vlistDefVarTable(vlistID, varID, varTableID);
+    }
+}
 
 static
-int isGaussGrid(size_t ysize, double yinc, const double *yvals)
+void cdf_scan_global_attr(int fileID, int vlistID, stream_t *streamptr, int ngatts, int *instID, int *modelID, bool *ucla_les, unsigned char *uuidOfHGrid, unsigned char *uuidOfVGrid, char *gridfile, int *number_of_grid_used)
 {
-  int lgauss = FALSE;
-  double *yv, *yw;
+  nc_type xtype;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+  char attstring[65636];
 
-  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
+  for ( int iatt = 0; iatt < ngatts; iatt++ )
     {
-      size_t i;
-      yv = (double *) Malloc(ysize*sizeof(double));
-      yw = (double *) Malloc(ysize*sizeof(double));
-      gaussaw(yv, yw, ysize);
-      Free(yw);
-      for ( i = 0; i < ysize; i++ )
-        yv[i] = asin(yv[i])/M_PI*180.0;
+      cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
+      cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
+      cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
 
-      for ( i = 0; i < ysize; i++ )
-        if ( fabs(yv[i] - yvals[i]) >
-             ((yv[0] - yv[1])/500) ) break;
+      if ( xtypeIsText(xtype) )
+	{
+	  cdfGetAttText(fileID, NC_GLOBAL, attname, sizeof(attstring), attstring);
 
-      if ( i == ysize ) lgauss = TRUE;
+          size_t attstrlen = strlen(attstring);
 
-      /* check S->N */
-      if ( lgauss == FALSE )
-        {
-          for ( i = 0; i < ysize; i++ )
-            if ( fabs(yv[i] - yvals[ysize-i-1]) >
-                 ((yv[0] - yv[1])/500) ) break;
+	  if ( attlen > 0 && attstring[0] != 0 )
+	    {
+	      if ( strcmp(attname, "history") == 0 )
+		{
+		  streamptr->historyID = iatt;
+		}
+	      else if ( strcmp(attname, "institution") == 0 )
+		{
+		  *instID = institutInq(0, 0, NULL, attstring);
+		  if ( *instID == CDI_UNDEFID )
+		    *instID = institutDef(0, 0, NULL, attstring);
+		}
+	      else if ( strcmp(attname, "source") == 0 )
+		{
+		  *modelID = modelInq(-1, 0, attstring);
+		  if ( *modelID == CDI_UNDEFID )
+		    *modelID = modelDef(-1, 0, attstring);
+		}
+	      else if ( strcmp(attname, "Source") == 0 )
+		{
+		  if ( strncmp(attstring, "UCLA-LES", 8) == 0 )
+		    *ucla_les = true;
+		}
+	      /*
+	      else if ( strcmp(attname, "Conventions") == 0 )
+		{
+		}
+	      */
+	      else if ( strcmp(attname, "CDI") == 0 )
+		{
+		}
+	      else if ( strcmp(attname, "CDO") == 0 )
+		{
+		}
+              /*
+	      else if ( strcmp(attname, "forecast_reference_time") == 0 )
+		{
+                  memcpy(fcreftime, attstring, attstrlen+1);
+		}
+              */
+	      else if ( strcmp(attname, "grid_file_uri") == 0 )
+		{
+                  memcpy(gridfile, attstring, attstrlen+1);
+		}
+	      else if ( strcmp(attname, "uuidOfHGrid") == 0 && attstrlen == 36 )
+		{
+                  attstring[36] = 0;
+                  cdiStr2UUID(attstring, uuidOfHGrid);
+                  //   printf("uuid: %d %s\n", attlen, attstring);
+		}
+	      else if ( strcmp(attname, "uuidOfVGrid") == 0 && attstrlen == 36 )
+		{
+                  attstring[36] = 0;
+                  cdiStr2UUID(attstring, uuidOfVGrid);
+		}
+	      else
+		{
+                  if ( strcmp(attname, "ICON_grid_file_uri") == 0 && gridfile[0] == 0 )
+                    memcpy(gridfile, attstring, attstrlen+1);
 
-          if ( i == ysize ) lgauss = TRUE;
+		  cdiDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)attstrlen, attstring);
+		}
+	    }
+	}
+      else if ( xtype == NC_SHORT || xtype == NC_INT )
+	{
+	  if ( strcmp(attname, "number_of_grid_used") == 0 )
+	    {
+	      (*number_of_grid_used) = CDI_UNDEFID;
+	      cdfGetAttInt(fileID, NC_GLOBAL, attname, 1, number_of_grid_used);
+	    }
+ 	  else
+            {
+              int attint[attlen];
+              cdfGetAttInt(fileID, NC_GLOBAL, attname, attlen, attint);
+              int datatype = (xtype == NC_SHORT) ? CDI_DATATYPE_INT16 : CDI_DATATYPE_INT32;
+              cdiDefAttInt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attint);
+            }
         }
-
-      Free(yv);
+      else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
+	{
+	  double attflt[attlen];
+	  cdfGetAttDouble(fileID, NC_GLOBAL, attname, attlen, attflt);
+          int datatype = (xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
+          cdiDefAttFlt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attflt);
+	}
     }
-
-  return (lgauss);
 }
 
 static
-void printNCvars(const ncvar_t *ncvars, int nvars, const char *oname)
+int find_leadtime(int nvars, ncvar_t *ncvars)
 {
-  char axis[7];
-  int ncvarid, i;
-  int ndim;
-  static const char iaxis[] = {'t', 'z', 'y', 'x'};
-
-  fprintf(stderr, "%s:\n", oname);
+  int leadtime_id = CDI_UNDEFID;
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      ndim = 0;
-      if ( ncvars[ncvarid].isvar )
-        {
-          axis[ndim++] = 'v';
-          axis[ndim++] = ':';
-          for ( i = 0; i < ncvars[ncvarid].ndims; i++ )
-            {/*
-              if      ( ncvars[ncvarid].tvarid != -1 ) axis[ndim++] = iaxis[0];
-              else if ( ncvars[ncvarid].zvarid != -1 ) axis[ndim++] = iaxis[1];
-              else if ( ncvars[ncvarid].yvarid != -1 ) axis[ndim++] = iaxis[2];
-              else if ( ncvars[ncvarid].xvarid != -1 ) axis[ndim++] = iaxis[3];
-              else
-             */
-              if      ( ncvars[ncvarid].dimtype[i] == T_AXIS ) axis[ndim++] = iaxis[0];
-              else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) axis[ndim++] = iaxis[1];
-              else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) axis[ndim++] = iaxis[2];
-              else if ( ncvars[ncvarid].dimtype[i] == X_AXIS ) axis[ndim++] = iaxis[3];
-              else                                             axis[ndim++] = '?';
-            }
-        }
-      else
-        {
-          axis[ndim++] = 'c';
-          axis[ndim++] = ':';
-          if      ( ncvars[ncvarid].istime ) axis[ndim++] = iaxis[0];
-          else if ( ncvars[ncvarid].islev  ) axis[ndim++] = iaxis[1];
-          else if ( ncvars[ncvarid].islat  ) axis[ndim++] = iaxis[2];
-          else if ( ncvars[ncvarid].islon  ) axis[ndim++] = iaxis[3];
-          else                               axis[ndim++] = '?';
-        }
-
-      axis[ndim++] = 0;
-
-      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
+      if ( ncvars[ncvarid].ndims == 1 )
+        if ( ncvars[ncvarid].stdname[0] && strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
+          {
+            leadtime_id = ncvarid;
+            break;
+          }
     }
+
+  return leadtime_id;
 }
 
 static
-void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
-                          int timedimid, int modelID, int format)
+void find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, stream_t *streamptr,
+                    bool *time_has_units, bool *time_has_bounds, bool *time_climatology)
 {
-  int ncid;
-  int ncdimid;
-  int nvdims, nvatts;
-  int *dimidsp;
-  int iatt;
-  nc_type xtype, atttype;
-  size_t attlen;
-  char name[CDI_MAX_NAME];
-  char attname[CDI_MAX_NAME];
-  const int attstringlen = 8192; char attstring[8192];
-
-  int nchecked_vars = 0;
-  enum { max_check_vars = 9 };
-  char *checked_vars[max_check_vars];
-  for ( int i = 0; i < max_check_vars; ++i ) checked_vars[i] = NULL;
+  int ncvarid;
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  if ( timedimid == CDI_UNDEFID )
     {
-      ncid    = ncvars[ncvarid].ncid;
-      dimidsp = ncvars[ncvarid].dimids;
-
-      cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
-      strcpy(ncvars[ncvarid].name, name);
-
-      for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
-        ncvars[ncvarid].dimtype[ncdimid] = -1;
-
-      ncvars[ncvarid].xtype = xtype;
-      ncvars[ncvarid].ndims = nvdims;
-
-#if  defined  (HAVE_NETCDF4)
-      if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
-        {
-          int shuffle, deflate, deflate_level;
-          size_t chunks[nvdims];
-          int storage_in;
-          nc_inq_var_deflate(ncid, ncvarid, &shuffle, &deflate, &deflate_level);
-          if ( deflate > 0 ) ncvars[ncvarid].deflate = 1;
-
-          if ( nc_inq_var_chunking(ncid, ncvarid, &storage_in, chunks) == NC_NOERR )
-            {
-              if ( storage_in == NC_CHUNKED )
-                {
-                  ncvars[ncvarid].chunked = 1;
-                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = (int)chunks[i];
-                  if ( CDI_Debug )
-                    {
-                      fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
-                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%ld ", chunks[i]);
-                      fprintf(stderr, "\n");
-                    }
-                  {
-                    char *buf = ncvars[ncvarid].extra;
-                    size_t pos = strlen(buf);
-                    static const char prefix[] = "chunks=";
-                    memcpy(buf + pos, prefix, sizeof (prefix));
-                    pos += sizeof (prefix) - 1;
-                    for ( int i = nvdims-1; i >= 0; --i )
-                      {
-                        pos += (size_t)(sprintf(buf + pos, "%zu%s", chunks[i],
-                                                i > 0 ? "x" : ""));
-                      }
-                    buf[pos] = ' '; buf[pos + 1] = 0;
-                  }
-                }
-            }
-        }
-#endif
+      char timeunits[CDI_MAX_NAME];
 
-      if ( nvdims > 0 )
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
         {
-          if ( timedimid == dimidsp[0] )
-            {
-              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
-              cdfSetDim(ncvars, ncvarid, 0, T_AXIS);
-            }
-          else
+          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
             {
-              for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
+              if ( ncvars[ncvarid].units[0] )
                 {
-                  if ( timedimid == dimidsp[ncdimid] )
+                  strcpy(timeunits, ncvars[ncvarid].units);
+                  str_tolower(timeunits);
+
+                  if ( is_time_units(timeunits) )
                     {
-                      Warning("Time must be the first dimension! Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = FALSE;
+                      streamptr->basetime.ncvarid = ncvarid;
+                      break;
                     }
                 }
             }
         }
+    }
+  else
+    {
+      bool ltimevar = false;
 
-      for ( iatt = 0; iatt < nvatts; iatt++ )
+      if ( ncdims[timedimid].ncvarid != CDI_UNDEFID )
         {
-          cdf_inq_attname(ncid, ncvarid, iatt, attname);
-          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
-          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
+          ltimevar = true;
+        }
 
-          if ( strcmp(attname, "long_name") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].longname);
-            }
-          else if ( strcmp(attname, "standard_name") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].stdname);
-            }
-          else if ( strcmp(attname, "units") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, CDI_MAX_NAME, ncvars[ncvarid].units);
-            }
-          else if ( strcmp(attname, "calendar") == 0 )
-            {
-              ncvars[ncvarid].calendar = TRUE;
-            }
-          else if ( strcmp(attname, "param") == 0 && xtypeIsText(atttype) )
-            {
-	      char paramstr[32];
-	      int pnum = 0, pcat = 255, pdis = 255;
-              cdfGetAttText(ncid, ncvarid, attname, sizeof(paramstr), paramstr);
-	      sscanf(paramstr, "%d.%d.%d", &pnum, &pcat, &pdis);
-	      ncvars[ncvarid].param = cdiEncodeParam(pnum, pcat, pdis);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "code") == 0 && !xtypeIsText(atttype) )
-            {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "table") == 0 && !xtypeIsText(atttype) )
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+        if ( ncvarid != streamptr->basetime.ncvarid &&
+             ncvars[ncvarid].ndims == 1 &&
+             timedimid == ncvars[ncvarid].dimids[0] &&
+             !xtypeIsText(ncvars[ncvarid].xtype) &&
+             is_timeaxis_units(ncvars[ncvarid].units) )
+          {
+            ncvars[ncvarid].isvar = FALSE;
+
+            if ( !ltimevar )
+              {
+                streamptr->basetime.ncvarid = ncvarid;
+                ltimevar = true;
+                if ( CDI_Debug )
+                  fprintf(stderr, "timevar %s\n", ncvars[ncvarid].name);
+              }
+            else
+              {
+                Warning("Found more than one time variable, skipped variable %s!", ncvars[ncvarid].name);
+              }
+          }
+
+      if ( ltimevar == false ) /* search for WRF time description */
+        {
+          for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+            if ( ncvarid != streamptr->basetime.ncvarid &&
+                 ncvars[ncvarid].ndims == 2 &&
+                 timedimid == ncvars[ncvarid].dimids[0] &&
+                 xtypeIsText(ncvars[ncvarid].xtype) &&
+                 ncdims[ncvars[ncvarid].dimids[1]].len == 19 )
+              {
+                streamptr->basetime.ncvarid = ncvarid;
+                streamptr->basetime.lwrf    = true;
+                break;
+              }
+        }
+
+      /* time varID */
+      ncvarid = streamptr->basetime.ncvarid;
+
+      if ( ncvarid == CDI_UNDEFID )
+        {
+          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
+        }
+    }
+
+  /* time varID */
+  ncvarid = streamptr->basetime.ncvarid;
+
+  if ( ncvarid != CDI_UNDEFID && streamptr->basetime.lwrf == false )
+    {
+      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = true;
+
+      if ( ncvars[ncvarid].bounds != CDI_UNDEFID )
+        {
+          int nbdims = ncvars[ncvars[ncvarid].bounds].ndims;
+          if ( nbdims == 2 )
             {
-              int tablenum;
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &tablenum);
-              if ( tablenum > 0 )
+              int len = (int) ncdims[ncvars[ncvars[ncvarid].bounds].dimids[nbdims-1]].len;
+              if ( len == 2 && timedimid == ncvars[ncvars[ncvarid].bounds].dimids[0] )
                 {
-                  ncvars[ncvarid].tabnum = tablenum;
-                  ncvars[ncvarid].tableID = tableInq(modelID, tablenum, NULL);
-                  if ( ncvars[ncvarid].tableID == CDI_UNDEFID )
-                    ncvars[ncvarid].tableID = tableDef(modelID, tablenum, NULL);
+                  *time_has_bounds = true;
+                  streamptr->basetime.ncvarboundsid = ncvars[ncvarid].bounds;
+                  if ( ncvars[ncvarid].climatology ) *time_climatology = true;
                 }
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "trunc_type") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              if ( memcmp(attstring, "Triangular", attlen) == 0 )
-                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
             }
-          else if ( strcmp(attname, "grid_type") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
-
-              if      ( strcmp(attstring, "gaussian reduced") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GAUSSIAN_REDUCED;
-              else if ( strcmp(attstring, "gaussian") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-              else if ( strncmp(attstring, "spectral", 8) == 0 )
-                ncvars[ncvarid].gridtype = GRID_SPECTRAL;
-              else if ( strncmp(attstring, "fourier", 7) == 0 )
-                ncvars[ncvarid].gridtype = GRID_FOURIER;
-              else if ( strcmp(attstring, "trajectory") == 0 )
-                ncvars[ncvarid].gridtype = GRID_TRAJECTORY;
-              else if ( strcmp(attstring, "generic") == 0 )
-                ncvars[ncvarid].gridtype = GRID_GENERIC;
-              else if ( strcmp(attstring, "cell") == 0 )
-                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
-              else if ( strcmp(attstring, "unstructured") == 0 )
-                ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
-              else if ( strcmp(attstring, "curvilinear") == 0 )
-                ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-              else if ( strcmp(attstring, "sinusoidal") == 0 )
-                ;
-              else if ( strcmp(attstring, "laea") == 0 )
-                ;
-              else if ( strcmp(attstring, "lcc2") == 0 )
-                ;
-              else if ( strcmp(attstring, "linear") == 0 ) // ignore grid type linear
-                ;
-              else
-                {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("NetCDF attribute grid_type='%s' unsupported!", attstring);
-                    }
-                }
+        }
+    }
+}
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "level_type") == 0 && xtypeIsText(atttype) )
+static
+void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
+{
+  /* find ECHAM VCT */
+  int nvcth_id = CDI_UNDEFID, vcta_id = CDI_UNDEFID, vctb_id = CDI_UNDEFID;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].ndims == 1 )
+        {
+          size_t len = strlen(ncvars[ncvarid].name);
+          if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
             {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
-
-              if      ( strcmp(attstring, "toa") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_TOA;
-              else if ( strcmp(attstring, "cloudbase") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_BASE;
-              else if ( strcmp(attstring, "cloudtop") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_CLOUD_TOP;
-              else if ( strcmp(attstring, "isotherm0") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_ISOTHERM_ZERO;
-              else if ( strcmp(attstring, "seabottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEA_BOTTOM;
-              else if ( strcmp(attstring, "lakebottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_LAKE_BOTTOM;
-              else if ( strcmp(attstring, "sedimentbottom") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM;
-              else if ( strcmp(attstring, "sedimentbottomta") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TA;
-              else if ( strcmp(attstring, "sedimentbottomtw") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_SEDIMENT_BOTTOM_TW;
-              else if ( strcmp(attstring, "mixlayer") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_MIX_LAYER;
-              else if ( strcmp(attstring, "atmosphere") == 0 )
-                ncvars[ncvarid].zaxistype = ZAXIS_ATMOSPHERE;
-              else
+              if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
                 {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
-                    }
+                  vcta_id = ncvarid;
+                  nvcth_id = ncvars[ncvarid].dimids[0];
+                  ncvars[ncvarid].isvar = FALSE;
                 }
-
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "trunc_count") == 0 && !xtypeIsText(atttype) )
-            {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
-            }
-          else if ( strcmp(attname, "truncation") == 0 && !xtypeIsText(atttype) )
-            {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
-            }
-          else if ( strcmp(attname, "number_of_grid_in_reference") == 0 && !xtypeIsText(atttype) )
-            {
-              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
-            }
-          else if ( strcmp(attname, "add_offset") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].addoffset);
-	      /*
-		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
-		if ( ncvars[ncvarid].addoffset != 0 )
-		Warning("attribute add_offset not supported for atttype %d", atttype);
-	      */
-	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "scale_factor") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].scalefactor);
-	      /*
-		if ( atttype != NC_BYTE && atttype != NC_SHORT && atttype != NC_INT )
-		if ( ncvars[ncvarid].scalefactor != 1 )
-		Warning("attribute scale_factor not supported for atttype %d", atttype);
-	      */
-	      /* (also used for lon/lat) cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "climatology") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int ncboundsid;
-              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
-              if ( status == NC_NOERR )
+              else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
                 {
-                  ncvars[ncvarid].climatology = TRUE;
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
+                  vctb_id = ncvarid;
+                  nvcth_id = ncvars[ncvarid].dimids[0];
+                  ncvars[ncvarid].isvar = FALSE;
                 }
-              else
-                Warning("%s - %s", nc_strerror(status), attstring);
-            }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "bounds") == 0 )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int ncboundsid;
-              int status = nc_inq_varid(ncid, attstring, &ncboundsid);
-              if ( status == NC_NOERR )
+              else if ( (ncvars[ncvarid].name[2] == 'a' || ncvars[ncvarid].name[2] == 'b') && ncvars[ncvarid].name[3] == 'm' )
                 {
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
+                  ncvars[ncvarid].isvar = FALSE; // hyam or hybm
                 }
-              else
-                Warning("%s - %s", nc_strerror(status), attstring);
-            }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "formula_terms") == 0 )
-            {
-              ncvars[ncvarid].lformulaterms = TRUE;
             }
-          else if ( xtypeIsText(atttype) && strcmp(attname, "formula") == 0 )
+	}
+    }
+
+  /* read VCT */
+  if ( nvcth_id != CDI_UNDEFID && vcta_id != CDI_UNDEFID && vctb_id != CDI_UNDEFID )
+    {
+      size_t vctsize = ncdims[nvcth_id].len;
+      vctsize *= 2;
+      *vct = (double *) Malloc(vctsize*sizeof(double));
+      cdf_get_var_double(fileID, vcta_id, *vct);
+      cdf_get_var_double(fileID, vctb_id, *vct+vctsize/2);
+      *pvctsize = vctsize;
+    }
+}
+
+static
+void cdf_set_ucla_dimtype(int ndims, ncdim_t *ncdims, ncvar_t *ncvars)
+{
+  for ( int ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      int ncvarid = ncdims[ncdimid].ncvarid;
+      if ( ncvarid != -1 )
+        {
+          if ( ncdims[ncdimid].dimtype == CDI_UNDEFID && ncvars[ncvarid].units[0] == 'm' )
             {
-              ncvars[ncvarid].lformula = TRUE;
+              if      ( ncvars[ncvarid].name[0] == 'x' ) ncdims[ncdimid].dimtype = X_AXIS;
+              else if ( ncvars[ncvarid].name[0] == 'y' ) ncdims[ncdimid].dimtype = Y_AXIS;
+              else if ( ncvars[ncvarid].name[0] == 'z' ) ncdims[ncdimid].dimtype = Z_AXIS;
             }
-          else if ( strcmp(attname, "cell_measures") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+        }
+    }
+}
 
-              while ( isspace((int) *pstring) ) pstring++;
-              char *cell_measures = pstring;
-              while ( isalnum((int) *pstring) ) pstring++;
-              *pstring++ = 0;
-              while ( isspace((int) *pstring) ) pstring++;
-              char *cell_var = pstring;
-              while ( ! isspace((int) *pstring) && *pstring != 0 ) pstring++;
-              *pstring++ = 0;
-              /*
-              printf("cell_measures >%s<\n", cell_measures);
-              printf("cell_var >%s<\n", cell_var);
-              */
-              if ( memcmp(cell_measures, "area", 4) == 0 )
-                {
-                  int nc_cell_id;
-                  int status = nc_inq_varid(ncid, cell_var, &nc_cell_id);
-                  if ( status == NC_NOERR )
-                    {
-                      ncvars[ncvarid].cellarea = nc_cell_id;
-                      /* ncvars[nc_cell_id].isvar = UNDEFID; */
-                      cdfSetVar(ncvars, nc_cell_id, FALSE);
-                    }
-                  else
-                    Warning("%s - %s", nc_strerror(status), cell_var);
-                }
-              else
-                {
-                  Warning("%s has an unexpected contents: %s", attname, cell_measures);
-                }
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          /*
-          else if ( strcmp(attname, "coordinates") == 0 )
-            {
-              char *pstring, *xvarname = NULL, *yvarname = NULL;
+static
+int cdf_check_vars(int nvars, ncvar_t *ncvars, size_t ntsteps, int timedimid)
+{
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( timedimid != CDI_UNDEFID )
+	if ( ncvars[ncvarid].isvar == -1 &&
+	     ncvars[ncvarid].ndims > 1   &&
+	     timedimid == ncvars[ncvarid].dimids[0] )
+	  cdf_set_var(ncvars, ncvarid, TRUE);
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              pstring = attstring;
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
+	cdf_set_var(ncvars, ncvarid, FALSE);
 
-              while ( isspace((int) *pstring) ) pstring++;
-              xvarname = pstring;
-              while ( isgraph((int) *pstring) ) pstring++;
-              *pstring++ = 0;
-              while ( isspace((int) *pstring) ) pstring++;
-              yvarname = pstring;
-              while ( isgraph((int) *pstring) ) pstring++;
-              *pstring++ = 0;
+      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
+	cdf_set_var(ncvars, ncvarid, TRUE);
 
-              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
-              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
+      if ( ncvars[ncvarid].isvar == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
+	  continue;
+	}
 
-              cdfSetVar(ncvars, ncvars[ncvarid].xvarid, FALSE);
-              cdfSetVar(ncvars, ncvars[ncvarid].yvarid, FALSE);
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          */
-          else if ( (strcmp(attname, "associate")  == 0 || strcmp(attname, "coordinates") == 0) && xtypeIsText(atttype) )
-            {
-              int lstop = FALSE;
-              int dimvarid;
+      if ( ncvars[ncvarid].ndims > 4 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("%d dimensional variables are not supported, skipped variable %s!",
+		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
+	  continue;
+	}
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+      if ( ncvars[ncvarid].ndims == 4 && timedimid == CDI_UNDEFID )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("%d dimensional variables without time dimension are not supported, skipped variable %s!",
+		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
+	  continue;
+	}
 
-              for ( int i = 0; i < MAX_COORDVARS; i++ )
-                {
-                  while ( isspace((int) *pstring) ) pstring++;
-                  if ( *pstring == 0 ) break;
-                  char *varname = pstring;
-                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-                  if ( *pstring == 0 ) lstop = TRUE;
-                  *pstring++ = 0;
+      if ( xtypeIsText(ncvars[ncvarid].xtype) )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  continue;
+	}
 
-                  int status = nc_inq_varid(ncid, varname, &dimvarid);
-                  if ( status == NC_NOERR )
-                    {
-                      cdfSetVar(ncvars, dimvarid, FALSE);
-                      if ( cdiIgnoreAttCoordinates == FALSE )
-                        {
-                          ncvars[ncvarid].coordvarids[i] = dimvarid;
-                          ncvars[ncvarid].ncoordvars++;
-                        }
-                    }
-                  else
-                    {
-                      int k;
-                      for ( k = 0; k < nchecked_vars; ++k )
-                        if ( strcmp(checked_vars[k], varname) == 0 ) break;
+      if ( cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Unsupported data type, skipped variable %s!", ncvars[ncvarid].name);
+	  continue;
+	}
 
-                      if ( k == nchecked_vars )
-                        {
-                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
-                          Warning("%s - %s", nc_strerror(status), varname);
-                        }
-                    }
+      if ( timedimid != CDI_UNDEFID && ntsteps == 0 && ncvars[ncvarid].ndims > 0 )
+	{
+	  if ( timedimid == ncvars[ncvarid].dimids[0] )
+	    {
+	      ncvars[ncvarid].isvar = 0;
+	      Warning("Number of time steps undefined, skipped variable %s!", ncvars[ncvarid].name);
+	      continue;
+	    }
+	}
+    }
 
-                  if ( lstop ) break;
-                }
+  return timedimid;
+}
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( (strcmp(attname, "auxiliary_variable") == 0) && xtypeIsText(atttype) )
-            {
-              int lstop = FALSE;
-              int dimvarid;
 
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
+int cdfInqContents(stream_t *streamptr)
+{
+  int ndims, nvars, ngatts, unlimdimid;
+  int ncvarid;
+  int ncdimid;
+  int *varids;
+  int nvarids;
+  bool time_has_units = false;
+  bool time_has_bounds = false;
+  bool time_climatology = false;
+  int leadtime_id = CDI_UNDEFID;
+  int nvars_data;
+  int instID  = CDI_UNDEFID;
+  int modelID = CDI_UNDEFID;
+  int calendar = CDI_UNDEFID;
+  int format = 0;
+  bool ucla_les = false;
+  char gridfile[8912];
+  char fcreftime[CDI_MAX_NAME];
+  int number_of_grid_used = CDI_UNDEFID;
 
-              for ( int i = 0; i < MAX_AUXVARS; i++ )
-                {
-                  while ( isspace((int) *pstring) ) pstring++;
-                  if ( *pstring == 0 ) break;
-                  char *varname = pstring;
-                  while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
-                  if ( *pstring == 0 ) lstop = TRUE;
-                  *pstring++ = 0;
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
+  memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
+  memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
+  gridfile[0] = 0;
+  fcreftime[0] = 0;
 
-                  int status = nc_inq_varid(ncid, varname, &dimvarid);
-                  if ( status == NC_NOERR )
-                    {
-                      cdfSetVar(ncvars, dimvarid, FALSE);
-                      //  if ( cdiIgnoreAttCoordinates == FALSE )
-                        {
-                          ncvars[ncvarid].auxvarids[i] = dimvarid;
-                          ncvars[ncvarid].nauxvars++;
-                        }
-                    }
-                  else
-                    Warning("%s - %s", nc_strerror(status), varname);
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-                  if ( lstop ) break;
-                }
+  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "grid_mapping") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              int nc_gmap_id;
-              int status = nc_inq_varid(ncid, attstring, &nc_gmap_id);
-              if ( status == NC_NOERR )
-                {
-                  ncvars[ncvarid].gmapid = nc_gmap_id;
-                  cdfSetVar(ncvars, ncvars[ncvarid].gmapid, FALSE);
-                }
-              else
-                Warning("%s - %s", nc_strerror(status), attstring);
+#if  defined  (HAVE_NETCDF4)
+  nc_inq_format(fileID, &format);
+#endif
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "positive") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
 
-              if    ( memcmp(attstring, "down", 4) == 0 ) ncvars[ncvarid].positive = POSITIVE_DOWN;
-              else if ( memcmp(attstring, "up", 2) == 0 ) ncvars[ncvarid].positive = POSITIVE_UP;
+  if ( CDI_Debug )
+    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+  /*
+  if ( ndims == 0 )
+    {
+      Warning("No dimensions found!");
+      return CDI_EUFSTRUCT;
+    }
+  */
+  // alloc ncdims
+  ncdim_t *ncdims = ndims ? (ncdim_t *) Malloc((size_t)ndims * sizeof(ncdim_t)) : NULL;
+  init_ncdims(ndims, ncdims);
 
-              if ( ncvars[ncvarid].ndims == 1 )
-                {
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                  cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
-                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
-                }
-            }
-          else if ( strcmp(attname, "_FillValue") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
-	      ncvars[ncvarid].deffillval = TRUE;
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "missing_value") == 0 && !xtypeIsText(atttype) )
-            {
-	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].missval);
-	      ncvars[ncvarid].defmissval = TRUE;
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "valid_range") == 0 && attlen == 2 )
-            {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 2, ncvars[ncvarid].validrange);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                      if ( ((int)ncvars[ncvarid].validrange[0]) == 0 && ((int)ncvars[ncvarid].validrange[1]) == 255 )
-                        ncvars[ncvarid].lunsigned = TRUE;
-                      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_range, ignored!", name);
-                    }
-                }
-            }
-          else if ( strcmp(attname, "valid_min") == 0 && attlen == 1 )
-            {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[0]);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_min, ignored!", name);
-                    }
-                }
-            }
-          else if ( strcmp(attname, "valid_max") == 0 && attlen == 1 )
+#if  defined  (TEST_GROUPS)
+#if  defined  (HAVE_NETCDF4)
+  if ( format == NC_FORMAT_NETCDF4 )
+    {
+      int ncid;
+      int numgrps;
+      int ncids[NC_MAX_VARS];
+      char name1[CDI_MAX_NAME];
+      int gndims, gnvars, gngatts, gunlimdimid;
+      nc_inq_grps(fileID, &numgrps, ncids);
+      for ( int i = 0; i < numgrps; ++i )
+        {
+          ncid = ncids[i];
+          nc_inq_grpname(ncid, name1);
+          cdf_inq(ncid, &gndims , &gnvars, &gngatts, &gunlimdimid);
+
+          if ( CDI_Debug )
+            Message("%s: ndims %d, nvars %d, ngatts %d", name1, gndims, gnvars, gngatts);
+
+          if ( gndims == 0 )
             {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
-                {
-                  extern int cdiIgnoreValidRange;
-                  int lignore = xtypeIsFloat(atttype) != xtypeIsFloat(xtype);
-                  if ( cdiIgnoreValidRange == FALSE && lignore == FALSE )
-                    {
-                      cdfGetAttDouble(ncid, ncvarid, attname, 1, &(ncvars[ncvarid].validrange)[1]);
-                      ncvars[ncvarid].lvalidrange = TRUE;
-                    }
-                  else if ( lignore )
-                    {
-                      Warning("Inconsistent data type for attribute %s:valid_max, ignored!", name);
-                    }
-                }
             }
-          else if ( strcmp(attname, "_Unsigned") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+        }
+    }
+#endif
+#endif
 
-              if ( memcmp(attstring, "true", 4) == 0 )
-                {
-                  ncvars[ncvarid].lunsigned = TRUE;
-                  /*
-                  ncvars[ncvarid].lvalidrange = TRUE;
-                  ncvars[ncvarid].validrange[0] = 0;
-                  ncvars[ncvarid].validrange[1] = 255;
-                  */
-                }
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
-            }
-          else if ( strcmp(attname, "cdi") == 0 && xtypeIsText(atttype) )
-            {
-	      cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      strtolower(attstring);
+  if ( nvars == 0 )
+    {
+      Warning("No arrays found!");
+      return CDI_EUFSTRUCT;
+    }
 
-	      if ( memcmp(attstring, "ignore", 6) == 0 )
-		{
-		  ncvars[ncvarid].ignore = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		}
-            }
-          else if ( strcmp(attname, "axis") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      attlen = strlen(attstring);
+  // alloc ncvars
+  ncvar_t *ncvars = nvars ? (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t)) : NULL;
+  init_ncvars(nvars, ncvars);
 
-	      if ( (int) attlen > nvdims && nvdims > 0 && attlen > 1 )
-		{
-		    Warning("Unexpected axis attribute length for %s, ignored!", name);
-		}
-              else if ( nvdims == 0 && attlen == 1 )
-                {
-                  if ( attstring[0] == 'z' || attstring[0] == 'Z' )
-                    {
-                      cdfSetVar(ncvars, ncvarid, FALSE);
-                      ncvars[ncvarid].islev = TRUE;
-                    }
-                }
-	      else
-		{
-		  strtolower(attstring);
-                  int i;
-		  for ( i = 0; i < (int)attlen; ++i )
-		    {
-		      if ( attstring[i] != '-' && attstring[i] != 't' && attstring[i] != 'z' &&
-			   attstring[i] != 'y' && attstring[i] != 'x' )
-			{
-			  Warning("Unexpected character in axis attribute for %s, ignored!", name);
-			  break;
-			}
-		    }
+  for ( ncvarid = 0; ncvarid < nvars; ++ncvarid ) ncvars[ncvarid].ncid = fileID;
 
-		  if ( i == (int) attlen && (int) attlen == nvdims )
-		    {
-		      while ( attlen-- )
-			{
-			  if ( (int) attstring[attlen] == 't' )
-			    {
-			      if ( attlen != 0 ) Warning("axis attribute 't' not on first position");
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, T_AXIS);
-			    }
-			  else if ( (int) attstring[attlen] == 'z' )
-			    {
-                              ncvars[ncvarid].zdim = dimidsp[attlen];
-                              cdfSetDim(ncvars, ncvarid, (int)attlen, Z_AXIS);
-
-                              if ( ncvars[ncvarid].ndims == 1 )
-                                {
-                                  cdfSetVar(ncvars, ncvarid, FALSE);
-                                  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Z_AXIS;
-                                }
-			    }
-			  else if ( (int) attstring[attlen] == 'y' )
-			    {
-			      ncvars[ncvarid].ydim = dimidsp[attlen];
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, Y_AXIS);
-
-			      if ( ncvars[ncvarid].ndims == 1 )
-				{
-				  cdfSetVar(ncvars, ncvarid, FALSE);
-				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = Y_AXIS;
-				}
-			    }
-			  else if ( (int) attstring[attlen] == 'x' )
-			    {
-			      ncvars[ncvarid].xdim = dimidsp[attlen];
-			      cdfSetDim(ncvars, ncvarid, (int)attlen, X_AXIS);
-
-			      if ( ncvars[ncvarid].ndims == 1 )
-				{
-				  cdfSetVar(ncvars, ncvarid, FALSE);
-				  ncdims[ncvars[ncvarid].dimids[0]].dimtype = X_AXIS;
-				}
-			    }
-			}
-		    }
-		}
-	    }
-	  else if ( ( strcmp(attname, "realization") == 0 )         ||
-	            ( strcmp(attname, "ensemble_members") == 0 )    ||
-	            ( strcmp(attname, "forecast_init_type") == 0 )    )
-	    {
-	      int temp;
 
-	      if( ncvars[ncvarid].ensdata == NULL )
-		ncvars[ncvarid].ensdata = (ensinfo_t *) Malloc( sizeof( ensinfo_t ) );
+  // scan global attributes
+  cdf_scan_global_attr(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
+                       uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
+
+  // find time dim
+  int timedimid = (unlimdimid >= 0) ? unlimdimid : cdf_time_dimid(fileID, ndims, nvars);
+
+  streamptr->basetime.ncdimid = timedimid;
+
+  size_t ntsteps = 0;
+  if ( timedimid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, timedimid, &ntsteps);
+  if ( ntsteps > INT_MAX )
+    {
+      Warning("Size limit exceeded for time dimension (limit=%d)!", INT_MAX);
+      return CDI_EDIMSIZE;
+    }
+
+  if ( CDI_Debug ) Message("Number of timesteps = %zu", ntsteps);
+  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
+
+  // read ncdims
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      cdf_inq_dimlen(fileID, ncdimid, &ncdims[ncdimid].len);
+      cdf_inq_dimname(fileID, ncdimid, ncdims[ncdimid].name);
+      if ( timedimid == ncdimid )
+	ncdims[ncdimid].dimtype = T_AXIS;
+    }
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_scan_var_attr");
 
-	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
+  // scan attributes of all variables
+  cdf_scan_var_attr(nvars, ncvars, ncdims, timedimid, modelID, format);
 
-	      if( strcmp(attname, "realization") == 0 )
-		ncvars[ncvarid].ensdata->ens_index = temp;
-	      else if( strcmp(attname, "ensemble_members") == 0 )
-		ncvars[ncvarid].ensdata->ens_count = temp;
-	      else if( strcmp(attname, "forecast_init_type") == 0 )
-		ncvars[ncvarid].ensdata->forecast_init_type = temp;
 
-	      cdfSetVar(ncvars, ncvarid, TRUE);
-	    }
-	  else
-	    {
-	      if ( ncvars[ncvarid].natts == 0 )
-		ncvars[ncvarid].atts
-                  = (int *) Malloc((size_t)nvatts * sizeof (int));
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "find coordinate vars");
 
-	      ncvars[ncvarid].atts[ncvars[ncvarid].natts++] = iatt;
-	      /*
-	      int attrint;
-	      double attrflt;
-	      nc_type attrtype;
-	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
-	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
-	      if ( attlen == 1 && (attrtype == NC_INT || attrtype == NC_SHORT) )
-		{
-		  cdfGetAttInt(ncid, ncvarid, attname, 1, &attrint);
-		  printf("int: %s.%s = %d\n", ncvars[ncvarid].name, attname, attrint);
-		}
-	      else if ( attlen == 1 && (attrtype == NC_FLOAT || attrtype == NC_DOUBLE) )
+  // find coordinate vars
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+	{
+	  if ( ncvars[ncvarid].ndims == 1 )
+	    {
+	      if ( timedimid != CDI_UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
 		{
-		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
-		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
+		  if ( ncvars[ncvarid].isvar != FALSE ) cdf_set_var(ncvars, ncvarid, TRUE);
 		}
-	      else if ( attrtype == NC_CHAR )
+	      else
 		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  attstring[attlen] = 0;
-		  printf("txt: %s.%s = %s\n", ncvars[ncvarid].name, attname, attstring);
+                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
 		}
-	      else
-		printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
-	      */
+	      // if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
+
+	      if ( ncdimid == ncvars[ncvarid].dimids[0] && ncdims[ncdimid].ncvarid == CDI_UNDEFID )
+		if ( strcmp(ncvars[ncvarid].name, ncdims[ncdimid].name) == 0 )
+		  {
+		    ncdims[ncdimid].ncvarid = ncvarid;
+		    ncvars[ncvarid].isvar = FALSE;
+		  }
 	    }
 	}
     }
 
-  for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
-}
-
-static
-void setDimType(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
-{
-  int ndims;
-  int ncvarid, ncdimid;
-  int i;
-
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].isvar == TRUE )
-	{
-	  int lxdim = 0, lydim = 0, lzdim = 0/* , ltdim = 0 */;
-	  ndims = ncvars[ncvarid].ndims;
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      ncdimid = ncvars[ncvarid].dimids[i];
-	      if      ( ncdims[ncdimid].dimtype == X_AXIS ) cdfSetDim(ncvars, ncvarid, i, X_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == Y_AXIS ) cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == Z_AXIS ) cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
-	      else if ( ncdims[ncdimid].dimtype == T_AXIS ) cdfSetDim(ncvars, ncvarid, i, T_AXIS);
-	    }
+  // find time vars
+  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
 
-	  if ( CDI_Debug )
-	    {
-	      Message("var %d %s", ncvarid, ncvars[ncvarid].name);
-	      for ( i = 0; i < ndims; i++ )
-		printf("  dim%d type=%d  ", i, ncvars[ncvarid].dimtype[i]);
-	      printf("\n");
-	    }
+  leadtime_id = find_leadtime(nvars, ncvars);
+  if ( leadtime_id != CDI_UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
 
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) lxdim = TRUE;
-	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) lydim = TRUE;
-	      else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) lzdim = TRUE;
-	      /* else if ( ncvars[ncvarid].dimtype[i] == T_AXIS ) ltdim = TRUE; */
-	    }
+  // check ncvars
+  timedimid = cdf_check_vars(nvars, ncvars, ntsteps, timedimid);
 
-          if ( lxdim == FALSE && ncvars[ncvarid].xvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = TRUE;
-            }
+  // verify coordinate vars - first scan (dimname == varname)
+  bool lhybrid_cf = false;
+  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid, &lhybrid_cf);
 
-          if ( lydim == FALSE && ncvars[ncvarid].yvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = TRUE;
-            }
+  // verify coordinate vars - second scan (all other variables)
+  verify_coordinate_vars_2(nvars, ncvars);
 
-          //   if ( ndims > 1 )
-            for ( i = ndims-1; i >= 0; i-- )
-              {
-                if ( ncvars[ncvarid].dimtype[i] == -1 )
-                  {
-                    if ( lxdim == FALSE )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, X_AXIS);
-                        lxdim = TRUE;
-                      }
-                    else if ( lydim == FALSE && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, Y_AXIS);
-                        lydim = TRUE;
-                      }
-                    else if ( lzdim == FALSE )
-                      {
-                        cdfSetDim(ncvars, ncvarid, i, Z_AXIS);
-                        lzdim = TRUE;
-                      }
-                  }
-              }
-	}
-    }
-}
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "verify_coordinate_vars");
 
-/* verify coordinate vars - first scan (dimname == varname) */
-static
-void verify_coordinate_vars_1(int ncid, int ndims, ncdim_t *ncdims, ncvar_t *ncvars, int timedimid)
-{
-  int ncdimid, ncvarid;
+  if ( ucla_les ) cdf_set_ucla_dimtype(ndims, ncdims, ncvars);
 
+  /*
   for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
     {
       ncvarid = ncdims[ncdimid].ncvarid;
       if ( ncvarid != -1 )
 	{
-	  if ( ncvars[ncvarid].dimids[0] == timedimid )
-	    {
-              ncvars[ncvarid].istime = TRUE;
-	      ncdims[ncdimid].dimtype = T_AXIS;
-	      continue;
-	    }
-
-          if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) ) continue;
-
-	  if ( ncvars[ncvarid].units[0] != 0 )
-	    {
-	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
-		  ncdims[ncdimid].dimtype = X_AXIS;
-		}
-	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
-		  ncdims[ncdimid].dimtype = Y_AXIS;
-		}
-	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
-		{
-		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
-		}
-	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
-		{
-		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
-		}
-	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
-                {
-                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
-		}
-	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
-		{
-		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
-		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
-		}
-	    }
-          else
-            {
-              if ( (strcmp(ncvars[ncvarid].longname, "generalized_height") == 0 ||
-                    strcmp(ncvars[ncvarid].longname, "generalized height") == 0) &&
-                   strcmp(ncvars[ncvarid].stdname, "height") == 0 )
-                  ncvars[ncvarid].zaxistype = ZAXIS_REFERENCE;
-            }
-
-	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
-               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
-	    {
-	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
-		  ncdims[ncdimid].dimtype = X_AXIS;
-		  continue;
-		}
-	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
-		  ncdims[ncdimid].dimtype = Y_AXIS;
-		  continue;
-		}
-	    }
+	  printf("coord var %d %s %s\n", ncvarid, ncvars[ncvarid].name, ncvars[ncvarid].units);
+	  if ( ncdims[ncdimid].dimtype == X_AXIS )
+	    printf("coord var %d %s is x dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == Y_AXIS )
+	    printf("coord var %d %s is y dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == Z_AXIS )
+	    printf("coord var %d %s is z dim\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncdims[ncdimid].dimtype == T_AXIS )
+	    printf("coord var %d %s is t dim\n", ncvarid, ncvars[ncvarid].name);
 
-	  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-	    {
-              ncvars[ncvarid].islev = TRUE;
-	      cdfSetVar(ncvars, ncvarid, FALSE);
-	      cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
-	      ncdims[ncdimid].dimtype = Z_AXIS;
-	    }
+	  if ( ncvars[ncvarid].islon )
+	    printf("coord var %d %s is lon\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncvars[ncvarid].islat )
+	    printf("coord var %d %s is lat\n", ncvarid, ncvars[ncvarid].name);
+	  if ( ncvars[ncvarid].islev )
+	    printf("coord var %d %s is lev\n", ncvarid, ncvars[ncvarid].name);
 	}
     }
-}
-
-/* verify coordinate vars - second scan (all other variables) */
-static
-void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
-{
-  int ncvarid;
+  */
 
+  // Set coordinate varids (att: associate)
   for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      if ( ncvars[ncvarid].isvar == 0 )
+      ncvar_t *ncvar = &ncvars[ncvarid];
+      if ( ncvar->isvar == TRUE && ncvar->ncoordvars )
 	{
-	  if ( ncvars[ncvarid].units[0] != 0 )
-	    {
-	      if ( isLonAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  continue;
-		}
-	      else if ( isLatAxis(ncvars[ncvarid].units, ncvars[ncvarid].stdname) )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  continue;
-		}
-	      else if ( unitsIsPressure(ncvars[ncvarid].units) )
-		{
-		  ncvars[ncvarid].zaxistype = ZAXIS_PRESSURE;
-		  continue;
-		}
-	      else if ( strcmp(ncvars[ncvarid].units, "level") == 0 || strcmp(ncvars[ncvarid].units, "1") == 0 )
-		{
-		  if      ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer midpoints") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at midpoints", 25) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID;
-		  else if ( strcmp(ncvars[ncvarid].longname, "hybrid level at layer interfaces") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strncmp(ncvars[ncvarid].longname, "hybrid level at interfaces", 26) == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HYBRID_HALF;
-		  else if ( strcmp(ncvars[ncvarid].units, "level") == 0 )
-		    ncvars[ncvarid].zaxistype = ZAXIS_GENERIC;
-		  continue;
-		}
-	      else if ( isDBLAxis(ncvars[ncvarid].longname) )
-		{
-                  ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_LAND;
-		  continue;
-		}
-	      else if ( unitsIsHeight(ncvars[ncvarid].units) )
-		{
-		  if ( isDepthAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_DEPTH_BELOW_SEA;
-		  else if ( isHeightAxis(ncvars[ncvarid].stdname, ncvars[ncvarid].longname) )
-		    ncvars[ncvarid].zaxistype = ZAXIS_HEIGHT;
-		  continue;
-		}
-            }
-
-	  /* not needed anymore for rotated grids */
-	  if ( ncvars[ncvarid].islon == FALSE && ncvars[ncvarid].longname[0] != 0 &&
-               ncvars[ncvarid].islat == FALSE && ncvars[ncvarid].longname[1] != 0 )
+	  int ncoordvars = ncvar->ncoordvars;
+	  for ( int i = 0; i < ncoordvars; i++ )
 	    {
-	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
-		{
-		  ncvars[ncvarid].islon = TRUE;
-		  continue;
-		}
-	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
-		{
-		  ncvars[ncvarid].islat = TRUE;
-		  continue;
-		}
+	      if      ( ncvars[ncvar->coordvarids[i]].islon ||
+                        ncvars[ncvar->coordvarids[i]].isx )   ncvar->xvarid = ncvar->coordvarids[i];
+	      else if ( ncvars[ncvar->coordvarids[i]].islat ||
+                        ncvars[ncvar->coordvarids[i]].isy )   ncvar->yvarid = ncvar->coordvarids[i];
+	      else if ( ncvars[ncvar->coordvarids[i]].islev ) ncvar->zvarid = ncvar->coordvarids[i];
+	      else if ( ncvars[ncvar->coordvarids[i]].isc )   ncvar->cvarids[i] = ncvar->coordvarids[i];
 	    }
 	}
     }
-}
 
-#if defined (PROJECTION_TEST)
-static
-void copy_numeric_projatts(int gridID, int ncvarID, int ncfileID)
-{
-  int iatt, nvatts;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  nc_type xtype;
+  // set dim type
+  cdf_set_dimtype(nvars, ncvars, ncdims);
 
-  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+  // read ECHAM VCT if present
+  size_t vctsize = 0;
+  double *vct = NULL;
+  if ( !lhybrid_cf ) read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
 
-  for ( iatt = 0; iatt < nvatts; iatt++ )
-    {
-      cdf_inq_attname(ncfileID, ncvarID, iatt, attname);
-      cdf_inq_atttype(ncfileID, ncvarID, attname, &xtype);
-      cdf_inq_attlen(ncfileID, ncvarID, attname, &attlen);
 
-      //  printf("%s %d\n", attname, (int)attlen);
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_define_all_grids");
+
+  // define all grids
+  int status;
+  status = cdf_define_all_grids(streamptr->ncgrid, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+  if ( status < 0 ) return status;
+
+  // define all zaxes
+  status = cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
+  if ( vct ) Free(vct);
+  if ( status < 0 ) return status;
+
+
+  // select vars
+  varids = (int *) Malloc((size_t)nvars * sizeof (int));
+  nvarids = 0;
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    if ( ncvars[ncvarid].isvar == TRUE ) varids[nvarids++] = ncvarid;
+
+  nvars_data = nvarids;
+
+  if ( CDI_Debug ) Message("time varid = %d", streamptr->basetime.ncvarid);
+  if ( CDI_Debug ) Message("ntsteps = %zu", ntsteps);
+  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+
+
+  if ( nvars_data == 0 )
+    {
+      streamptr->ntsteps = 0;
+      return CDI_EUFSTRUCT;
     }
 
-}
-#endif
+  if ( ntsteps == 0 && streamptr->basetime.ncdimid == CDI_UNDEFID && streamptr->basetime.ncvarid != CDI_UNDEFID )
+    ntsteps = 1;
 
-static
-void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
-{
-  if ( ncvar->chunked )
+  streamptr->ntsteps = (long)ntsteps;
+
+  // define all data variables
+  cdf_define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
+
+
+  cdiCreateTimesteps(streamptr);
+
+  // time varID
+  int nctimevarid = streamptr->basetime.ncvarid;
+
+  if ( time_has_units )
     {
-      int ndims = ncvar->ndims;
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
 
-      if ( grid->type == GRID_UNSTRUCTURED )
+      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
         {
-          if ( ncvar->chunks[ndims-1] == grid->size )
-            ncvar->chunktype = CHUNK_GRID;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
+          nctimevarid = CDI_UNDEFID;
+          streamptr->basetime.ncvarid = CDI_UNDEFID;
         }
-      else
+
+      if ( leadtime_id != CDI_UNDEFID && taxis->type == TAXIS_RELATIVE )
         {
-          if ( grid->xsize > 1 && grid->ysize > 1 && ndims > 1 &&
-               grid->xsize == ncvar->chunks[ndims-1] &&
-               grid->ysize == ncvar->chunks[ndims-2] )
-            ncvar->chunktype = CHUNK_GRID;
-          else if ( grid->xsize > 1 && grid->xsize == ncvar->chunks[ndims-1] )
-            ncvar->chunktype = CHUNK_LINES;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
+          streamptr->basetime.leadtimeid = leadtime_id;
+          taxis->type = TAXIS_FORECAST;
+
+          int timeunit = -1;
+          if ( ncvars[leadtime_id].units[0] != 0 ) timeunit = scanTimeUnit(ncvars[leadtime_id].units);
+          if ( timeunit == -1 ) timeunit = taxis->unit;
+          taxis->fc_unit = timeunit;
+
+          setForecastTime(fcreftime, taxis);
         }
     }
-}
 
-static struct gridVirtTable cdfLazyGridVtable;
-static double *cdfPendingLoad;
-#ifdef HAVE_LIBPTHREAD
-static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
-#else
-static bool cdfLazyInitialized;
-#endif
+  if ( time_has_bounds )
+    {
+      streamptr->tsteps[0].taxis.has_bounds = true;
+      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = true;
+    }
 
-struct cdfLazyGrid
-{
-  grid_t base;
-  const struct gridVirtTable *baseVtable;
-  struct {
-    int datasetNCId, varNCId;
-  } cellAreaGet, xBoundsGet, yBoundsGet;
-  struct xyValGet {
-    double scalefactor, addoffset;
-    size_t start[3], count[3], size, dimsize;
-    int datasetNCId, varNCId;
-    short ndims;
-  } xValsGet, yValsGet;
-#ifdef HAVE_LIBPTHREAD
-  pthread_mutex_t loadSerialize;
-#endif
-};
+  if ( nctimevarid != CDI_UNDEFID )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      ptaxisDefName(taxis, ncvars[nctimevarid].name);
 
-#ifdef HAVE_LIBPTHREAD
-#define lock_lazy_load(plGrid) pthread_mutex_lock(&((plGrid)->loadSerialize))
-#define unlock_lazy_load(plGrid) pthread_mutex_unlock(&((plGrid)->loadSerialize))
-#define destroy_lazy_load_lock(plGrid) pthread_mutex_destroy(&((plGrid)->loadSerialize))
-#define init_lazy_load_lock(plGrid) pthread_mutex_init(&((plGrid)->loadSerialize), NULL)
-#else
-#define lock_lazy_load(plGrid)
-#define unlock_lazy_load(plGrid)
-#define destroy_lazy_load_lock(plGrid)
-#define init_lazy_load_lock(plGrid)
+      if ( ncvars[nctimevarid].longname[0] )
+        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+
+      if ( ncvars[nctimevarid].units[0] )
+        ptaxisDefUnits(taxis, ncvars[nctimevarid].units);
+
+      int datatype = (ncvars[nctimevarid].xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
+      ptaxisDefDatatype(taxis, datatype);
+    }
+
+  if ( nctimevarid != CDI_UNDEFID )
+    if ( ncvars[nctimevarid].calendar == true )
+      {
+        char attstring[1024];
+	cdfGetAttText(fileID, nctimevarid, "calendar", sizeof(attstring), attstring);
+	str_tolower(attstring);
+        set_calendar(attstring, &calendar);
+      }
+
+  int taxisID;
+  if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
+    {
+      taxisID = taxisCreate(TAXIS_FORECAST);
+    }
+  else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
+    {
+      taxisID = taxisCreate(TAXIS_RELATIVE);
+    }
+  else
+    {
+      taxisID = taxisCreate(TAXIS_ABSOLUTE);
+      if ( !time_has_units )
+	{
+	  taxisDefTunit(taxisID, TUNIT_DAY);
+	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
+	}
+    }
+
+
+  if ( calendar == CDI_UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
+    {
+      calendar = CALENDAR_STANDARD;
+    }
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wstrict-overflow"
+#endif
+  if ( calendar != CDI_UNDEFID )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      taxis->calendar = calendar;
+      taxisDefCalendar(taxisID, calendar);
+    }
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic pop
 #endif
 
-static void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid)
-{
-  lazyGrid->base.extraData = NULL;
-  if (lazyGrid->base.area == cdfPendingLoad)
-    lazyGrid->base.area = NULL;
-  if (lazyGrid->base.xvals == cdfPendingLoad)
-    lazyGrid->base.xvals = NULL;
-  if (lazyGrid->base.yvals == cdfPendingLoad)
-    lazyGrid->base.yvals = NULL;
-  if (lazyGrid->base.xbounds == cdfPendingLoad)
-    lazyGrid->base.xbounds = NULL;
-  if (lazyGrid->base.ybounds == cdfPendingLoad)
-    lazyGrid->base.ybounds = NULL;
-  destroy_lazy_load_lock(lazyGrid);
-}
+  vlistDefTaxis(vlistID, taxisID);
 
-static void cdfLazyGridDelete(grid_t *grid)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
-  cdfLazyGridDestroy(cdfGrid);
-  baseDestroy(grid);
+  streamptr->curTsID = 0;
+  streamptr->rtsteps = 1;
+
+  (void) cdfInqTimestep(streamptr, 0);
+
+  cdfCreateRecords(streamptr, 0);
+
+  // free ncdims
+  if ( ncdims ) Free(ncdims);
+
+  // free ncvars
+  if ( ncvars ) Free(ncvars);
+
+  return 0;
 }
 
-static void cdfLazyGridDestroyOnce(void)
+static
+void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
 {
-  /*
-#ifdef HAVE_MMAP
-  size_t pgSize = cdiGetPageSize(false);
-  munmap(cdfPendingLoad, pgSize);
-#endif
-  */
+  size_t start[2], count[2];
+  char stvalue[32];
+  start[0] = (size_t) tsID; start[1] = 0;
+  count[0] = 1; count[1] = 19;
+  stvalue[0] = 0;
+  cdf_get_vara_text(fileID, nctimevarid, start, count, stvalue);
+  stvalue[19] = 0;
+  {
+    int year = 1, month = 1, day = 1 , hour = 0, minute = 0, second = 0;
+    if ( strlen(stvalue) == 19 )
+      sscanf(stvalue, "%d-%d-%d_%d:%d:%d", &year, &month, &day, &hour, &minute, &second);
+    taxis->vdate = cdiEncodeDate(year, month, day);
+    taxis->vtime = cdiEncodeTime(hour, minute, second);
+    taxis->type = TAXIS_ABSOLUTE;
+  }
 }
 
-static void
-cdfLazyGridDefArea(grid_t *grid, const double *area)
+static
+double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
 {
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(cdfGrid);
-  if (grid->area == cdfPendingLoad)
-    grid->area = NULL;
-  cdfGrid->cellAreaGet.datasetNCId = -1;
-  cdfGrid->cellAreaGet.varNCId = -1;
-  cdfGrid->baseVtable->defArea(grid, area);
-  unlock_lazy_load(cdfGrid);
+  double timevalue = 0;
+
+  if ( tcache )
+    {
+      if ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
+        {
+          int maxvals = MAX_TIMECACHE_SIZE;
+          tcache->startid = (tsID/MAX_TIMECACHE_SIZE)*MAX_TIMECACHE_SIZE;
+          if ( (tcache->startid + maxvals) > tcache->maxvals ) maxvals = (tcache->maxvals)%MAX_TIMECACHE_SIZE;
+          tcache->size = maxvals;
+          size_t index = (size_t) tcache->startid;
+          // fprintf(stderr, "fill time cache: %d %d %d %d %d\n", tcache->maxvals, tsID, tcache->startid, tcache->startid+maxvals-1, maxvals);
+          for ( int ival = 0; ival < maxvals; ++ival )
+            {
+              cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+              tcache->cache[ival] = timevalue;
+              index++;
+            }
+        }
+
+      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
+    }
+  else
+    {
+      size_t index = (size_t) tsID;
+      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
+      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+    }
+
+  return timevalue;
 }
 
 
-static const double *
-cdfLazyGridInqAreaPtr(grid_t *grid)
+int cdfInqTimestep(stream_t * streamptr, int tsID)
 {
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->area == cdfPendingLoad)
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+
+  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
+
+  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
     {
-      grid->area = (double *)Malloc((size_t)grid->size * sizeof(double));
-      cdf_get_var_double(lazyGrid->cellAreaGet.datasetNCId,
-                         lazyGrid->cellAreaGet.varNCId, grid->area);
+      cdfCreateRecords(streamptr, tsID);
+
+      taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+      if ( tsID > 0 )
+	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
+
+      double timevalue = tsID;
+
+      int nctimevarid = streamptr->basetime.ncvarid;
+      if ( nctimevarid != CDI_UNDEFID )
+	{
+	  int fileID = streamptr->fileID;
+	  size_t index = (size_t)tsID;
+
+	  if ( streamptr->basetime.lwrf )
+	    {
+              wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
+	    }
+	  else
+	    {
+#if defined (USE_TIMECACHE)
+              if ( streamptr->basetime.timevar_cache == NULL )
+                {
+                  streamptr->basetime.timevar_cache = (timecache_t *) Malloc(MAX_TIMECACHE_SIZE*sizeof(timecache_t));
+                  streamptr->basetime.timevar_cache->size = 0;
+                  streamptr->basetime.timevar_cache->maxvals = streamptr->ntsteps;
+                }
+#endif
+              timevalue = get_timevalue(fileID, nctimevarid, tsID, streamptr->basetime.timevar_cache);
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate, &taxis->vtime);
+	    }
+
+	  int nctimeboundsid = streamptr->basetime.ncvarboundsid;
+	  if ( nctimeboundsid != CDI_UNDEFID )
+	    {
+	      size_t start[2], count[2];
+              start[0] = index; count[0] = 1; start[1] = 0; count[1] = 1;
+	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
+
+              start[0] = index; count[0] = 1; start[1] = 1; count[1] = 1;
+	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
+	    }
+
+          int leadtimeid = streamptr->basetime.leadtimeid;
+          if ( leadtimeid != CDI_UNDEFID )
+            {
+              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
+              cdiSetForecastPeriod(timevalue, taxis);
+            }
+	}
     }
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqAreaPtr(grid);
-}
 
-static void
-cdfLazyGridInqArea(grid_t *grid, double *area)
-{
-  grid->vtable->inqAreaPtr(grid);
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lazyGrid->baseVtable->inqArea(grid, area);
+  streamptr->curTsID = tsID;
+  long nrecs = streamptr->tsteps[tsID].nrecs;
+
+  return (int) nrecs;
 }
 
 
-static void
-cdfLazyLoadXYVals(struct xyValGet *valsGet, double **valsp)
+int cdfInqHistorySize(stream_t *streamptr)
 {
-  double *grid_vals
-    = (double *)Malloc(valsGet->size * sizeof (double));
-  *valsp = grid_vals;
-  if ( valsGet->ndims == 3 )
-    cdf_get_vara_double(valsGet->datasetNCId, valsGet->varNCId,
-                        valsGet->start, valsGet->count, grid_vals);
-  else
-    cdf_get_var_double(valsGet->datasetNCId, valsGet->varNCId, grid_vals);
-  scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
-}
+  size_t size = 0;
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
+    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
 
-static const double *
-cdfLazyGridInqXValsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->xvals == cdfPendingLoad)
-    cdfLazyLoadXYVals(&lazyGrid->xValsGet, &grid->xvals);
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqXValsPtr(grid);
+  return (int) size;
 }
 
-static const double *
-cdfLazyGridInqYValsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->yvals == cdfPendingLoad)
-    cdfLazyLoadXYVals(&lazyGrid->yValsGet, &grid->yvals);
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqYValsPtr(grid);
-}
 
-static double
-cdfLazyGridInqXYVal(grid_t *grid, size_t index,
-                    const struct xyValGet *valsGet, double *vals,
-                    const double *(*inqValsPtr)(grid_t *gridptr))
+void cdfInqHistoryString(stream_t *streamptr, char *history)
 {
-  size_t size = valsGet->size;
-  double v;
-  if ( vals == cdfPendingLoad )
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
     {
-      /* prevent full load if only first/last values get inspected */
-      if ( index == 0 || index == size - 1 )
+      nc_type atttype;
+      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
+
+      if ( atttype == NC_CHAR )
         {
-          size_t indexND[3];
-          if ( valsGet->ndims == 3 )
-            {
-              indexND[0] = 0;
-              indexND[1] = index / valsGet->count[2];
-              indexND[2] = index % valsGet->count[2];
-            }
-          else if ( valsGet->ndims == 2)
-            {
-              indexND[0] = index / (size_t)grid->xsize;
-              indexND[1] = index % (size_t)grid->xsize;
-            }
-          else
-            indexND[0] = index;
-          cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId,
-                              indexND, &v);
+          cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
         }
-      else
+#if  defined  (HAVE_NETCDF4)
+      else if ( atttype == NC_STRING )
         {
-          const double *grid_vals = inqValsPtr(grid);
-          v = grid_vals[index];
+          // ToDo
+          Warning("History attribute with type NC_STRING unsupported!");
         }
+#endif
     }
-  else if ( vals )
-    v = vals[index];
-  else
-    v = 0.0;
-  return v;
 }
 
-static void
-cdfLazyGridDefXVals(grid_t *grid, const double *vals)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(cdfGrid);
-  if (grid->xvals == cdfPendingLoad)
-    grid->xvals = NULL;
-  cdfGrid->xValsGet.datasetNCId = -1;
-  cdfGrid->xValsGet.varNCId = -1;
-  cdfGrid->baseVtable->defXVals(grid, vals);
-  unlock_lazy_load(cdfGrid);
-}
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-static void
-cdfLazyGridDefYVals(grid_t *grid, const double *vals)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(cdfGrid);
-  if (grid->yvals == cdfPendingLoad)
-    grid->yvals = NULL;
-  cdfGrid->yValsGet.datasetNCId = -1;
-  cdfGrid->yValsGet.varNCId = -1;
-  cdfGrid->baseVtable->defYVals(grid, vals);
-  unlock_lazy_load(cdfGrid);
-}
+#ifdef HAVE_LIBNETCDF
 
-static double
-cdfLazyGridInqXVal(grid_t *grid, int index)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->xValsGet,
-                                  grid->xvals, grid->vtable->inqXValsPtr);
-  unlock_lazy_load(lazyGrid);
-  return rv;
-}
 
-static double
-cdfLazyGridInqYVal(grid_t *grid, int index)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  double rv = cdfLazyGridInqXYVal(grid, (size_t)index, &lazyGrid->yValsGet,
-                                  grid->yvals, grid->vtable->inqYValsPtr);
-  unlock_lazy_load(lazyGrid);
-  return rv;
-}
 
-static bool
-cdfLazyXYValGetCompare(struct cdfLazyGrid *lazyGridRef,
-                       struct cdfLazyGrid *lazyGridTest)
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
+
+
+static const char bndsName[] = "bnds";
+
+
+void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 {
-  struct xyValGet *valsGetXRef = &lazyGridRef->xValsGet,
-    *valsGetYRef = &lazyGridRef->yValsGet,
-    *valsGetXTest = &lazyGridTest->xValsGet,
-    *valsGetYTest = &lazyGridTest->yValsGet;
-  if (valsGetXRef->datasetNCId == -1
-      || valsGetXTest->datasetNCId == -1
-      || valsGetYRef->datasetNCId == -1
-      || valsGetYTest->datasetNCId == -1)
-    return lazyGridRef->baseVtable->compareXYFull(&lazyGridRef->base,
-                                                  &lazyGridTest->base);
-  return valsGetXRef->datasetNCId != valsGetXTest->datasetNCId
-    ||   valsGetXRef->varNCId     != valsGetXTest->varNCId
-    ||   valsGetYRef->datasetNCId != valsGetYTest->datasetNCId
-    ||   valsGetYRef->varNCId     != valsGetYTest->varNCId;
+  int vlistID1 = streamptr1->vlistID;
+  int tsID     = streamptr1->curTsID;
+  int vrecID   = streamptr1->tsteps[tsID].curRecID;
+  int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
+  int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
+  int gridID   = vlistInqVarGrid(vlistID1, ivarID);
+  size_t datasize = gridInqSize(gridID);
+  int datatype = vlistInqVarDatatype(vlistID1, ivarID);
+  int memtype  = datatype != CDI_DATATYPE_FLT32 ? MEMTYPE_DOUBLE : MEMTYPE_FLOAT;
+
+  void *data = Malloc(datasize * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
+
+  size_t nmiss;
+  cdf_read_record(streamptr1, memtype, data, &nmiss);
+  cdf_write_record(streamptr2, memtype, data, nmiss);
+
+  Free(data);
 }
 
-static bool
-cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
+
+void cdfDefRecord(stream_t *streamptr)
 {
-  bool diff;
-  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
-  if (gridTest->vtable == &cdfLazyGridVtable)
-    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
-  else
-    diff = lazyGridRef->baseVtable->compareXYFull(gridRef, gridTest);
-  return diff;
+  (void)streamptr;
 }
 
-static bool
-cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
+static
+void cdfDefTimeValue(stream_t *streamptr, int tsID)
 {
-  bool diff;
-  struct cdfLazyGrid *lazyGridRef = (struct cdfLazyGrid *)gridRef;
-  if (gridTest->vtable == &cdfLazyGridVtable)
-    diff = cdfLazyXYValGetCompare(lazyGridRef, (struct cdfLazyGrid *)gridTest);
-  else
-    diff = lazyGridRef->baseVtable->compareXYAO(gridRef, gridTest);
-  return diff;
-}
+  int fileID = streamptr->fileID;
+
+  if ( CDI_Debug )
+    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
 
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
-static const double *
-cdfLazyGridInqXBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->xbounds == cdfPendingLoad)
+  if ( streamptr->ncmode == 1 )
     {
-      grid->xbounds = (double *)Malloc((size_t)grid->nvertex
-                                       * (size_t)grid->size * sizeof(double));
-      cdf_get_var_double(lazyGrid->xBoundsGet.datasetNCId,
-                         lazyGrid->xBoundsGet.varNCId, grid->xbounds);
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
     }
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqXBoundsPtr(grid);
-}
 
-static void
-cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(cdfGrid);
-  if (grid->xbounds == cdfPendingLoad)
-    grid->xbounds = NULL;
-  cdfGrid->xBoundsGet.datasetNCId = -1;
-  cdfGrid->xBoundsGet.varNCId = -1;
-  cdfGrid->baseVtable->defXBounds(grid, xbounds);
-  unlock_lazy_load(cdfGrid);
-}
+  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
+  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
 
-static void
-cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(cdfGrid);
-  if (grid->ybounds == cdfPendingLoad)
-    grid->ybounds = NULL;
-  cdfGrid->yBoundsGet.datasetNCId = -1;
-  cdfGrid->yBoundsGet.varNCId = -1;
-  cdfGrid->baseVtable->defYBounds(grid, ybounds);
-  unlock_lazy_load(cdfGrid);
-}
+  int ncvarid = streamptr->basetime.ncvarid;
+  size_t index = (size_t)tsID;
+  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
 
-static const double *
-cdfLazyGridInqYBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->ybounds == cdfPendingLoad)
+  if ( taxis->has_bounds )
     {
-      grid->ybounds = (double *)Malloc((size_t)grid->nvertex
-                                       * (size_t)grid->size * sizeof(double));
-      cdf_get_var_double(lazyGrid->yBoundsGet.datasetNCId,
-                         lazyGrid->yBoundsGet.varNCId, grid->ybounds);
+      ncvarid = streamptr->basetime.ncvarboundsid;
+      if ( ncvarid == CDI_UNDEFID ) Error("Call to taxisWithBounds() missing!");
+
+      timevalue = cdiEncodeTimeval(taxis->vdate_lb, taxis->vtime_lb, &streamptr->tsteps[0].taxis);
+      size_t start[2], count[2];
+      start[0] = (size_t)tsID; count[0] = 1; start[1] = 0; count[1] = 1;
+      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+
+      timevalue = cdiEncodeTimeval(taxis->vdate_ub, taxis->vtime_ub, &streamptr->tsteps[0].taxis);
+      start[0] = (size_t)tsID; count[0] = 1; start[1] = 1; count[1] = 1;
+      cdf_put_vara_double(fileID, ncvarid, start, count, &timevalue);
+    }
+
+  ncvarid = streamptr->basetime.leadtimeid;
+  if ( taxis->type == TAXIS_FORECAST && ncvarid != CDI_UNDEFID )
+    {
+      timevalue = taxis->fc_period;
+      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
     }
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqYBoundsPtr(grid);
 }
 
-static void
-cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+void cdfDefTimestep(stream_t *streamptr, int tsID)
 {
-  struct cdfLazyGrid *lazyGridDup = (struct cdfLazyGrid *)gridptrDup,
-    *lazyGridOrig = (struct cdfLazyGrid *)gridptrOrig;
-  lazyGridOrig->baseVtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
-  lazyGridDup->baseVtable = lazyGridOrig->baseVtable;
-  lazyGridDup->cellAreaGet = lazyGridOrig->cellAreaGet;
-  lazyGridDup->xBoundsGet = lazyGridOrig->xBoundsGet;
-  lazyGridDup->yBoundsGet = lazyGridOrig->yBoundsGet;
-  lazyGridDup->xValsGet = lazyGridOrig->xValsGet;
-  lazyGridDup->yValsGet = lazyGridOrig->yValsGet;
-  init_lazy_load_lock(lazyGridDup);
+  cdfDefTimeValue(streamptr, tsID);
 }
 
-static void
-cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+static
+void cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
 {
-  size_t nrowlon = (size_t)gridptrOrig->nrowlon;
-  size_t gridsize = (size_t)gridptrOrig->size;
-  int gridtype = gridptrOrig->type;
-  int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
-  if ( nrowlon )
+  int dimID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  for ( int index = 0; index < gridindex; ++index )
     {
-      gridptrDup->rowlon = (int *)Malloc(nrowlon * sizeof (int));
-      memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
+      if ( ncgrid[index].ncIDs[CDF_DIMID_X] != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
+            {
+              dimID = ncgrid[index].ncIDs[CDF_DIMID_X];
+              goto dimIDEstablished;
+            }
+        }
     }
 
-  if ( gridptrOrig->xvals != NULL && gridptrOrig->xvals != cdfPendingLoad )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+  {
+    static const char axisname[] = "nc2";
+    size_t dimlen = 2;
+    int fileID  = streamptr->fileID;
+
+    if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+    cdf_def_dim(fileID, axisname, dimlen, &dimID);
+    cdf_enddef(fileID);
+    streamptr->ncmode = 2;
+  }
+  dimIDEstablished:
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+}
 
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
-    }
+struct idSearch
+{
+  int numNonMatching, foundID;
+  size_t foundIdx;
+};
 
-  if ( gridptrOrig->yvals != NULL && gridptrOrig->yvals != cdfPendingLoad )
+static inline struct idSearch
+cdfSearchIDBySize(size_t startIdx, size_t numIDs, const ncgrid_t ncgrid[numIDs],
+                  int ncIDType, int searchType, int searchSize,
+                  int (*typeInq)(int id), size_t (*sizeInq)(int id))
+{
+  int numNonMatching = 0,
+    foundID = CDI_UNDEFID;
+  size_t foundIdx = SIZE_MAX;
+  for ( size_t index = startIdx; index < numIDs; index++ )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
-
-      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
+      if ( ncgrid[index].ncIDs[ncIDType] != CDI_UNDEFID )
+        {
+          int id0 = ncgrid[index].gridID,
+            id0Type = typeInq(id0);
+          if ( id0Type == searchType )
+            {
+              int size0 = sizeInq(id0);
+              if ( searchSize == size0 )
+                {
+                  foundID = ncgrid[index].ncIDs[ncIDType];
+                  foundIdx = index;
+                  break;
+                }
+              numNonMatching++;
+            }
+        }
     }
+  return (struct idSearch){ .numNonMatching = numNonMatching,
+      .foundID = foundID, .foundIdx = foundIdx };
+}
 
-  if ( gridptrOrig->xbounds != NULL && gridptrOrig->xbounds != cdfPendingLoad )
-    {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
-        * (size_t)gridptrOrig->nvertex;
+static size_t
+cdfGridInqHalfSize(int gridID)
+{
+  return gridInqSize(gridID)/2;
+}
 
-      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
-    }
 
-  if ( gridptrOrig->ybounds != NULL && gridptrOrig->ybounds != cdfPendingLoad )
-    {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
-        * (size_t)gridptrOrig->nvertex;
+static void
+cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex,
+             char *restrict axisname, int gridRefType)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
-    }
+  size_t dimlen = gridInqSize(gridID)/2;
 
+  int iz;
+  int dimID;
   {
-    if ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
-      {
-        size_t size = gridsize;
-
-        gridptrDup->area = (double *)Malloc(size * sizeof (double));
-        memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
-      }
+    struct idSearch search
+      = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y,
+                          gridRefType, (int)dimlen,
+                          gridInqType, cdfGridInqHalfSize);
+    dimID = search.foundID;
+    iz = search.numNonMatching;
   }
 
-  if ( gridptrOrig->mask != NULL )
+  if ( dimID == CDI_UNDEFID )
     {
-      size_t size = gridsize;
+      int fileID  = streamptr->fileID;
+      if ( iz == 0 ) axisname[3] = '\0';
+      else           sprintf(&axisname[3], "%1d", iz+1);
 
-      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
-      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
-    }
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  if ( gridptrOrig->mask_gme != NULL )
-    {
-      size_t size = gridsize;
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
-      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
     }
-}
 
-static grid_t *
-cdfLazyGridCopy(grid_t *gridptrOrig)
-{
-  struct cdfLazyGrid *lazyGridDup
-    = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
-  gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
-  gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
-  return &lazyGridDup->base;
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID;
 }
 
-static void
-cdfLazyGridInitOnce(void)
+static
+void cdfDefSP(stream_t *streamptr, int gridID, int gridindex)
 {
-  cdfLazyGridVtable = cdiGridVtable;
-  cdfLazyGridVtable.destroy = cdfLazyGridDelete;
-  cdfLazyGridVtable.copy = cdfLazyGridCopy;
-  cdfLazyGridVtable.copyScalarFields = cdfLazyGridCopyScalarFields;
-  cdfLazyGridVtable.copyArrayFields = cdfLazyGridCopyArrayFields;
-  cdfLazyGridVtable.defArea = cdfLazyGridDefArea;
-  cdfLazyGridVtable.inqAreaPtr = cdfLazyGridInqAreaPtr;
-  cdfLazyGridVtable.inqArea = cdfLazyGridInqArea;
-  cdfLazyGridVtable.inqXValsPtr = cdfLazyGridInqXValsPtr;
-  cdfLazyGridVtable.inqYValsPtr = cdfLazyGridInqYValsPtr;
-  cdfLazyGridVtable.inqXVal = cdfLazyGridInqXVal;
-  cdfLazyGridVtable.inqYVal = cdfLazyGridInqYVal;
-  cdfLazyGridVtable.defXVals = cdfLazyGridDefXVals;
-  cdfLazyGridVtable.defYVals = cdfLazyGridDefYVals;
-  cdfLazyGridVtable.compareXYFull = cdfLazyCompareXYFull;
-  cdfLazyGridVtable.compareXYAO = cdfLazyCompareXYAO;
-  cdfLazyGridVtable.defXBounds = cdfLazyGridDefXBounds;
-  cdfLazyGridVtable.defYBounds = cdfLazyGridDefYBounds;
-  cdfLazyGridVtable.inqXBoundsPtr = cdfLazyGridInqXBoundsPtr;
-  cdfLazyGridVtable.inqYBoundsPtr = cdfLazyGridInqYBoundsPtr;
-  /* create inaccessible memory area, if possible, this serves as
-   * dummy value for pointers to data not yet loaded */
   /*
-#ifdef HAVE_MMAP
-  {
-    size_t pgSize = cdiGetPageSize(false);
-    static const char devZero[] = "/dev/zero";
-    int fd = open(devZero, O_RDWR);
-    if (fd == -1)
-      SysError("Could not open %s to map anonymous memory", devZero);
-    void *cdfInvalid = mmap(NULL, pgSize, PROT_NONE, MAP_PRIVATE, fd, 0);
-    if (cdfInvalid == MAP_FAILED)
-      SysError("Could not mmap anonymous memory");
-    cdfPendingLoad = cdfInvalid;
-    int rc = close(fd);
-    if (rc == -1)
-      SysError("Could not close %s file handle %d after mapping anonymous"
-               " memory", devZero, fd);
-  }
-#else
+  char longname[] = "Spherical harmonic coefficient";
   */
-  cdfPendingLoad = (double *)&cdfPendingLoad;
-  //#endif
-  atexit(cdfLazyGridDestroyOnce);
-#ifndef HAVE_LIBPTHREAD
-  cdfLazyInitialized = true;
-#endif
+  char axisname[5] = "nspX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_SPECTRAL);
 }
 
-static void
-cdfBaseGridInit(grid_t *grid, int gridtype)
+
+static
+void cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
 {
-  grid_init(grid);
-  cdiGridTypeInit(grid, gridtype, 0);
+  char axisname[5] = "nfcX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_FOURIER);
 }
 
-static void
-cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
+static const struct cdfDefGridAxisInqs {
+  size_t (*axisSize)(int gridID);
+  int (*axisDimname)(int cdiID, int key, int size, char *mesg);
+  int (*axisName)(int cdiID, int key, int size, char *mesg);
+  int (*axisLongname)(int cdiID, int key, int size, char *mesg);
+  int (*axisUnits)(int cdiID, int key, int size, char *mesg);
+  void (*axisStdname)(int cdiID, char *dimstdname);
+  double (*axisVal)(int gridID, size_t index);
+  const double *(*axisValsPtr)(int gridID);
+  const double *(*axisBoundsPtr)(int gridID);
+} gridInqsX = {
+  .axisSize = gridInqXsize,
+  .axisDimname = cdiGridInqKeyStr,
+  .axisName = cdiGridInqKeyStr,
+  .axisLongname = cdiGridInqKeyStr,
+  .axisUnits = cdiGridInqKeyStr,
+  .axisStdname = gridInqXstdname,
+  .axisVal = gridInqXval,
+  .axisValsPtr = gridInqXvalsPtr,
+  .axisBoundsPtr = gridInqXboundsPtr,
+}, gridInqsY = {
+  .axisSize = gridInqYsize,
+  .axisDimname = cdiGridInqKeyStr,
+  .axisName = cdiGridInqKeyStr,
+  .axisLongname = cdiGridInqKeyStr,
+  .axisUnits = cdiGridInqKeyStr,
+  .axisStdname = gridInqYstdname,
+  .axisVal = gridInqYval,
+  .axisValsPtr = gridInqYvalsPtr,
+  .axisBoundsPtr = gridInqYboundsPtr,
+}, gridInqsZ = {
+  .axisLongname = cdiZaxisInqKeyStr,
+  .axisUnits = cdiZaxisInqKeyStr,
+  .axisStdname = zaxisInqStdname,
+};
+
+static
+void cdfPutGridStdAtts(int fileID, int ncvarid, int gridID, int dimtype, const struct cdfDefGridAxisInqs *inqs)
 {
-#ifdef HAVE_LIBPTHREAD
-  pthread_once(&cdfLazyInitialized, cdfLazyGridInitOnce);
-#else
-  if (cdfLazyInitialized) ; else cdfLazyGridInitOnce();
-#endif
-  cdfBaseGridInit(&grid->base, gridtype);
-  grid->baseVtable = grid->base.vtable;
-  grid->cellAreaGet.datasetNCId = -1;
-  grid->cellAreaGet.varNCId = -1;
-  grid->xValsGet.datasetNCId = -1;
-  grid->xValsGet.varNCId = -1;
-  grid->yValsGet.datasetNCId = -1;
-  grid->yValsGet.varNCId = -1;
-  grid->xBoundsGet.datasetNCId = -1;
-  grid->xBoundsGet.varNCId = -1;
-  grid->yBoundsGet.datasetNCId = -1;
-  grid->yBoundsGet.varNCId = -1;
-  grid->base.vtable = &cdfLazyGridVtable;
-  init_lazy_load_lock(grid);
+  size_t len;
+
+  char stdname[CDI_MAX_NAME];
+  inqs->axisStdname(gridID, stdname);
+  if ( (len = strlen(stdname)) )
+    cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
+
+  char longname[CDI_MAX_NAME]; longname[0] = 0;
+  int keyname = (dimtype == 'Z') ? CDI_KEY_LONGNAME : (dimtype == 'X') ? CDI_KEY_XLONGNAME : CDI_KEY_YLONGNAME;
+  inqs->axisLongname(gridID, keyname, CDI_MAX_NAME, longname);
+  if ( longname[0] && (len = strlen(longname)) )
+    cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
+
+  char units[CDI_MAX_NAME]; units[0] = 0;
+  keyname = (dimtype == 'Z') ? CDI_KEY_UNITS : (dimtype == 'X') ? CDI_KEY_XUNITS : CDI_KEY_YUNITS;
+  inqs->axisUnits(gridID, keyname, CDI_MAX_NAME, units);
+  if ( units[0] && (len = strlen(units)) )
+    cdf_put_att_text(fileID, ncvarid, "units", len, units);
 }
 
 static void
-cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex,
+                 const struct cdfDefGridAxisInqs *inqs, int dimtype)
 {
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
-  cdfLazyGridInit(grid, gridtype);
+  nc_type xtype = (gridInqDatatype(gridID) == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  size_t dimlen = inqs->axisSize(gridID);
+  if ( dimlen != 1 )
+    Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID)));
+
+  int ncvarid = ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y];
+
+  if ( ncvarid == CDI_UNDEFID )
+    {
+      int dimNcID = streamptr->basetime.ncvarid;
+      int fileID  = streamptr->fileID;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      char axisname[CDI_MAX_NAME]; axisname[0] = 0;
+      int keyname = (dimtype == 'X') ? CDI_KEY_XNAME : CDI_KEY_YNAME;
+      inqs->axisName(gridID, keyname, CDI_MAX_NAME, axisname);
+      cdf_def_var(fileID, axisname, xtype, 1, &dimNcID, &ncvarid);
+      cdfPutGridStdAtts(fileID, ncvarid, gridID, dimtype, inqs);
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  /* var ID for trajectory !!! */
+  ncgrid[gridindex].ncIDs[dimtype == 'X' ? CDF_DIMID_X : CDF_DIMID_Y] = ncvarid;
 }
 
-static void
-cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+static
+void cdfDefTrajLon(stream_t *streamptr, int gridID, int gridindex)
 {
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
-  cdfBaseGridInit((grid_t*)grid, gridtype);
+  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsX, 'X');
+}
+
+
+static
+void cdfDefTrajLat(stream_t *streamptr, int gridID, int gridindex)
+{
+  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsY, 'Y');
 }
 
+static
+int checkDimName(int fileID, size_t dimlen, char *dimname)
+{
+  /* check whether the dimenion name is already defined with the same length */
+  unsigned iz = 0;
+  int dimid = CDI_UNDEFID;
+  char name[CDI_MAX_NAME];
+
+  size_t len = strlen(dimname);
+  memcpy(name, dimname, len + 1);
+
+  do
+    {
+      if ( iz ) sprintf(name + len, "_%u", iz+1);
+
+      int dimid0, status = nc_inq_dimid(fileID, name, &dimid0);
+      if ( status != NC_NOERR )
+        break;
+      size_t dimlen0;
+      cdf_inq_dimlen(fileID, dimid0, &dimlen0);
+      if ( dimlen0 == dimlen )
+        {
+          dimid = dimid0;
+          break;
+        }
+      iz++;
+    }
+  while ( iz <= 99 );
+
+
+  if ( iz ) sprintf(dimname + len, "_%u", iz+1);
+
+  return dimid;
+}
 
-/* define all input grids */
 static
-void define_all_grids(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars, int timedimid, unsigned char *uuidOfHGrid, char *gridfile, int number_of_grid_used)
+void checkGridName(char *axisname, int fileID)
 {
-  int ltwarn = TRUE;
-  struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
-#define grid (&lazyGrid->base)
-#define proj (&lazyProj->base)
+  int ncdimid;
+  char axisname2[CDI_MAX_NAME];
 
-  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
+  /* check that the name is not already defined */
+  unsigned iz = 0;
+
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
     {
-      if ( ncvars[ncvarid].isvar && ncvars[ncvarid].gridID == UNDEFID )
-	{
-          int xdimids[2] = {-1,-1}, ydimids[2] = {-1,-1};
-	  int xdimid = -1, ydimid = -1;
-          int vdimid = -1;
-	  int islon = 0, islat = 0;
-	  int nxdims = 0, nydims = 0;
-          size_t size = 0;
-          size_t xsize = 0, ysize = 0;
-	  double yinc = 0;
-          struct addIffNewRes projAdded = { .Id = CDI_UNDEFID, .isNew = 0 },
-            gridAdded  = { .Id = CDI_UNDEFID, .isNew = 0 };
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
 
-	  int ndims = ncvars[ncvarid].ndims;
-	  for ( int i = 0; i < ndims; i++ )
-	    {
-	      if ( ncvars[ncvarid].dimtype[i] == X_AXIS && nxdims < 2 )
-		{
-		  xdimids[nxdims] = ncvars[ncvarid].dimids[i];
-		  nxdims++;
-		}
-	      else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS && nydims < 2 )
-		{
-		  ydimids[nydims] = ncvars[ncvarid].dimids[i];
-		  nydims++;
-		}
-	    }
+      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
+      if ( status != NC_NOERR ) break;
 
-	  if ( nxdims == 2 )
-	    {
-	      xdimid = xdimids[1];
-	      ydimid = xdimids[0];
-	    }
-	  else if ( nydims == 2 )
-	    {
-	      xdimid = ydimids[1];
-	      ydimid = ydimids[0];
-	    }
-	  else
-	    {
-	      xdimid = xdimids[0];
-	      ydimid = ydimids[0];
-	    }
+      ++iz;
+    }
+  while ( iz <= 99 );
 
-	  int xvarid = ncvars[ncvarid].xvarid != UNDEFID
-	    ? ncvars[ncvarid].xvarid
-            : (xdimid != UNDEFID ? ncdims[xdimid].ncvarid : -1);
-          int yvarid = ncvars[ncvarid].yvarid != UNDEFID
-            ? ncvars[ncvarid].yvarid
-            : (ydimid != UNDEFID ? ncdims[ydimid].ncvarid : -1);
+  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
+}
 
-	  /*
-	  if ( xdimid != UNDEFID )
-	    xvarid = ncdims[xdimid].ncvarid;
-	  if ( xvarid == UNDEFID && ncvars[ncvarid].xvarid != UNDEFID )
-	    xvarid = ncvars[ncvarid].xvarid;
-
-	  if ( ydimid != UNDEFID )
-	    yvarid = ncdims[ydimid].ncvarid;
-	  if ( yvarid == UNDEFID && ncvars[ncvarid].yvarid != UNDEFID )
-	    yvarid = ncvars[ncvarid].yvarid;
-	  */
+static
+int checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
+{
+  char axisname2[CDI_MAX_NAME];
 
-	  if ( xdimid != UNDEFID ) xsize = ncdims[xdimid].len;
-	  if ( ydimid != UNDEFID ) ysize = ncdims[ydimid].len;
+  /* check that the name is not already defined */
+  unsigned iz = 0;
 
-	  if ( ydimid == UNDEFID && yvarid != UNDEFID )
-	    {
-	      if ( ncvars[yvarid].ndims == 1 )
-		{
-		  ydimid = ncvars[yvarid].dimids[0];
-		  ysize  = ncdims[ydimid].len;
-		}
-	    }
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
+    {
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
 
-	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
+      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
 
-          if (CDI_netcdf_lazy_grid_load)
-            {
-              cdfLazyGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
-            }
-          else
+      if ( status != NC_NOERR )
+        {
+          if ( iz )
             {
-              cdfBaseGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
+              /* check that the name does not exist for other zaxes */
+              for ( int index = 0; index < nzaxis; index++ )
+                {
+                  int zaxisID0 = vlistZaxis(vlistID, index);
+                  if ( zaxisID != zaxisID0 )
+                    {
+                      const char *axisname0 = zaxisInqNamePtr(zaxisID0);
+                      if ( strcmp(axisname0, axisname2) == 0 ) goto nextSuffix;
+                    }
+                }
             }
+          break;
+        }
+      nextSuffix:
+      ++iz;
+    }
+  while (iz <= 99);
 
-	  grid->prec  = DATATYPE_FLT64;
-	  grid->trunc = ncvars[ncvarid].truncation;
 
-	  if ( ncvars[ncvarid].gridtype == GRID_TRAJECTORY )
-	    {
-	      if ( ncvars[ncvarid].xvarid == UNDEFID )
-		Error("Longitude coordinate undefined for %s!", ncvars[ncvarid].name);
-	      if ( ncvars[ncvarid].yvarid == UNDEFID )
-		Error("Latitude coordinate undefined for %s!", ncvars[ncvarid].name);
-	    }
-	  else
-	    {
-	      size_t start[3], count[3];
-	      int ltgrid = FALSE;
+  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
 
-	      if ( xvarid != UNDEFID && yvarid != UNDEFID )
-		{
-		  if ( ncvars[xvarid].ndims != ncvars[yvarid].ndims )
-		    {
-		      Warning("Inconsistent grid structure for variable %s!", ncvars[ncvarid].name);
-		      ncvars[ncvarid].xvarid = UNDEFID;
-		      ncvars[ncvarid].yvarid = UNDEFID;
-		      xvarid = UNDEFID;
-		      yvarid = UNDEFID;
-		    }
+  return (int)iz;
+}
 
-		  if ( ncvars[xvarid].ndims > 2 || ncvars[yvarid].ndims > 2 )
-		    {
-		      if ( ncvars[xvarid].ndims == 3 && ncvars[xvarid].dimids[0] == timedimid &&
-			   ncvars[yvarid].ndims == 3 && ncvars[yvarid].dimids[0] == timedimid )
-			{
-			  if ( ltwarn )
-			    Warning("Time varying grids unsupported, using grid at time step 1!");
-			  ltgrid = TRUE;
-			  ltwarn = FALSE;
-			  start[0] = start[1] = start[2] = 0;
-			  count[0] = 1; count[1] = ysize; count[2] = xsize;
-			}
-		      else
-			{
-			  Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvars[ncvarid].name);
-			  ncvars[ncvarid].xvarid = UNDEFID;
-			  ncvars[ncvarid].yvarid = UNDEFID;
-			  xvarid = UNDEFID;
-			  yvarid = UNDEFID;
-			}
-		    }
-		}
+static void
+cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims,
+                 const struct cdfDefGridAxisInqs *gridAxisInq, int dimKey, char axisLetter,
+                 void (*finishCyclicBounds)(double *pbounds, size_t dimlen, const double *pvals))
+{
+  int dimID = CDI_UNDEFID;
+  int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  int fileID  = streamptr->fileID;
+  size_t dimlen = gridAxisInq->axisSize(gridID);
+  nc_type xtype = (nc_type)cdfDefDatatype(gridInqDatatype(gridID), streamptr->filetype);
 
-              if ( xvarid != UNDEFID )
-                {
-                  if ( ncvars[xvarid].ndims > 3 || (ncvars[xvarid].ndims == 3 && ltgrid == FALSE) )
-                    {
-                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[xvarid].name, ncvars[xvarid].ndims);
-                      //ncvars[ncvarid].xvarid = UNDEFID;
-                      xvarid = UNDEFID;
-                    }
-                }
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  const double *pvals = gridAxisInq->axisValsPtr(gridID);
+  char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
+  if ( ndims && pvals == NULL ) cdiGridInqKeyStr(gridID, dimKey, CDI_MAX_NAME, dimname);
 
-              if ( yvarid != UNDEFID )
+  for ( int index = 0; index < gridindex; ++index )
+    {
+      int gridID0 = ncgrid[index].gridID;
+      assert(gridID0 != CDI_UNDEFID);
+      int gridtype0 = gridInqType(gridID0);
+      if ( gridtype0 == GRID_GAUSSIAN    ||
+           gridtype0 == GRID_LONLAT      ||
+           gridtype0 == GRID_PROJECTION  ||
+           gridtype0 == GRID_CURVILINEAR ||
+           gridtype0 == GRID_GENERIC )
+        {
+          size_t dimlen0 = gridAxisInq->axisSize(gridID0);
+          char dimname0[CDI_MAX_NAME]; dimname0[0] = 0;
+          if ( dimname[0] ) cdiGridInqKeyStr(gridID0, dimKey, CDI_MAX_NAME, dimname0);
+          bool lname = dimname0[0] ? strcmp(dimname, dimname0) == 0 : true;
+          if ( dimlen == dimlen0 && lname )
+            {
+              double (*inqVal)(int gridID, size_t index) = gridAxisInq->axisVal;
+              if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) &&
+                   IS_EQUAL(inqVal(gridID0, dimlen-1), inqVal(gridID, dimlen-1)) )
                 {
-                  if ( ncvars[yvarid].ndims > 3 || (ncvars[yvarid].ndims == 3 && ltgrid == FALSE) )
-                    {
-                      Warning("Coordinate variable %s has to many dimensions (%d), skipped!", ncvars[yvarid].name, ncvars[yvarid].ndims);
-                      //ncvars[ncvarid].yvarid = UNDEFID;
-                      yvarid = UNDEFID;
-                    }
+                  dimID = ncgrid[index].ncIDs[dimKey == CDI_KEY_XDIMNAME
+                                              ? CDF_DIMID_X : CDF_DIMID_Y];
+                  break;
                 }
+            }
+        }
+    }
 
-              if ( xvarid != UNDEFID )
-		{
-                  bool skipvar = true;
-		  islon = ncvars[xvarid].islon;
-		  ndims = ncvars[xvarid].ndims;
-		  if ( ndims == 2 || ndims == 3 )
-		    {
-		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-		      size = xsize*ysize;
-		      /* Check size of 2 dimensional coordinate variables */
-                      int dimid = ncvars[xvarid].dimids[ndims-2];
-                      size_t dimsize1 = ncdims[dimid].len;
-                      dimid = ncvars[xvarid].dimids[ndims-1];
-                      size_t dimsize2 = ncdims[dimid].len;
-                      skipvar = dimsize1*dimsize2 != size;
-		    }
-		  else if ( ndims == 1 )
-		    {
-		      size = xsize;
-		      /* Check size of 1 dimensional coordinate variables */
-                      int dimid = ncvars[xvarid].dimids[0];
-                      size_t dimsize = ncdims[dimid].len;
-                      skipvar = dimsize != size;
-		    }
-		  else if ( ndims == 0 && xsize == 0 )
-		    {
-                      size = xsize = 1;
-                      skipvar = false;
-		    }
+  if ( dimID == CDI_UNDEFID )
+    {
+      char axisname[CDI_MAX_NAME]; axisname[0] = 0;
+      int keyname = (axisLetter == 'X') ? CDI_KEY_XNAME : CDI_KEY_YNAME;
+      gridAxisInq->axisName(gridID, keyname, CDI_MAX_NAME, axisname);
+      if ( axisname[0] == 0 ) Error("axis name undefined!");
+      size_t axisnameLen = strlen(axisname);
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+      /* enough to append _ plus up to 100 decimal and trailing \0 */
+      char extendedAxisname[axisnameLen + 4 + 1];
+      memcpy(extendedAxisname, axisname, axisnameLen + 1);
+      checkGridName(extendedAxisname, fileID);
+      size_t extendedAxisnameLen = axisnameLen + strlen(extendedAxisname + axisnameLen);
 
-		  if ( ncvars[xvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
-                  if (CDI_netcdf_lazy_grid_load)
-                    {
-                      lazyGrid->xValsGet = (struct xyValGet){
-                        .scalefactor = ncvars[xvarid].scalefactor,
-                        .addoffset = ncvars[xvarid].addoffset,
-                        .start = { start[0], start[1], start[2] },
-                        .count = { count[0], count[1], count[2] },
-                        .size = size,
-                        .datasetNCId = ncvars[xvarid].ncid,
-                        .varNCId = xvarid,
-                        .ndims = (short)ndims,
-                      };
-                      grid->xvals = cdfPendingLoad;
-                    }
-                  else
-                    {
-                      grid->xvals = (double *) Malloc(size*sizeof(double));
-                      if ( ltgrid )
-                        cdf_get_vara_double(ncvars[xvarid].ncid, xvarid,
-                                            start, count, grid->xvals);
-                      else
-                        cdf_get_var_double(ncvars[xvarid].ncid, xvarid,
-                                           grid->xvals);
-                      scale_add(size, grid->xvals,
-                                ncvars[xvarid].addoffset,
-                                ncvars[xvarid].scalefactor);
-                    }
-		  strcpy(grid->xname, ncvars[xvarid].name);
-		  strcpy(grid->xlongname, ncvars[xvarid].longname);
-		  strcpy(grid->xunits, ncvars[xvarid].units);
-		  /* don't change the name !!! */
-		  /*
-		  if ( (len = strlen(grid->xname)) > 2 )
-		    if ( grid->xname[len-2] == '_' && isdigit((int) grid->xname[len-1]) )
-		      grid->xname[len-2] = 0;
-		  */
-		}
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	      if ( yvarid != UNDEFID )
-		{
-                  bool skipvar = true;
-		  islat = ncvars[yvarid].islat;
-		  ndims = ncvars[yvarid].ndims;
-		  if ( ndims == 2 || ndims == 3 )
-		    {
-		      ncvars[ncvarid].gridtype = GRID_CURVILINEAR;
-		      size = xsize*ysize;
-		      /* Check size of 2 dimensional coordinate variables */
-		      {
-			int dimid;
-			size_t dimsize1, dimsize2;
-			dimid = ncvars[yvarid].dimids[ndims-2];
-			dimsize1 = ncdims[dimid].len;
-			dimid = ncvars[yvarid].dimids[ndims-1];
-			dimsize2 = ncdims[dimid].len;
-			skipvar = dimsize1*dimsize2 != size;
-		      }
-		    }
-		  else if ( ndims == 1 )
-		    {
-		      if ( (int) ysize == 0 ) size = xsize;
-		      else                    size = ysize;
-
-		      /* Check size of 1 dimensional coordinate variables */
-		      {
-			int dimid;
-			size_t dimsize;
-			dimid = ncvars[yvarid].dimids[0];
-			dimsize = ncdims[dimid].len;
-			skipvar = dimsize != size;
-		      }
-		    }
-		  else if ( ndims == 0 && ysize == 0 )
-		    {
-                      size = ysize = 1;
-                      skipvar = false;
-		    }
+      if ( ndims )
+        {
+          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
+          dimID = checkDimName(fileID, dimlen, dimname);
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+          if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+        }
 
-		  if ( ncvars[yvarid].xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
-                  /* see below for when it's impossible to operate
-                   * without y values */
-                  if ( !CDI_netcdf_lazy_grid_load
-                       || ((ncvars[ncvarid].gridtype == UNDEFID ||
-                            ncvars[ncvarid].gridtype == GRID_GENERIC)
-                           && islat && (islon || xsize == 0)) )
-                    {
-                      grid->yvals = (double *) Malloc(size*sizeof(double));
-
-                      if ( ltgrid )
-                        cdf_get_vara_double(ncvars[yvarid].ncid, yvarid, start, count, grid->yvals);
-                      else
-                        cdf_get_var_double(ncvars[yvarid].ncid, yvarid, grid->yvals);
-
-                      scale_add(size, grid->yvals, ncvars[yvarid].addoffset, ncvars[yvarid].scalefactor);
-
-                      /* don't change the name !!! */
-                      /*
-                        if ( (len = strlen(grid->yname)) > 2 )
-                        if ( grid->yname[len-2] == '_' && isdigit((int) grid->yname[len-1]) )
-                        grid->yname[len-2] = 0;
-                      */
-                      if ( islon && (int) ysize > 1 )
-                        {
-                          yinc = fabs(grid->yvals[0] - grid->yvals[1]);
-                          for ( size_t i = 2; i < ysize; i++ )
-                            if ( (fabs(grid->yvals[i-1] - grid->yvals[i]) - yinc) > (yinc/1000) )
-                              {
-                                yinc = 0;
-                                break;
-                              }
-                        }
-                    }
-                  else
-                    {
-                      lazyGrid->yValsGet = (struct xyValGet){
-                        .scalefactor = ncvars[yvarid].scalefactor,
-                        .addoffset = ncvars[yvarid].addoffset,
-                        .start = { start[0], start[1], start[2] },
-                        .count = { count[0], count[1], count[2] },
-                        .size = size,
-                        .datasetNCId = ncvars[yvarid].ncid,
-                        .varNCId = yvarid,
-                        .ndims = (short)ndims,
-                      };
-                      grid->yvals = cdfPendingLoad;
-                    }
-                  strcpy(grid->yname, ncvars[yvarid].name);
-                  strcpy(grid->ylongname, ncvars[yvarid].longname);
-                  strcpy(grid->yunits, ncvars[yvarid].units);
-		}
+      bool gen_bounds = false;
+      bool grid_is_cyclic = gridIsCircular(gridID) > 0;
+      double *pbounds = NULL;
+      if ( pvals )
+        {
+          cdf_def_var(fileID, extendedAxisname, xtype, ndims, &dimID, &ncvarid);
 
-	      if      ( (int) ysize == 0 ) size = xsize;
-	      else if ( (int) xsize == 0 ) size = ysize;
-	      else if ( ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED ) size = xsize;
-	      else                         size = xsize*ysize;
-	    }
+          cdfPutGridStdAtts(fileID, ncvarid, gridID, axisLetter, gridAxisInq);
+          {
+            char axisStr[2] = { axisLetter, '\0' };
+            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
+          }
 
-	  if ( ncvars[ncvarid].gridtype == UNDEFID ||
-	       ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    {
-	      if ( islat && (islon || xsize == 0) )
-		{
-		  if ( isGaussGrid(ysize, yinc, grid->yvals) )
-                    {
-                      ncvars[ncvarid].gridtype = GRID_GAUSSIAN;
-                      grid->np = (int)(ysize/2);
-                    }
-                  else
-		    ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else if ( islon && !islat && ysize == 0 )
-		{
-		  ncvars[ncvarid].gridtype = GRID_LONLAT;
-		}
-	      else
-		ncvars[ncvarid].gridtype = GRID_GENERIC;
-	    }
+          size_t nvertex = gridInqNvertex(gridID);
+          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
 
-	  switch (ncvars[ncvarid].gridtype)
-	    {
-	    case GRID_GENERIC:
-	    case GRID_LONLAT:
-	    case GRID_GAUSSIAN:
-	    case GRID_UNSTRUCTURED:
-	    case GRID_CURVILINEAR:
-	      {
-		grid->size  = (int)size;
-		grid->xsize = (int)xsize;
-		grid->ysize = (int)ysize;
-		if ( xvarid != UNDEFID )
-		  {
-		    grid->xdef  = 1;
-		    if ( ncvars[xvarid].bounds != UNDEFID )
-		      {
-			int nbdims = ncvars[ncvars[xvarid].bounds].ndims;
-			if ( nbdims == 2 || nbdims == 3 )
-			  {
-                            vdimid = ncvars[ncvars[xvarid].bounds].dimids[nbdims-1];
-			    size_t nvertex = ncdims[vdimid].len;
-			    grid->nvertex = (int)nvertex;
-                            if (CDI_netcdf_lazy_grid_load)
-                              {
-                                lazyGrid->xBoundsGet.datasetNCId
-                                  = ncvars[xvarid].ncid;
-                                lazyGrid->xBoundsGet.varNCId
-                                  = ncvars[xvarid].bounds;
-                                grid->xbounds = cdfPendingLoad;
-                              }
-                            else
-                              {
-                                grid->xbounds
-                                  = (double *)Malloc(nvertex * size
-                                                     * sizeof(double));
-                                cdf_get_var_double(ncvars[xvarid].ncid,
-                                                   ncvars[xvarid].bounds,
-                                                   grid->xbounds);
-                              }
-			  }
-		      }
-		  }
-		if ( yvarid != UNDEFID )
-		  {
-		    grid->ydef  = 1;
-		    if ( ncvars[yvarid].bounds != UNDEFID )
-		      {
-			int nbdims = ncvars[ncvars[yvarid].bounds].ndims;
-			if ( nbdims == 2 || nbdims == 3 )
-			  {
-			    /* size_t nvertex = ncdims[ncvars[ncvars[yvarid].bounds].dimids[nbdims-1]].len;
-			    if ( nvertex != grid->nvertex )
-			      Warning("nvertex problem! nvertex x %d, nvertex y %d",
-				      grid->nvertex, (int) nvertex);
-			    */
-                            if (CDI_netcdf_lazy_grid_load)
-                              {
-                                lazyGrid->yBoundsGet.datasetNCId
-                                  = ncvars[yvarid].ncid;
-                                lazyGrid->yBoundsGet.varNCId
-                                  = ncvars[yvarid].bounds;
-                                grid->ybounds = cdfPendingLoad;
-                              }
-                            else
-                              {
-                                vdimid = ncvars[ncvars[yvarid].bounds].dimids[nbdims-1];
-                                size_t nvertex = ncdims[vdimid].len;
-                                /*
-                                  if ( nvertex != grid->nvertex )
-                                  Warning("nvertex problem! nvertex x %d, nvertex y %d",
-                                  grid->nvertex, (int) nvertex);
-                                */
-                                grid->ybounds
-                                  = (double *)Malloc(nvertex * size
-                                                     * sizeof(double));
-                                cdf_get_var_double(ncvars[yvarid].ncid,
-                                                   ncvars[yvarid].bounds,
-                                                   grid->ybounds);
-                              }
-			  }
-		      }
-		  }
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = true;
+              nvertex = 2;
+              pbounds = (double*) Malloc(2*dimlen*sizeof(double));
+              for ( size_t i = 0; i < dimlen-1; ++i )
+                {
+                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
+                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                }
+              finishCyclicBounds(pbounds, dimlen, pvals);
+            }
+          if ( pbounds )
+            {
+              if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
+                cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
+            }
+          if ( pbounds && nvdimID != CDI_UNDEFID )
+            {
+              char boundsname[extendedAxisnameLen + 1 + sizeof(bndsName)];
+              memcpy(boundsname, axisname, extendedAxisnameLen);
+              boundsname[extendedAxisnameLen] = '_';
+              memcpy(boundsname + extendedAxisnameLen + 1, bndsName, sizeof bndsName);
+              int dimIDs[2] = { dimID, nvdimID };
+              cdf_def_var(fileID, boundsname, xtype, 2, dimIDs, &ncbvarid);
+              cdf_put_att_text(fileID, ncvarid, "bounds", extendedAxisnameLen + sizeof (bndsName), boundsname);
+            }
+        }
 
-		if ( ncvars[ncvarid].cellarea != UNDEFID )
-                  {
-                    if (CDI_netcdf_lazy_grid_load)
-                      {
-                        grid->area = cdfPendingLoad;
-                        lazyGrid->cellAreaGet.datasetNCId
-                          = ncvars[ncvarid].ncid;
-                        lazyGrid->cellAreaGet.varNCId
-                          = ncvars[ncvarid].cellarea;
-                      }
-                    else
-                      {
-                        grid->area = (double *) Malloc(size*sizeof(double));
-                        cdf_get_var_double(ncvars[ncvarid].ncid,
-                                           ncvars[ncvarid].cellarea,
-                                           grid->area);
-                      }
-                  }
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
 
-		break;
-	      }
-	    case GRID_SPECTRAL:
-	      {
-		grid->size = (int)size;
-		grid->lcomplex = 1;
-		break;
-	      }
-	    case GRID_FOURIER:
-	      {
-		grid->size = (int)size;
-		break;
-	      }
-	    case GRID_TRAJECTORY:
-	      {
-		grid->size = 1;
-		break;
-	      }
-	    }
+      if ( ncvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncvarid, pvals);
+      if ( ncbvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbvarid, pbounds);
+      if ( gen_bounds ) Free(pbounds);
 
-          if ( grid->type != ncvars[ncvarid].gridtype )
-            {
-              int gridtype = ncvars[ncvarid].gridtype;
-              grid->type = gridtype;
-              cdiGridTypeInit(grid, gridtype, grid->size);
-            }
+      if ( ndims == 0 )
+        ncgrid[gridindex].ncIDs[dimKey == CDI_KEY_XDIMNAME
+                                ? CDF_VARID_X : CDF_VARID_Y] = ncvarid;
+    }
 
-	  if ( grid->size == 0 )
-	    {
-	      if ( (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == T_AXIS) ||
-		   (ncvars[ncvarid].ndims == 1 && ncvars[ncvarid].dimtype[0] == Z_AXIS) ||
-		   (ncvars[ncvarid].ndims == 2 && ncvars[ncvarid].dimtype[0] == T_AXIS && ncvars[ncvarid].dimtype[1] == Z_AXIS) )
-		{
-		  grid->type  = GRID_GENERIC;
-		  grid->size  = 1;
-		  grid->xsize = 0;
-		  grid->ysize = 0;
-		}
-	      else
-		{
-		  Warning("Variable %s has an unsupported grid, skipped!", ncvars[ncvarid].name);
-		  ncvars[ncvarid].isvar = -1;
-		  continue;
-		}
-	    }
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[dimKey == CDI_KEY_XDIMNAME
+                          ? CDF_DIMID_X : CDF_DIMID_Y] = dimID;
+}
 
-	  if ( number_of_grid_used != UNDEFID && (grid->type == UNDEFID || grid->type == GRID_GENERIC) )
-            grid->type   = GRID_UNSTRUCTURED;
+static
+void finishCyclicXBounds(double *pbounds, size_t dimlen, const double *pvals)
+{
+  pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)*0.5;
+  pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)*0.5;
+}
 
-	  if ( number_of_grid_used != UNDEFID && grid->type == GRID_UNSTRUCTURED )
-            grid->number = number_of_grid_used;
+static
+void cdfDefXaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
+{
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsX,
+                   CDI_KEY_XDIMNAME, 'X', finishCyclicXBounds);
+}
 
-	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
-	    {
-              int nvatts;
-	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
+static
+void finishCyclicYBounds(double *pbounds, size_t dimlen, const double *pvals)
+{
+  pbounds[0] = copysign(90.0, pvals[0]);
+  pbounds[2*dimlen-1] = copysign(90.0, pvals[dimlen-1]);
+}
 
-	      for ( int iatt = 0; iatt < nvatts; iatt++ )
-		{
-                  size_t attlen;
-                  char attname[CDI_MAX_NAME];
-		  cdf_inq_attname(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, iatt, attname);
-		  cdf_inq_attlen(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, &attlen);
+static
+void cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
+{
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsY,
+                   CDI_KEY_YDIMNAME, 'Y', finishCyclicYBounds);
+}
 
-		  if ( strcmp(attname, "grid_mapping_name") == 0 )
-		    {
-                      enum {
-                        attstringlen = 8192,
-                      };
-                      char attstring[attstringlen];
-
-		      cdfGetAttText(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, attstringlen, attstring);
-		      strtolower(attstring);
-
-		      if ( strcmp(attstring, "rotated_latitude_longitude") == 0 )
-			grid->isRotated = TRUE;
-		      else if ( strcmp(attstring, "sinusoidal") == 0 )
-			grid->type = GRID_SINUSOIDAL;
-		      else if ( strcmp(attstring, "lambert_azimuthal_equal_area") == 0 )
-			grid->type = GRID_LAEA;
-		      else if ( strcmp(attstring, "lambert_conformal_conic") == 0 )
-			grid->type = GRID_LCC2;
-		      else if ( strcmp(attstring, "lambert_cylindrical_equal_area") == 0 )
-			{
-			  proj->type = GRID_PROJECTION;
-			  proj->name = strdup(attstring);
-			}
-		    }
-		  else if ( strcmp(attname, "earth_radius") == 0 )
-		    {
-                      double datt;
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid->laea_a = datt;
-		      grid->lcc2_a = datt;
-		    }
-		  else if ( strcmp(attname, "longitude_of_projection_origin") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->laea_lon_0);
-		    }
-		  else if ( strcmp(attname, "longitude_of_central_meridian") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->lcc2_lon_0);
-		    }
-		  else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )
-		    {
-                      double datt;
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-		      grid->laea_lat_0 = datt;
-		      grid->lcc2_lat_0 = datt;
-		    }
-		  else if ( strcmp(attname, "standard_parallel") == 0 )
-		    {
-		      if ( attlen == 1 )
-			{
-                          double datt;
-			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &datt);
-			  grid->lcc2_lat_1 = datt;
-			  grid->lcc2_lat_2 = datt;
-			}
-		      else
-			{
-			  double datt2[2];
-			  cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 2, datt2);
-			  grid->lcc2_lat_1 = datt2[0];
-			  grid->lcc2_lat_2 = datt2[1];
-			}
-		    }
-		  else if ( strcmp(attname, "grid_north_pole_latitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->ypole);
-		    }
-		  else if ( strcmp(attname, "grid_north_pole_longitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->xpole);
-		    }
-		  else if ( strcmp(attname, "north_pole_grid_longitude") == 0 )
-		    {
-		      cdfGetAttDouble(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, attname, 1, &grid->angle);
-		    }
-		}
-	    }
+static
+void cdfGridCompress(int fileID, int ncvarid, size_t gridsize, int filetype, int comptype)
+{
+#if  defined  (HAVE_NETCDF4)
+  if ( gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C) )
+    {
+      cdf_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
+      cdfDefVarDeflate(fileID, ncvarid, 1);
+    }
+#endif
+}
 
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              int zdimid = UNDEFID;
-              int xdimidx = -1, ydimidx = -1;
+static
+void cdfDefGridReference(stream_t *streamptr, int gridID)
+{
+  int fileID  = streamptr->fileID;
+  int number = gridInqNumber(gridID);
 
-              for ( int i = 0; i < ndims; i++ )
-                {
-                  if      ( ncvars[ncvarid].dimtype[i] == X_AXIS ) xdimidx = i;
-                  else if ( ncvars[ncvarid].dimtype[i] == Y_AXIS ) ydimidx = i;
-                  else if ( ncvars[ncvarid].dimtype[i] == Z_AXIS ) zdimid = ncvars[ncvarid].dimids[i];
-                }
+  if ( number > 0 )
+    {
+      cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
+    }
 
-              if ( xdimid != UNDEFID && ydimid != UNDEFID && zdimid == UNDEFID )
-                {
-                  if ( grid->xsize > grid->ysize && grid->ysize < 1000 )
-                    {
-                      ncvars[ncvarid].dimtype[ydimidx] = Z_AXIS;
-                      ydimid = UNDEFID;
-                      grid->size  = grid->xsize;
-                      grid->ysize = 0;
-                    }
-                  else if ( grid->ysize > grid->xsize && grid->xsize < 1000 )
-                    {
-                      ncvars[ncvarid].dimtype[xdimidx] = Z_AXIS;
-                      xdimid = ydimid;
-                      ydimid = UNDEFID;
-                      grid->size  = grid->ysize;
-                      grid->xsize = grid->ysize;
-                      grid->ysize = 0;
-                    }
-                }
+  const char *gridfile = gridInqReferencePtr(gridID);
+  if ( gridfile && gridfile[0] != 0 )
+    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
+}
 
-              if ( grid->size != grid->xsize )
-                {
-                  Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                  ncvars[ncvarid].isvar = -1;
-                  continue;
-                }
+static
+void cdfDefGridUUID(stream_t *streamptr, int gridID)
+{
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
 
-              if ( ncvars[ncvarid].position > 0 ) grid->position = ncvars[ncvarid].position;
-              if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
-            }
+  gridInqUUID(gridID, uuidOfHGrid);
+  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+    {
+      char uuidOfHGridStr[37];
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
+      if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
+        {
+          int fileID  = streamptr->fileID;
+          //if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+          cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfHGrid", 36, uuidOfHGridStr);
+          //if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+        }
+    }
+}
 
-#if defined (PROJECTION_TEST)
-	  if ( proj->type == GRID_PROJECTION )
-	    {
-	      if ( grid->type == GRID_GENERIC )
-		{
-		  grid->type = GRID_CURVILINEAR;
-		}
+struct cdfDefIrregularGridCommonIDs
+{
+  int xdimID, ydimID, ncxvarid, ncyvarid, ncavarid;
+};
 
-	      if ( grid->type == GRID_CURVILINEAR )
-		{
-                  proj->size  = grid->size;
-                  proj->xsize = grid->xsize;
-                  proj->ysize = grid->ysize;
-		}
+static struct cdfDefIrregularGridCommonIDs
+cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
+                          size_t xdimlen, size_t ydimlen,
+                          int ndims, const char *xdimname_default,
+                          size_t nvertex, const char *vdimname_default,
+                          bool setVdimname)
+{
+  nc_type xtype = (nc_type)cdfDefDatatype(gridInqDatatype(gridID), streamptr->filetype);
+  int xdimID = CDI_UNDEFID;
+  int ydimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID;
+  int fileID  = streamptr->fileID;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	      //  grid->proj = gridGenerate(proj);
-	    }
-#endif
+  {
+    char xdimname[CDI_MAX_NAME+3];
+    xdimname[0] = 0;
+    cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname);
+    if ( xdimname[0] == 0 ) strcpy(xdimname, xdimname_default);
+    xdimID = checkDimName(fileID, xdimlen, xdimname);
+    if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID);
+  }
 
-	  if ( CDI_Debug )
-	    {
-	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
-		      grid->type, grid->size, grid->xsize, grid->ysize);
-	      Message("proj: type = %d, size = %d, nx = %d, ny %d",
-		      proj->type, proj->size, proj->xsize, proj->ysize);
-	    }
+  if ( ndims == 3 )
+    {
+      char ydimname[CDI_MAX_NAME+3];
+      ydimname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, ydimname);
+      if ( ydimname[0] == 0 ) { ydimname[0] = 'y'; ydimname[1] = 0; }
+      ydimID = checkDimName(fileID, ydimlen, ydimname);
+      if ( ydimID == CDI_UNDEFID ) cdf_def_dim(fileID, ydimname, ydimlen, &ydimID);
+    }
 
-#if defined (PROJECTION_TEST)
-	  if ( proj->type == GRID_PROJECTION )
-	    {
-              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 1);
-              ncvars[ncvarid].gridID = projAdded.Id;
-	      copy_numeric_projatts(ncvars[ncvarid].gridID, ncvars[ncvarid].gmapid, ncvars[ncvarid].ncid);
-	    }
-	  else
-#endif
-            {
-              gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
-              ncvars[ncvarid].gridID = gridAdded.Id;
-            }
+  int nvdimID = CDI_UNDEFID;
+  int dimIDs[3];
+  dimIDs[ndims-1] = CDI_UNDEFID;
+  if ( setVdimname )
+    {
+      char vdimname[CDI_MAX_NAME+3]; vdimname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname);
+      if ( vdimname[0] == 0 ) strcpy(vdimname, vdimname_default);
+      nvdimID = dimIDs[ndims-1] = checkDimName(fileID, nvertex, vdimname);
+      if ( nvdimID == CDI_UNDEFID )
+        {
+          cdf_def_dim(fileID, vdimname, nvertex, dimIDs+ndims-1);
+          nvdimID = dimIDs[ndims-1];
+        }
+    }
 
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
-            }
+  if ( ndims == 3 )
+    {
+      dimIDs[0] = ydimID;
+      dimIDs[1] = xdimID;
+    }
+  else /* ndims == 2 */
+    {
+      dimIDs[0] = xdimID;
+      cdfDefGridReference(streamptr, gridID);
+      cdfDefGridUUID(streamptr, gridID);
+    }
 
-          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(grid, &ncvars[ncvarid]);
+  const double *xvalsPtr = gridInqXvalsPtr(gridID),
+    *xboundsPtr = NULL;
+  if ( xvalsPtr )
+    {
+      char xaxisname[CDI_MAX_NAME]; xaxisname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname);
+      checkGridName(xaxisname, fileID);
+      cdf_def_var(fileID, xaxisname, xtype, ndims-1, dimIDs, &ncxvarid);
+      cdfGridCompress(fileID, ncxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
-	  int gridindex = vlistGridIndex(vlistID, ncvars[ncvarid].gridID);
-	  streamptr->xdimID[gridindex] = xdimid;
-	  streamptr->ydimID[gridindex] = ydimid;
-          if ( xdimid == -1 && ydimid == -1 && grid->size == 1 )
-            gridDefHasDims(ncvars[ncvarid].gridID, FALSE);
+      cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
 
-          if ( xdimid != -1 )
-            cdiGridDefString(ncvars[ncvarid].gridID, CDI_GRID_XDIMNAME, (int)(strlen(ncdims[xdimid].name)+1), ncdims[xdimid].name);
-          if ( ydimid != -1 )
-            cdiGridDefString(ncvars[ncvarid].gridID, CDI_GRID_YDIMNAME, (int)(strlen(ncdims[ydimid].name)+1), ncdims[ydimid].name);
-          if ( vdimid != -1 )
-            cdiGridDefString(ncvars[ncvarid].gridID, CDI_GRID_VDIMNAME, (int)(strlen(ncdims[vdimid].name)+1), ncdims[vdimid].name);
+      /* attribute for Panoply */
+      if ( ndims == 3 )
+        cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
 
-	  if ( CDI_Debug )
-	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
+      if ( (xboundsPtr = gridInqXboundsPtr(gridID)) && nvdimID != CDI_UNDEFID )
+        {
+          size_t xaxisnameLen = strlen(xaxisname);
+          xaxisname[xaxisnameLen] = '_';
+          memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName));
+          cdf_def_var(fileID, xaxisname, xtype, ndims, dimIDs, &ncbxvarid);
+          cdfGridCompress(fileID, ncbxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
-	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
-	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].gridID == UNDEFID )
-	      {
-		int xdimid2 = UNDEFID, ydimid2 = UNDEFID, zdimid2 = UNDEFID;
-                int xdimidx = -1, ydimidx = -1;
-		int ndims2 = ncvars[ncvarid2].ndims;
+          cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+        }
+    }
 
-		for ( int i = 0; i < ndims2; i++ )
-		  {
-		    if ( ncvars[ncvarid2].dimtype[i] == X_AXIS )
-		      { xdimid2 = ncvars[ncvarid2].dimids[i]; xdimidx = i; }
-		    else if ( ncvars[ncvarid2].dimtype[i] == Y_AXIS )
-		      { ydimid2 = ncvars[ncvarid2].dimids[i]; ydimidx = i; }
-		    else if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
-		      { zdimid2 = ncvars[ncvarid2].dimids[i]; }
-		  }
+  const double *yvalsPtr = gridInqYvalsPtr(gridID),
+    *yboundsPtr = NULL;
+  if ( yvalsPtr )
+    {
+      char yaxisname[CDI_MAX_NAME];
+      gridInqYname(gridID, yaxisname);
+      checkGridName(yaxisname, fileID);
 
-                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid->type == GRID_UNSTRUCTURED )
-                  {
-                    if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[ydimidx] = Z_AXIS;
-                        ydimid2 = UNDEFID;
-                      }
+      cdf_def_var(fileID, yaxisname, xtype, ndims - 1, dimIDs, &ncyvarid);
+      cdfGridCompress(fileID, ncyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
-                    if ( xdimid == ydimid2 && xdimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[xdimidx] = Z_AXIS;
-                        xdimid2 = ydimid2;
-                        ydimid2 = UNDEFID;
-                      }
-                  }
+      cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
 
-                if ( xdimid == xdimid2 &&
-		    (ydimid == ydimid2 || (xdimid == ydimid && ydimid2 == UNDEFID)) )
-		  {
-		    int same_grid = ncvars[ncvarid].xvarid == ncvars[ncvarid2].xvarid
-                      && ncvars[ncvarid].yvarid == ncvars[ncvarid2].yvarid
-                      && ncvars[ncvarid].position == ncvars[ncvarid2].position;
-                    /*
-		    if ( xvarid != -1 && ncvars[ncvarid2].xvarid != UNDEFID &&
-			 xvarid != ncvars[ncvarid2].xvarid ) same_grid = FALSE;
-
-		    if ( yvarid != -1 && ncvars[ncvarid2].yvarid != UNDEFID &&
-			 yvarid != ncvars[ncvarid2].yvarid ) same_grid = FALSE;
-                    */
-
-		    if ( same_grid )
-		      {
-			if ( CDI_Debug )
-			  Message("Same gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid2, ncvars[ncvarid2].name);
-			ncvars[ncvarid2].gridID = ncvars[ncvarid].gridID;
-			ncvars[ncvarid2].chunktype = ncvars[ncvarid].chunktype;
-		      }
-		  }
-	      }
+      /* attribute for Panoply */
+      if ( ndims == 3 )
+        cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
 
-          if (gridAdded.isNew)
-            lazyGrid = NULL;
-          if (projAdded.isNew)
-            lazyProj = NULL;
-	}
-    }
-  if (lazyGrid)
-    {
-      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyGrid);
-      grid_free(grid);
-      Free(grid);
+      if ( (yboundsPtr = gridInqYboundsPtr(gridID)) && nvdimID != CDI_UNDEFID )
+        {
+          size_t yaxisnameLen = strlen(yaxisname);
+          yaxisname[yaxisnameLen] = '_';
+          memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName));
+          cdf_def_var(fileID, yaxisname, xtype, ndims, dimIDs, &ncbyvarid);
+          cdfGridCompress(fileID, ncbyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
+
+          cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+        }
     }
-  if (lazyProj)
+
+  const double *areaPtr = gridInqAreaPtr(gridID);
+  if ( areaPtr )
     {
-      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyProj);
-      grid_free(proj);
-      Free(proj);
+      static const char yaxisname_[] = "cell_area";
+      static const char units[] = "m2";
+      static const char longname[] = "area of grid cell";
+      static const char stdname[] = "cell_area";
+
+      cdf_def_var(fileID, yaxisname_, xtype, ndims-1, dimIDs, &ncavarid);
+
+      cdf_put_att_text(fileID, ncavarid, "standard_name", sizeof (stdname) - 1, stdname);
+      cdf_put_att_text(fileID, ncavarid, "long_name", sizeof (longname) - 1, longname);
+      cdf_put_att_text(fileID, ncavarid, "units", sizeof (units) - 1, units);
     }
-#undef proj
-#undef grid
+
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
+
+  if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  xvalsPtr);
+  if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, xboundsPtr);
+  if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  yvalsPtr);
+  if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, yboundsPtr);
+  if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  areaPtr);
+
+  return (struct cdfDefIrregularGridCommonIDs) {
+    .xdimID=xdimID, .ydimID = ydimID,
+    .ncxvarid=ncxvarid, .ncyvarid=ncyvarid, .ncavarid=ncavarid
+  };
 }
 
-/* define all input zaxes */
 static
-void define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int nvars, ncvar_t *ncvars,
-		      size_t vctsize_echam, double *vct_echam, unsigned char *uuidOfVGrid)
-{
-  int ncvarid, ncvarid2;
-  int i, ilev;
-  int zaxisindex;
-  int nbdims, nvertex, nlevel;
-  int psvarid = -1;
-  char *pname, *plongname, *punits;
-  size_t vctsize = vctsize_echam;
-  double *vct = vct_echam;
-
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].zaxisID == UNDEFID )
-	{
-          int is_scalar = FALSE;
-	  int with_bounds = FALSE;
-	  int zdimid = UNDEFID;
-	  int zvarid = UNDEFID;
-	  int zsize = 1;
-	  double *lbounds = NULL;
-	  double *ubounds = NULL;
+void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-          int positive = 0;
-	  int ndims = ncvars[ncvarid].ndims;
+  size_t dimlen = gridInqSize(gridID);
+  size_t xdimlen = gridInqXsize(gridID);
+  size_t ydimlen = gridInqYsize(gridID);
 
-          if ( ncvars[ncvarid].zvarid != -1 && ncvars[ncvars[ncvarid].zvarid].ndims == 0 )
+  int xdimID = CDI_UNDEFID, ydimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  {
+    size_t ofs = 0;
+    do {
+      struct idSearch search
+        = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X,
+                            GRID_CURVILINEAR, (int)dimlen,
+                            gridInqType, gridInqSize);
+      size_t index = search.foundIdx;
+      if ( index != SIZE_MAX )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          if (    IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0))
+               && IS_EQUAL(gridInqXval(gridID0, dimlen-1),
+                           gridInqXval(gridID, dimlen-1))
+               && IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0))
+               && IS_EQUAL(gridInqYval(gridID0, dimlen-1),
+                           gridInqYval(gridID, dimlen-1)) )
             {
-              zvarid = ncvars[ncvarid].zvarid;
-              is_scalar = TRUE;
+              xdimID = ncgrid[index].ncIDs[CDF_DIMID_X];
+              ydimID = ncgrid[index].ncIDs[CDF_DIMID_Y];
+              ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X];
+              ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y];
+              break;
             }
-          else
-            {
-              for ( i = 0; i < ndims; i++ )
-                {
-                  if ( ncvars[ncvarid].dimtype[i] == Z_AXIS )
-                    zdimid = ncvars[ncvarid].dimids[i];
-                }
+          ofs = search.foundIdx;
+          if ( ofs < (size_t)gridindex )
+            continue;
+        }
+    } while (false);
+  }
 
-              if ( zdimid != UNDEFID )
-                {
-                  zvarid = ncdims[zdimid].ncvarid;
-                  zsize  = (int)ncdims[zdimid].len;
-                }
-            }
+  if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID )
+    {
+      struct cdfDefIrregularGridCommonIDs createdIDs
+        = cdfDefIrregularGridCommon(streamptr, gridID,
+                                    xdimlen, ydimlen, 3, "x", 4, "nv4",
+                                    gridInqXboundsPtr(gridID)
+                                    || gridInqYboundsPtr(gridID));
+      xdimID = createdIDs.xdimID;
+      ydimID = createdIDs.ydimID;
+      ncxvarid = createdIDs.ncxvarid;
+      ncyvarid = createdIDs.ncyvarid;
+      ncavarid = createdIDs.ncavarid;
+    }
 
-	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = xdimID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = ydimID;
+  ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid;
+  ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid;
+  ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid;
+}
 
-	  double *zvar = (double *) Malloc((size_t)zsize * sizeof (double));
 
-	  int zaxisType = UNDEFID;
-	  if ( zvarid != UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
-	  if ( zaxisType == UNDEFID )  zaxisType = ZAXIS_GENERIC;
+static
+void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-	  int zprec = DATATYPE_FLT64;
+  size_t dimlen = gridInqSize(gridID);
 
-	  if ( zvarid != UNDEFID )
-	    {
-	      positive  = ncvars[zvarid].positive;
-	      pname     = ncvars[zvarid].name;
-	      plongname = ncvars[zvarid].longname;
-	      punits    = ncvars[zvarid].units;
-	      if ( ncvars[zvarid].xtype == NC_FLOAT ) zprec = DATATYPE_FLT32;
-	      /* don't change the name !!! */
-	      /*
-	      if ( (len = strlen(pname)) > 2 )
-		if ( pname[len-2] == '_' && isdigit((int) pname[len-1]) )
-		  pname[len-2] = 0;
-	      */
-              psvarid = -1;
-              if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
-                {
-                  vct = ncvars[zvarid].vct;
-                  vctsize = ncvars[zvarid].vctsize;
+  int dimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  {
+    size_t ofs = 0;
+    do {
+      struct idSearch search
+        = cdfSearchIDBySize(ofs, (size_t)gridindex, ncgrid, CDF_DIMID_X,
+                            GRID_UNSTRUCTURED, (int)dimlen,
+                            gridInqType, gridInqSize);
+      size_t index = search.foundIdx;
+      if ( index != SIZE_MAX )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) &&
+               IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) &&
+               IS_EQUAL(gridInqXval(gridID0, dimlen-1),
+                        gridInqXval(gridID, dimlen-1)) &&
+               IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) &&
+               IS_EQUAL(gridInqYval(gridID0, dimlen-1),
+                        gridInqYval(gridID, dimlen-1)) )
+            {
+              dimID = ncgrid[index].ncIDs[CDF_DIMID_X];
+              ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X];
+              ncyvarid = ncgrid[index].ncIDs[CDF_VARID_Y];
+              ncavarid = ncgrid[index].ncIDs[CDF_VARID_A];
+              break;
+            }
+          ofs = search.foundIdx;
+          if ( ofs < (size_t)gridindex )
+            continue;
+        }
+    } while (false);
+  }
 
-                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
-                }
+  if ( dimID == CDI_UNDEFID )
+    {
+      size_t nvertex = (size_t)gridInqNvertex(gridID);
+      struct cdfDefIrregularGridCommonIDs createdIDs
+        = cdfDefIrregularGridCommon(streamptr, gridID,
+                                    dimlen, 1, 2, "ncells",
+                                    nvertex, "vertices", nvertex > 0);
+      dimID = createdIDs.xdimID;
+      ncxvarid = createdIDs.ncxvarid;
+      ncyvarid = createdIDs.ncyvarid;
+      ncavarid = createdIDs.ncavarid;
+    }
 
-	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+  ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncxvarid;
+  ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncyvarid;
+  ncgrid[gridindex].ncIDs[CDF_VARID_A] = ncavarid;
+}
 
-	      if ( ncvars[zvarid].bounds != UNDEFID )
-		{
-		  nbdims = ncvars[ncvars[zvarid].bounds].ndims;
-		  if ( nbdims == 2 )
-		    {
-		      nlevel  = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
-		      nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1]].len;
-		      if ( nlevel == zsize && nvertex == 2 )
-			{
-			  with_bounds = TRUE;
-			  lbounds = (double *) Malloc((size_t)nlevel*sizeof(double));
-			  ubounds = (double *) Malloc((size_t)nlevel*sizeof(double));
-			  double zbounds[2*nlevel];
-			  cdf_get_var_double(ncvars[zvarid].ncid, ncvars[zvarid].bounds, zbounds);
-			  for ( i = 0; i < nlevel; ++i )
-			    {
-			      lbounds[i] = zbounds[i*2];
-			      ubounds[i] = zbounds[i*2+1];
-			    }
-			}
-		    }
-		}
-	    }
-	  else
-	    {
-	      pname     = NULL;
-	      plongname = NULL;
-	      punits    = NULL;
+struct attTxtTab2
+{
+  const char *attName, *attVal;
+  size_t valLen;
+};
 
-	      if ( zsize == 1 )
-		{
-                  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-                    zaxisType = ncvars[ncvarid].zaxistype;
-                  else
-                    zaxisType = ZAXIS_SURFACE;
+static
+void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
+{
+  int type = zaxisInqType(zaxisID);
+
+  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
+    {
+      int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
+
+      int mlev = ilev - 1;
+
+      if ( streamptr->vct.ilev > 0 )
+        {
+          if ( streamptr->vct.ilev != ilev )
+            Error("More than one VCT for each file unsupported!");
+          return;
+        }
 
-		  zvar[0] = 0;
-		  /*
-		  if ( zdimid == UNDEFID )
-		    zvar[0] = 9999;
-		  else
-		    zvar[0] = 0;
-		  */
-		}
-	      else
-		{
-		  for ( ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
-		}
-	    }
+      int fileID = streamptr->fileID;
 
-      	  ncvars[ncvarid].zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
-						(int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	  if ( uuidOfVGrid[0] != 0 )
-            {
-              // printf("uuidOfVGrid: defined\n");
-              zaxisDefUUID(ncvars[ncvarid].zaxisID, uuidOfVGrid);
-            }
+      int ncdimid = -1, ncdimid2 = -1;
+      int hyaiid, hybiid, hyamid = -1, hybmid = -1;
 
-          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 ) zaxisDefPsName(ncvars[ncvarid].zaxisID, ncvars[psvarid].name);
+      cdf_def_dim(fileID, "nhyi", (size_t)ilev, &ncdimid2);
+      cdf_def_var(fileID, "hyai", NC_DOUBLE, 1, &ncdimid2, &hyaiid);
+      cdf_def_var(fileID, "hybi", NC_DOUBLE, 1, &ncdimid2, &hybiid);
+      if ( mlev > 0 )
+        {
+          cdf_def_dim(fileID, "nhym", (size_t)mlev, &ncdimid);
+          cdf_def_var(fileID, "hyam", NC_DOUBLE, 1, &ncdimid,  &hyamid);
+          cdf_def_var(fileID, "hybm", NC_DOUBLE, 1, &ncdimid,  &hybmid);
+        }
 
-          if ( positive > 0 ) zaxisDefPositive(ncvars[ncvarid].zaxisID, positive);
-          if ( is_scalar ) zaxisDefScalar(ncvars[ncvarid].zaxisID);
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.mlevID = ncdimid;
+      streamptr->vct.ilevID = ncdimid2;
 
-          if ( zdimid != -1 )
-            cdiZaxisDefString(ncvars[ncvarid].zaxisID, CDI_ZAXIS_DIMNAME, (int)(strlen(ncdims[zdimid].name)+1), ncdims[zdimid].name);
-          /*
-          if ( vdimid != -1 )
-            cdiZaxisDefString(ncvars[ncvarid].zaxisID, CDI_ZAXIS_VDIMNAME, strlen(ncdims[vdimid].name)+1, ncdims[vdimid].name);
-          */
-	  Free(zvar);
-	  Free(lbounds);
-	  Free(ubounds);
+      {
+        static const char lname_n[] = "long_name",
+          units_n[] = "units",
+          lname_v_ai[] = "hybrid A coefficient at layer interfaces",
+          units_v_ai[] = "Pa",
+          lname_v_bi[] = "hybrid B coefficient at layer interfaces",
+          units_v_bi[] = "1";
+        static const struct attTxtTab2 tab[]
+          = {
+          { lname_n, lname_v_ai, sizeof (lname_v_ai) - 1 },
+          { units_n, units_v_ai, sizeof (units_v_ai) - 1 },
+          { lname_n, lname_v_bi, sizeof (lname_v_bi) - 1 },
+          { units_n, units_v_bi, sizeof (units_v_bi) - 1 },
+        };
+        enum { tabLen = sizeof (tab) / sizeof (tab[0]) };
+        int ids[tabLen] = { hyaiid, hyaiid, hybiid, hybiid };
+        for ( size_t i = 0; i < tabLen; ++i )
+          cdf_put_att_text(fileID, ids[i], tab[i].attName, tab[i].valLen, tab[i].attVal);
+      }
 
-	  zaxisindex = vlistZaxisIndex(vlistID, ncvars[ncvarid].zaxisID);
-	  streamptr->zaxisID[zaxisindex]  = zdimid;
+      {
+        static const char lname_n[] = "long_name",
+          units_n[] = "units",
+          lname_v_am[] = "hybrid A coefficient at layer midpoints",
+          units_v_am[] = "Pa",
+          lname_v_bm[] = "hybrid B coefficient at layer midpoints",
+          units_v_bm[] = "1";
+        static const struct attTxtTab2 tab[]
+          = {
+          { lname_n, lname_v_am, sizeof (lname_v_am) - 1 },
+          { units_n, units_v_am, sizeof (units_v_am) - 1 },
+          { lname_n, lname_v_bm, sizeof (lname_v_bm) - 1 },
+          { units_n, units_v_bm, sizeof (units_v_bm) - 1 },
+        };
+        enum { tabLen = sizeof (tab) / sizeof (tab[0]) };
+        int ids[tabLen] = { hyamid, hyamid, hybmid, hybmid };
+        for ( size_t i = 0; i < tabLen; ++i )
+          cdf_put_att_text(fileID, ids[i], tab[i].attName, tab[i].valLen, tab[i].attVal);
+      }
 
-	  if ( CDI_Debug )
-	    Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid, ncvars[ncvarid].name);
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
 
-	  for ( ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
-	    if ( ncvars[ncvarid2].isvar == TRUE && ncvars[ncvarid2].zaxisID == UNDEFID /*&& ncvars[ncvarid2].zaxistype == UNDEFID*/ )
-	      {
-                int zvarid2 = UNDEFID;
-                if ( ncvars[ncvarid2].zvarid != UNDEFID && ncvars[ncvars[ncvarid2].zvarid].ndims == 0 )
-                  zvarid2 = ncvars[ncvarid2].zvarid;
+      const double *vctptr = zaxisInqVctPtr(zaxisID);
 
-		int zdimid2 = UNDEFID;
-		ndims = ncvars[ncvarid2].ndims;
-		for ( i = 0; i < ndims; i++ )
-		  {
-		    if ( ncvars[ncvarid2].dimtype[i] == Z_AXIS )
-		      zdimid2 = ncvars[ncvarid2].dimids[i];
-		  }
+      cdf_put_var_double(fileID, hyaiid, vctptr);
+      cdf_put_var_double(fileID, hybiid, vctptr+ilev);
 
-		if ( zdimid == zdimid2 /* && zvarid == zvarid2 */)
-		  {
-                    if ( (zdimid != UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) ||
-                         (zdimid == UNDEFID && zvarid != UNDEFID && zvarid == zvarid2) ||
-                         (zdimid == UNDEFID && zaxisType == ncvars[ncvarid2].zaxistype) ||
-                         (zdimid == UNDEFID && zvarid2 == UNDEFID && ncvars[ncvarid2].zaxistype == UNDEFID) )
-                      {
-                        if ( CDI_Debug )
-                          Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid2, ncvars[ncvarid2].name);
-                        ncvars[ncvarid2].zaxisID = ncvars[ncvarid].zaxisID;
-                      }
-                  }
-	      }
-	}
+      size_t start;
+      size_t count = 1;
+      double mval;
+      for ( int i = 0; i < mlev; i++ )
+        {
+          start = (size_t)i;
+          mval = (vctptr[i] + vctptr[i+1]) * 0.5;
+          cdf_put_vara_double(fileID, hyamid, &start, &count, &mval);
+          mval = (vctptr[ilev+i] + vctptr[ilev+i+1]) * 0.5;
+          cdf_put_vara_double(fileID, hybmid, &start, &count, &mval);
+        }
     }
 }
 
-struct varinfo
-{
-  int      ncvarid;
-  const char *name;
-};
-
 static
-int cmpvarname(const void *s1, const void *s2)
+void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID, int p0status, double p0value)
 {
-  const struct varinfo *x = (const struct varinfo *)s1,
-    *y = (const struct varinfo *)s2;
-  return (strcmp(x->name, y->name));
-}
+  int type = zaxisInqType(zaxisID);
 
-/* define all input data variables */
-static
-void define_all_vars(stream_t *streamptr, int vlistID, int instID, int modelID, int *varids, int nvars, int num_ncvars, ncvar_t *ncvars)
-{
-  if ( CDI_Debug )
-    {
-      for(int i = 0; i < nvars; i++) Message("varids[%d] = %d", i, varids[i]);
-    }
-  if ( streamptr->sortname )
+  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
-      struct varinfo *varInfo
-        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
+      int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
 
-      for ( int varID = 0; varID < nvars; varID++ )
-	{
-	  int ncvarid = varids[varID];
-	  varInfo[varID].ncvarid = ncvarid;
-	  varInfo[varID].name = ncvars[ncvarid].name;
-	}
-      qsort(varInfo, (size_t)nvars, sizeof(varInfo[0]), cmpvarname);
-      for ( int varID = 0; varID < nvars; varID++ )
-	{
-	  varids[varID] = varInfo[varID].ncvarid;
-	}
-      Free(varInfo);
-      if ( CDI_Debug )
+      int mlev = ilev - 1;
+      int hyaiid = 0, hybiid = 0, hyamid, hybmid;
+
+      if ( streamptr->vct.ilev > 0 )
         {
-          for(int i = 0; i < nvars; i++) Message("sorted varids[%d] = %d", i, varids[i]);
+          if ( streamptr->vct.ilev != ilev )
+            Error("more than one VCT for each file unsupported!");
+          return;
         }
-    }
-
-  for ( int varID1 = 0; varID1 < nvars; varID1++ )
-    {
-      int ncvarid = varids[varID1];
-      int gridID  = ncvars[ncvarid].gridID;
-      int zaxisID = ncvars[ncvarid].zaxisID;
-
-      stream_new_var(streamptr, gridID, zaxisID, CDI_UNDEFID);
-      int varID = vlistDefVar(vlistID, gridID, zaxisID, ncvars[ncvarid].tsteptype);
-
-#if  defined  (HAVE_NETCDF4)
-      if ( ncvars[ncvarid].deflate )
-	vlistDefVarCompType(vlistID, varID, COMPRESS_ZIP);
 
-      if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != UNDEFID )
-        vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
-#endif
-
-      streamptr->vars[varID1].defmiss = 0;
-      streamptr->vars[varID1].ncvarid = ncvarid;
+      int fileID = streamptr->fileID;
 
-      vlistDefVarName(vlistID, varID, ncvars[ncvarid].name);
-      if ( ncvars[ncvarid].param != UNDEFID ) vlistDefVarParam(vlistID, varID, ncvars[ncvarid].param);
-      if ( ncvars[ncvarid].code != UNDEFID )  vlistDefVarCode(vlistID, varID, ncvars[ncvarid].code);
-      if ( ncvars[ncvarid].code != UNDEFID )
-	{
-	  int param = cdiEncodeParam(ncvars[ncvarid].code, ncvars[ncvarid].tabnum, 255);
-	  vlistDefVarParam(vlistID, varID, param);
-	}
-      if ( ncvars[ncvarid].longname[0] )  vlistDefVarLongname(vlistID, varID, ncvars[ncvarid].longname);
-      if ( ncvars[ncvarid].stdname[0] )   vlistDefVarStdname(vlistID, varID, ncvars[ncvarid].stdname);
-      if ( ncvars[ncvarid].units[0] )     vlistDefVarUnits(vlistID, varID, ncvars[ncvarid].units);
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      if ( ncvars[ncvarid].lvalidrange )
-        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
+      int dimIDs[2];
+      dimIDs[0] = nclevID;
+      dimIDs[1] = ncbndsID;
 
-      if ( IS_NOT_EQUAL(ncvars[ncvarid].addoffset, 0) )
-	vlistDefVarAddoffset(vlistID, varID, ncvars[ncvarid].addoffset);
-      if ( IS_NOT_EQUAL(ncvars[ncvarid].scalefactor, 1) )
-	vlistDefVarScalefactor(vlistID, varID, ncvars[ncvarid].scalefactor);
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlevID = nclevID;
+      streamptr->vct.ilevID = nclevID;
 
-      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
+      if ( p0status == 0 )
+        cdf_def_var(fileID, "a", NC_DOUBLE, 1, dimIDs,  &hyamid);
+      else
+        cdf_def_var(fileID, "ap", NC_DOUBLE, 1, dimIDs,  &hyamid);
+      cdf_def_var(fileID, "b",  NC_DOUBLE, 1, dimIDs,  &hybmid);
 
-      vlistDefVarInstitut(vlistID, varID, instID);
-      vlistDefVarModel(vlistID, varID, modelID);
-      if ( ncvars[ncvarid].tableID != UNDEFID )
-	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
+      {
+        static const char lname[] = "vertical coordinate formula term: ap(k)";
+        cdf_put_att_text(fileID, hyamid, "long_name", sizeof (lname) - 1, lname);
+      }
+      {
+        static const char units[] = "Pa";
+        cdf_put_att_text(fileID, hyamid, "units", sizeof (units) - 1, units);
+      }
+      {
+        static const char lname[] = "vertical coordinate formula term: b(k)";
+        cdf_put_att_text(fileID, hybmid, "long_name", sizeof (lname) - 1, lname);
+      }
+      {
+        static const char units[] = "1";
+        cdf_put_att_text(fileID, hybmid, "units", sizeof (units) - 1, units);
+      }
 
-      if ( ncvars[ncvarid].deffillval == FALSE && ncvars[ncvarid].defmissval == TRUE )
+      if ( ncbndsID != -1 )
         {
-          ncvars[ncvarid].deffillval = TRUE;
-          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
+          if ( p0status == 0 )
+            cdf_def_var(fileID, "a_bnds", NC_DOUBLE, 2, dimIDs, &hyaiid);
+          else
+            cdf_def_var(fileID, "ap_bnds", NC_DOUBLE, 2, dimIDs, &hyaiid);
+          cdf_def_var(fileID, "b_bnds",  NC_DOUBLE, 2, dimIDs, &hybiid);
+          {
+            static const char lname[] = "vertical coordinate formula term: ap(k+1/2)";
+            cdf_put_att_text(fileID, hyaiid, "long_name", sizeof (lname) - 1, lname);
+          }
+          {
+            static const char units[] = "Pa";
+            cdf_put_att_text(fileID, hyaiid, "units", sizeof (units) - 1, units);
+          }
+          {
+            static const char lname[] = "vertical coordinate formula term: b(k+1/2)";
+            cdf_put_att_text(fileID, hybiid, "long_name", sizeof (lname) - 1, lname);
+          }
+          {
+            static const char units[] = "1";
+            cdf_put_att_text(fileID, hybiid, "units", sizeof (units) - 1, units);
+          }
         }
 
-      if ( ncvars[ncvarid].deffillval == TRUE )
-        vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
-
-      if ( CDI_Debug )
-	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
-		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
-
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      int xdimid = streamptr->xdimID[gridindex];
-      int ydimid = streamptr->ydimID[gridindex];
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
 
-      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-      int zdimid = streamptr->zaxisID[zaxisindex];
+      int vctsize = zaxisInqVctSize(zaxisID);
+      double vct[vctsize];
+      zaxisInqVct(zaxisID, vct);
 
-      int ndims = ncvars[ncvarid].ndims;
-      int iodim = 0;
-      int ixyz = 0;
-      int ipow10[4] = {1, 10, 100, 1000};
+      if ( p0status == 0 && IS_NOT_EQUAL(p0value,0) )
+        for ( int i = 0; i < vctsize/2; ++i ) vct[i] /= p0value;
 
-      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
+      double tarray[ilev*2];
 
-      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
+      if ( ncbndsID != -1 )
         {
-          if ( xdimid == ncvars[ncvarid].dimids[ndims-1] )
-            {
-              ixyz = 321;
-            }
-          else
+          for ( int i = 0; i < mlev; ++i )
             {
-              ixyz = 213;
+              tarray[2*i  ] = vct[i];
+              tarray[2*i+1] = vct[i+1];
             }
-        }
-      else
-        {
-          for ( int idim = iodim; idim < ndims; idim++ )
+          cdf_put_var_double(fileID, hyaiid, tarray);
+
+          for ( int i = 0; i < mlev; ++i )
             {
-              if      ( xdimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 1*ipow10[ndims-idim-1];
-              else if ( ydimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 2*ipow10[ndims-idim-1];
-              else if ( zdimid == ncvars[ncvarid].dimids[idim] )
-                ixyz += 3*ipow10[ndims-idim-1];
+              tarray[2*i  ] = vct[ilev+i];
+              tarray[2*i+1] = vct[ilev+i+1];
             }
+          cdf_put_var_double(fileID, hybiid, tarray);
         }
 
-      vlistDefVarXYZ(vlistID, varID, ixyz);
-      /*
-      printf("ixyz %d\n", ixyz);
-      printf("ndims %d\n", ncvars[ncvarid].ndims);
-      for ( int i = 0; i < ncvars[ncvarid].ndims; ++i )
-        printf("dimids: %d %d\n", i, ncvars[ncvarid].dimids[i]);
-      printf("xdimid, ydimid %d %d\n", xdimid, ydimid);
-      */
-      if ( ncvars[ncvarid].ensdata != NULL )
-        {
-          vlistDefVarEnsemble( vlistID, varID, ncvars[ncvarid].ensdata->ens_index,
-                               ncvars[ncvarid].ensdata->ens_count,
-                               ncvars[ncvarid].ensdata->forecast_init_type );
-          Free(ncvars[ncvarid].ensdata);
-          ncvars[ncvarid].ensdata = NULL;
-        }
+      for ( int i = 0; i < mlev; ++i )
+        tarray[i] = (vct[i] + vct[i+1]) * 0.5;
+      cdf_put_var_double(fileID, hyamid, tarray);
 
-      if ( ncvars[ncvarid].extra[0] != 0 )
-        {
-          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
-        }
+      for ( int i = 0; i < mlev; ++i )
+        tarray[i] = (vct[ilev+i] + vct[ilev+i+1]) * 0.5;
+      cdf_put_var_double(fileID, hybmid, tarray);
     }
+}
 
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int ncvarid = varids[varID];
-      int ncid = ncvars[ncvarid].ncid;
+struct attTxtTab { const char *txt; size_t txtLen; };
 
-      if ( ncvars[ncvarid].natts )
-	{
-	  int attnum;
-	  int iatt;
-	  nc_type attrtype;
-	  size_t attlen;
-	  char attname[CDI_MAX_NAME];
-	  const int attstringlen = 8192; char attstring[8192];
-	  int nvatts = ncvars[ncvarid].natts;
-
-	  for ( iatt = 0; iatt < nvatts; iatt++ )
-	    {
-	      attnum = ncvars[ncvarid].atts[iatt];
-	      cdf_inq_attname(ncid, ncvarid, attnum, attname);
-	      cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
-	      cdf_inq_atttype(ncid, ncvarid, attname, &attrtype);
+static
+void cdf_def_zaxis_hybrid_echam(stream_t *streamptr, int type, int *ncvaridp, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
+{
+  int fileID = streamptr->fileID;
 
-	      if ( attrtype == NC_SHORT || attrtype == NC_INT )
-		{
-		  int attint[attlen];
-		  cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint);
-		  if ( attrtype == NC_SHORT )
-		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT16, (int)attlen, attint);
-		  else
-		    vlistDefAttInt(vlistID, varID, attname, DATATYPE_INT32, (int)attlen, attint);
-		}
-	      else if ( attrtype == NC_FLOAT || attrtype == NC_DOUBLE )
-		{
-		  double attflt[attlen];
-		  cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt);
-		  if ( attrtype == NC_FLOAT )
-		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT32, (int)attlen, attflt);
-		  else
-		    vlistDefAttFlt(vlistID, varID, attname, DATATYPE_FLT64, (int)attlen, attflt);
-		}
-	      else if ( xtypeIsText(attrtype) )
-		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  vlistDefAttTxt(vlistID, varID, attname, (int)attlen, attstring);
-		}
-	      else
-		{
-		  if ( CDI_Debug ) printf("att: %s.%s = unknown\n", ncvars[ncvarid].name, attname);
-		}
-	    }
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	  if (ncvars[ncvarid].vct) Free(ncvars[ncvarid].vct);
-	  if (ncvars[ncvarid].atts) Free(ncvars[ncvarid].atts);
-          ncvars[ncvarid].vct = NULL;
-          ncvars[ncvarid].atts = NULL;
-	}
-    }
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  ncvaridp);
+  int ncvarid = *ncvaridp;
 
-  /* release mem of not freed attributes */
-  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
-    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
+  {
+    static const char sname[] = "hybrid_sigma_pressure";
+    cdf_put_att_text(fileID, ncvarid, "standard_name", sizeof (sname) - 1, sname);
+  }
+  {
+    static const char *attName[] = {
+      "long_name",
+      "formula",
+      "formula_terms"
+    };
+    enum { nAtt = sizeof (attName) / sizeof (attName[0]) };
+    static const char lname_m[] = "hybrid level at layer midpoints",
+      formula_m[] = "hyam hybm (mlev=hyam+hybm*aps)",
+      fterms_m[] = "ap: hyam b: hybm ps: aps",
+      lname_i[] = "hybrid level at layer interfaces",
+      formula_i[] = "hyai hybi (ilev=hyai+hybi*aps)",
+      fterms_i[] = "ap: hyai b: hybi ps: aps";
+    static const struct attTxtTab tab[2][nAtt] = {
+      {
+        { lname_i, sizeof (lname_i) - 1 },
+        { formula_i, sizeof (formula_i) - 1 },
+        { fterms_i, sizeof (fterms_i) - 1 }
+      },
+      {
+        { lname_m, sizeof (lname_m) - 1 },
+        { formula_m, sizeof (formula_m) - 1 },
+        { fterms_m, sizeof (fterms_m) - 1 }
+      }
+    };
 
-  if ( varids ) Free(varids);
+    size_t tabSelect = type == ZAXIS_HYBRID;
+    for (size_t i = 0; i < nAtt; ++i)
+      cdf_put_att_text(fileID, ncvarid, attName[i],
+                       tab[tabSelect][i].txtLen, tab[tabSelect][i].txt);
+  }
 
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      if ( vlistInqVarCode(vlistID, varID) == -varID-1 )
-	{
-	  const char *pname = vlistInqVarNamePtr(vlistID, varID);
-	  size_t len = strlen(pname);
-	  if ( len > 3 && isdigit((int) pname[3]) )
-	    {
-	      if ( memcmp("var", pname, 3) == 0 )
-		{
-		  vlistDefVarCode(vlistID, varID, atoi(pname+3));
-                  // vlistDestroyVarName(vlistID, varID);
-		}
-	    }
-	  else if ( len > 4 && isdigit((int) pname[4]) )
-	    {
-	      if ( memcmp("code", pname, 4) == 0 )
-		{
-		  vlistDefVarCode(vlistID, varID, atoi(pname+4));
-		  // vlistDestroyVarName(vlistID, varID);
-		}
-	    }
-	  else if ( len > 5 && isdigit((int) pname[5]) )
-	    {
-	      if ( memcmp("param", pname, 5) == 0 )
-		{
-		  int pnum = -1, pcat = 255, pdis = 255;
-		  sscanf(pname+5, "%d.%d.%d", &pnum, &pcat, &pdis);
-		  vlistDefVarParam(vlistID, varID, cdiEncodeParam(pnum, pcat, pdis));
-                  // vlistDestroyVarName(vlistID, varID);
-		}
-	    }
-	}
-    }
+  {
+    static const char units[] = "level";
+    cdf_put_att_text(fileID, ncvarid, "units", sizeof (units) - 1, units);
+  }
+  {
+    static const char direction[] = "down";
+    cdf_put_att_text(fileID, ncvarid, "positive", sizeof (direction) - 1, direction);
+  }
 
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int varInstID  = vlistInqVarInstitut(vlistID, varID);
-      int varModelID = vlistInqVarModel(vlistID, varID);
-      int varTableID = vlistInqVarTable(vlistID, varID);
-      int code = vlistInqVarCode(vlistID, varID);
-      if ( cdiDefaultTableID != UNDEFID )
-	{
-	  if ( tableInqParNamePtr(cdiDefaultTableID, code) )
-	    {
-	      vlistDestroyVarName(vlistID, varID);
-	      vlistDestroyVarLongname(vlistID, varID);
-	      vlistDestroyVarUnits(vlistID, varID);
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
 
-	      if ( varTableID != UNDEFID )
-		{
-		  vlistDefVarName(vlistID, varID, tableInqParNamePtr(cdiDefaultTableID, code));
-		  if ( tableInqParLongnamePtr(cdiDefaultTableID, code) )
-		    vlistDefVarLongname(vlistID, varID, tableInqParLongnamePtr(cdiDefaultTableID, code));
-		  if ( tableInqParUnitsPtr(cdiDefaultTableID, code) )
-		    vlistDefVarUnits(vlistID, varID, tableInqParUnitsPtr(cdiDefaultTableID, code));
-		}
-	      else
-		{
-		  varTableID = cdiDefaultTableID;
-		}
-	    }
+  cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
 
-	  if ( cdiDefaultModelID != UNDEFID ) varModelID = cdiDefaultModelID;
-	  if ( cdiDefaultInstID  != UNDEFID ) varInstID  = cdiDefaultInstID;
-	}
-      if ( varInstID  != UNDEFID ) vlistDefVarInstitut(vlistID, varID, varInstID);
-      if ( varModelID != UNDEFID ) vlistDefVarModel(vlistID, varID, varModelID);
-      if ( varTableID != UNDEFID ) vlistDefVarTable(vlistID, varID, varTableID);
-    }
+  cdf_def_vct_echam(streamptr, zaxisID);
+
+  if ( *dimID == CDI_UNDEFID )
+    streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID
+      ? streamptr->vct.mlevID : streamptr->vct.ilevID;
 }
 
 static
-void scan_global_attributes(int fileID, int vlistID, stream_t *streamptr, int ngatts, int *instID, int *modelID, int *ucla_les, unsigned char *uuidOfHGrid, unsigned char *uuidOfVGrid, char *gridfile, int *number_of_grid_used)
+void cdf_def_zaxis_hybrid_cf(stream_t *streamptr, int type, int *ncvaridp, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
 {
-  nc_type xtype;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  enum { attstringlen = 65636 };
-  char attstring[attstringlen];
-  int iatt;
+  int fileID = streamptr->fileID;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  for ( iatt = 0; iatt < ngatts; iatt++ )
-    {
-      cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
-      cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
-      cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
+  char psname[CDI_MAX_NAME]; psname[0] = 0;
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_PSNAME, CDI_MAX_NAME, psname);
+  if ( psname[0] == 0 ) strcpy(psname, "ps");
 
-      if ( xtypeIsText(xtype) )
-	{
-	  cdfGetAttText(fileID, NC_GLOBAL, attname, attstringlen, attstring);
+  char p0name[CDI_MAX_NAME]; p0name[0] = 0;
+  double p0value = 1;
+  int p0varid = CDI_UNDEFID;
+  int p0status = cdiZaxisInqKeyFlt(zaxisID, CDI_KEY_P0VALUE, &p0value);
+  if ( p0status == 0 )
+    {
+      cdiZaxisInqKeyStr(zaxisID, CDI_KEY_P0NAME, CDI_MAX_NAME, p0name);
+      if ( p0name[0] == 0 ) strcpy(p0name, "p0");
+      cdf_def_var(fileID, p0name, NC_DOUBLE, 0, 0,  &p0varid);
+      static const char longname[] = "reference pressure";
+      cdf_put_att_text(fileID, p0varid, "long_name", strlen(longname), longname);
+      static const char units[] = "Pa";
+      cdf_put_att_text(fileID, p0varid, "units", strlen(units), units);
+    }
+
+  char zname[CDI_MAX_NAME]; zname[0] = 0;
+  char zlongname[CDI_MAX_NAME]; zlongname[0] = 0;
+  char zunits[CDI_MAX_NAME]; zunits[0] = 0;
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_NAME, CDI_MAX_NAME, zname);
+  //cdiZaxisInqKeyStr(zaxisID, CDI_KEY_LONGNAME, CDI_MAX_NAME, zlongname);
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_UNITS, CDI_MAX_NAME, zunits);
+  if ( zname[0] ) strcpy(axisname, zname);
+  if ( zlongname[0] == 0 ) strcpy(zlongname, "hybrid sigma pressure coordinate");
+  if ( zunits[0] == 0 ) strcpy(zunits, "1");
 
-          size_t attstrlen = strlen(attstring);
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID, ncvaridp);
+  int ncvarid = *ncvaridp;
 
-	  if ( attlen > 0 && attstring[0] != 0 )
-	    {
-	      if ( strcmp(attname, "history") == 0 )
-		{
-		  streamptr->historyID = iatt;
-		}
-	      else if ( strcmp(attname, "institution") == 0 )
-		{
-		  *instID = institutInq(0, 0, NULL, attstring);
-		  if ( *instID == UNDEFID )
-		    *instID = institutDef(0, 0, NULL, attstring);
-		}
-	      else if ( strcmp(attname, "source") == 0 )
-		{
-		  *modelID = modelInq(-1, 0, attstring);
-		  if ( *modelID == UNDEFID )
-		    *modelID = modelDef(-1, 0, attstring);
-		}
-	      else if ( strcmp(attname, "Source") == 0 )
-		{
-		  if ( strncmp(attstring, "UCLA-LES", 8) == 0 )
-		    *ucla_les = TRUE;
-		}
-	      /*
-	      else if ( strcmp(attname, "Conventions") == 0 )
-		{
-		}
-	      */
-	      else if ( strcmp(attname, "CDI") == 0 )
-		{
-		}
-	      else if ( strcmp(attname, "CDO") == 0 )
-		{
-		}
-              /*
-	      else if ( strcmp(attname, "forecast_reference_time") == 0 )
-		{
-                  memcpy(fcreftime, attstring, attstrlen+1);
-		}
-              */
-	      else if ( strcmp(attname, "grid_file_uri") == 0 )
-		{
-                  memcpy(gridfile, attstring, attstrlen+1);
-		}
-	      else if ( strcmp(attname, "uuidOfHGrid") == 0 && attstrlen == 36 )
-		{
-                  attstring[36] = 0;
-                  cdiStr2UUID(attstring, uuidOfHGrid);
-                  //   printf("uuid: %d %s\n", attlen, attstring);
-		}
-	      else if ( strcmp(attname, "uuidOfVGrid") == 0 && attstrlen == 36 )
-		{
-                  attstring[36] = 0;
-                  cdiStr2UUID(attstring, uuidOfVGrid);
-		}
-	      else
-		{
-                  if ( strcmp(attname, "ICON_grid_file_uri") == 0 && gridfile[0] == 0 )
-                    {
-                      memcpy(gridfile, attstring, attstrlen+1);
-                    }
+  {
+    static const char sname[] = "standard_name",
+      sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate",
+      axis[] = "axis",
+      axis_v[] = "Z",
+      direction[] = "positive",
+      direction_v[] = "down";
+    struct attTxtTab2 tab[] = {
+      { sname, sname_v, sizeof (sname_v) - 1 },
+      { axis, axis_v, sizeof (axis_v) - 1 },
+      { direction, direction_v, sizeof (direction_v) - 1 },
+    };
+    enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
+    for ( size_t i = 0; i < nAtt; ++i )
+      cdf_put_att_text(fileID, ncvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
 
-		  vlistDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)attstrlen, attstring);
-		}
-	    }
-	}
-      else if ( xtype == NC_SHORT || xtype == NC_INT )
-	{
-	  if ( strcmp(attname, "number_of_grid_used") == 0 )
-	    {
-	      (*number_of_grid_used) = UNDEFID;
-	      cdfGetAttInt(fileID, NC_GLOBAL, attname, 1, number_of_grid_used);
-	    }
- 	  else
-            {
-              int attint[attlen];
-              cdfGetAttInt(fileID, NC_GLOBAL, attname, (int)attlen, attint);
-              if ( xtype == NC_SHORT )
-                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT16, (int)attlen, attint);
-              else
-                vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT32, (int)attlen, attint);
-            }
+    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(zlongname), zlongname);
+    cdf_put_att_text(fileID, ncvarid, "units", strlen(zunits), zunits);
+  }
+
+  size_t len = 0;
+  char txt[CDI_MAX_NAME];
+  if ( p0status == 0 )
+    len = (size_t)(sprintf(txt, "%s%s %s%s", "a: a b: b p0: ", p0name, "ps: ", psname));
+  else
+    len = (size_t)(sprintf(txt, "%s%s", "ap: ap b: b ps: ", psname));
+  cdf_put_att_text(fileID, ncvarid, "formula_terms", len, txt);
+
+  int ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+
+  double lbounds[dimlen], ubounds[dimlen], levels[dimlen];
+
+  if ( zaxisInqLevels(zaxisID, NULL) )
+    zaxisInqLevels(zaxisID, levels);
+  else
+    for ( size_t i = 0; i < dimlen; ++i ) levels[i] = i+1;
+
+  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+    {
+      zaxisInqLbounds(zaxisID, lbounds);
+      zaxisInqUbounds(zaxisID, ubounds);
+    }
+  else
+    {
+      for ( size_t i = 0; i < dimlen; ++i ) lbounds[i] = levels[i];
+      for ( size_t i = 0; i < dimlen-1; ++i ) ubounds[i] = levels[i+1];
+      ubounds[dimlen-1] = levels[dimlen-1] + 1;
+    }
+
+  //if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+    {
+      size_t nvertex = 2;
+      if ( dimlen > 1 && nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
+        cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
+
+      if ( nvdimID != CDI_UNDEFID )
+        {
+          size_t axisnameLen = strlen(axisname);
+          axisname[axisnameLen] = '_';
+          memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
+          axisnameLen += sizeof (bndsName);
+          int dimIDs[2] = { *dimID, nvdimID };
+          cdf_def_var(fileID, axisname, (nc_type) xtype, 2, dimIDs, &ncbvarid);
+          cdf_put_att_text(fileID, ncvarid, "bounds", axisnameLen, axisname);
+          {
+            static const char sname[] = "standard_name",
+              sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate";
+            struct attTxtTab2 tab[] = {
+              { sname, sname_v, sizeof (sname_v) - 1 },
+            };
+            enum { nAtt = sizeof (tab) / sizeof (tab[0]) };
+            for ( size_t i = 0; i < nAtt; ++i )
+              cdf_put_att_text(fileID, ncbvarid, tab[i].attName, tab[i].valLen, tab[i].attVal);
+            cdf_put_att_text(fileID, ncbvarid, "units", strlen(zunits), zunits);
+          }
+
+          if ( p0status == 0 )
+            len = (size_t)(sprintf(txt, "%s%s %s%s", "a: a_bnds b: b_bnds p0: ", p0name, "ps: ", psname));
+          else
+            len = (size_t)(sprintf(txt, "%s%s", "ap: ap_bnds b: b_bnds ps: ", psname));
+          cdf_put_att_text(fileID, ncbvarid, "formula_terms", len, txt);
         }
-      else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
-	{
-	  double attflt[attlen];
-	  cdfGetAttDouble(fileID, NC_GLOBAL, attname, (int)attlen, attflt);
-	  if ( xtype == NC_FLOAT )
-	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT32, (int)attlen, attflt);
-	  else
-	    vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT64, (int)attlen, attflt);
-	}
     }
-}
 
-static
-int find_leadtime(int nvars, ncvar_t *ncvars)
-{
-  int leadtime_id = UNDEFID;
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  cdf_put_var_double(fileID, ncvarid, levels);
+
+  if ( p0varid != CDI_UNDEFID ) cdf_put_var_double(fileID, p0varid, &p0value);
+
+  if ( ncbvarid != CDI_UNDEFID )
     {
-      if ( ncvars[ncvarid].stdname[0] )
+      double zbounds[2*dimlen];
+      for ( size_t i = 0; i < dimlen; ++i )
         {
-          if ( strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
-            {
-              leadtime_id = ncvarid;
-              break;
-            }
+          zbounds[2*i  ] = lbounds[i];
+          zbounds[2*i+1] = ubounds[i];
         }
+      cdf_put_var_double(fileID, ncbvarid, zbounds);
     }
 
-  return (leadtime_id);
+  cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID, p0status, p0value);
+
+  if ( *dimID == CDI_UNDEFID )
+    streamptr->zaxisID[zaxisindex] = type == ZAXIS_HYBRID
+      ? streamptr->vct.mlevID : streamptr->vct.ilevID;
 }
 
 static
-void find_time_vars(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, stream_t *streamptr,
-                    int *time_has_units, int *time_has_bounds, int *time_climatology)
+void cdf_def_zaxis_hybrid(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
 {
-  int ncvarid;
+  void (*def_zaxis_hybrid_delegate)(stream_t *streamptr, int type, int *ncvarid, int zaxisID, int zaxisindex, int xtype, size_t dimlen, int *dimID, char *axisname)
+    = ( (!CDI_cmor_mode && cdiConvention == CDI_CONVENTION_ECHAM)
+        || type == ZAXIS_HYBRID_HALF )
+    ? cdf_def_zaxis_hybrid_echam : cdf_def_zaxis_hybrid_cf;
+  def_zaxis_hybrid_delegate(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname);
+}
 
-  if ( timedimid == UNDEFID )
-    {
-      char timeunits[CDI_MAX_NAME];
+static
+void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
+{
+  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
+  zaxisInqUUID(zaxisID, uuidOfVGrid);
 
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  if ( uuidOfVGrid[0] != 0 )
+    {
+      char uuidOfVGridStr[37];
+      cdiUUID2Str(uuidOfVGrid, uuidOfVGridStr);
+      if ( uuidOfVGridStr[0] != 0 && strlen(uuidOfVGridStr) == 36 )
         {
-          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
-            {
-              if ( ncvars[ncvarid].units[0] )
-                {
-                  strcpy(timeunits, ncvars[ncvarid].units);
-                  strtolower(timeunits);
-
-                  if ( isTimeUnits(timeunits) )
-                    {
-                      streamptr->basetime.ncvarid = ncvarid;
-                      break;
-                    }
-                }
-            }
+          int fileID  = streamptr->fileID;
+          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+          cdf_put_att_text(fileID, NC_GLOBAL, "uuidOfVGrid", 36, uuidOfVGridStr);
+          if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
         }
     }
-  else
-    {
-      int ltimevar = FALSE;
+}
 
-      if ( ncdims[timedimid].ncvarid != UNDEFID )
-        {
-          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
-          ltimevar = TRUE;
-        }
+static
+void cdfDefZaxisChar(stream_t *streamptr, int zaxisID, char *axisname, int *dimID, size_t dimlen, int zaxisindex)
+{
+  int fileID  = streamptr->fileID;
+  int ncvarID = CDI_UNDEFID;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-        if ( ncvarid != streamptr->basetime.ncvarid &&
-             ncvars[ncvarid].ndims == 1 &&
-             timedimid == ncvars[ncvarid].dimids[0] &&
-             !xtypeIsText(ncvars[ncvarid].xtype) &&
-             isTimeAxisUnits(ncvars[ncvarid].units) )
-          {
-            ncvars[ncvarid].isvar = FALSE;
+  /* Check StrlenID */
+  char strlen[7] = "strlen\0";
+  size_t clen = (size_t) zaxisInqCLen(zaxisID);
+  if ( clen == 0 )
+    Error("Maximal string length value is 0.\nA given character axis requires a dimension to save the maximal string length.");
+  int strlenID = CDI_UNDEFID;
+  strlenID = checkDimName(fileID, clen, strlen);
 
-            if ( !ltimevar )
-              {
-                streamptr->basetime.ncvarid = ncvarid;
-                ltimevar = TRUE;
-                if ( CDI_Debug )
-                  fprintf(stderr, "timevar %s\n", ncvars[ncvarid].name);
-              }
-            else
-              {
-                Warning("Found more than one time variable, skipped variable %s!", ncvars[ncvarid].name);
-              }
-          }
+  if ( strlenID == CDI_UNDEFID ) cdf_def_dim(fileID, strlen, clen, &strlenID);
 
-      if ( ltimevar == FALSE ) /* search for WRF time description */
-        {
-          for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-            if ( ncvarid != streamptr->basetime.ncvarid &&
-                 ncvars[ncvarid].ndims == 2 &&
-                 timedimid == ncvars[ncvarid].dimids[0] &&
-                 xtypeIsText(ncvars[ncvarid].xtype) &&
-                 ncdims[ncvars[ncvarid].dimids[1]].len == 19 )
-              {
-                streamptr->basetime.ncvarid = ncvarid;
-                streamptr->basetime.lwrf    = TRUE;
-                break;
-              }
-        }
+  /* Check 'areatype'dimID */
+  char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
+  *dimID = checkDimName(fileID, dimlen, dimname);
+  if ( !(dimlen > 0) )
+    Error("No strings delivered for a character axis.");
+  if ( dimname[0] == 0 ) { memcpy(dimname, "area_type", 10); dimname[10] = 0; }
 
-      /* time varID */
-      ncvarid = streamptr->basetime.ncvarid;
+  if ( *dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, dimID);
 
-      if ( ncvarid == UNDEFID )
-        {
-          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
-        }
-    }
+  int dimIDs[2];
+  dimIDs[0] = *dimID;
+  dimIDs[1] = strlenID;
 
-  /* time varID */
-  ncvarid = streamptr->basetime.ncvarid;
+  /* Get Stringvalues */
+  char **cvals = zaxisInqCValsPtr(zaxisID);
 
-  if ( ncvarid != UNDEFID && streamptr->basetime.lwrf == FALSE )
+  if ( cvals )
     {
-      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = TRUE;
+      /* Define variable and its attributes */
+      cdf_def_var(fileID, axisname, NC_CHAR, 2, dimIDs, &ncvarID);
 
-      if ( ncvars[ncvarid].bounds != UNDEFID )
-        {
-          int nbdims = ncvars[ncvars[ncvarid].bounds].ndims;
-          if ( nbdims == 2 )
-            {
-              int len = (int) ncdims[ncvars[ncvars[ncvarid].bounds].dimids[nbdims-1]].len;
-              if ( len == 2 && timedimid == ncvars[ncvars[ncvarid].bounds].dimids[0] )
-                {
-                  *time_has_bounds = TRUE;
-                  streamptr->basetime.ncvarboundsid = ncvars[ncvarid].bounds;
-                  if ( ncvars[ncvarid].climatology ) *time_climatology = TRUE;
-                }
-            }
-        }
-    }
-}
+      cdfPutGridStdAtts(fileID, ncvarID, zaxisID, 'Z', &gridInqsZ);
+      cdf_put_att_text(fileID, ncvarID, "axis", 1, "Z");
+      cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarID);
 
-static
-void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
-{
-  /* find ECHAM VCT */
-  int nvcth_id = UNDEFID, vcta_id = UNDEFID, vctb_id = UNDEFID;
+      streamptr->nczvarID[zaxisindex] = ncvarID;
+      cdf_enddef(fileID);
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].ndims == 1 )
+      /* Write Stringvalues */
+      size_t start[2], count[2];
+      start[1] = 0;
+      count[0] = 1;
+      count[1] = clen;
+      for ( size_t i = 0; i < dimlen; i++ )
         {
-          size_t len = strlen(ncvars[ncvarid].name);
-          if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
-            {
-              if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
-                {
-                  vcta_id = ncvarid;
-                  nvcth_id = ncvars[ncvarid].dimids[0];
-                  ncvars[ncvarid].isvar = FALSE;
-                }
-              else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
-                {
-                  vctb_id = ncvarid;
-                  nvcth_id = ncvars[ncvarid].dimids[0];
-                  ncvars[ncvarid].isvar = FALSE;
-                }
-              else if ( (ncvars[ncvarid].name[2] == 'a' || ncvars[ncvarid].name[2] == 'b') && ncvars[ncvarid].name[3] == 'm' )
-                {
-                  ncvars[ncvarid].isvar = FALSE; // hyam or hybm
-                }
-            }
-	}
+          start[0] = i;
+          nc_put_vara_text(fileID, ncvarID, start, count, cvals[i]);
+        }
     }
 
-  /* read VCT */
-  if ( nvcth_id != UNDEFID && vcta_id != UNDEFID && vctb_id != UNDEFID )
-    {
-      size_t vctsize = ncdims[nvcth_id].len;
-      vctsize *= 2;
-      *vct = (double *) Malloc(vctsize*sizeof(double));
-      cdf_get_var_double(fileID, vcta_id, *vct);
-      cdf_get_var_double(fileID, vctb_id, *vct+vctsize/2);
-      *pvctsize = vctsize;
-    }
+  streamptr->ncmode = 2;
 }
 
-
-int cdfInqContents(stream_t *streamptr)
+static
+void cdfDefZaxis(stream_t *streamptr, int zaxisID)
 {
-  int ndims, nvars, ngatts, unlimdimid;
-  int ncvarid;
-  int ncdimid;
-  size_t ntsteps;
-  int timedimid = -1;
-  int *varids;
-  int nvarids;
-  int time_has_units = FALSE;
-  int time_has_bounds = FALSE;
-  int time_climatology = FALSE;
-  int leadtime_id = UNDEFID;
-  int nvars_data;
-  int instID  = UNDEFID;
-  int modelID = UNDEFID;
-  int taxisID;
-  int i;
-  int calendar = UNDEFID;
-  ncdim_t *ncdims;
-  ncvar_t *ncvars = NULL;
-  int format = 0;
-  int ucla_les = FALSE;
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
-  char gridfile[8912];
-  char fcreftime[CDI_MAX_NAME];
-  int number_of_grid_used = UNDEFID;
-
-  memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
-  memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
-  gridfile[0] = 0;
-  fcreftime[0] = 0;
+  /*  char zaxisname0[CDI_MAX_NAME]; */
+  char axisname[CDI_MAX_NAME];
+  int dimID = CDI_UNDEFID;
+  int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
+  int xtype = zaxisInqDatatype(zaxisID) == CDI_DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
 
   int vlistID = streamptr->vlistID;
   int fileID  = streamptr->fileID;
 
-  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+  int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
 
-#if  defined  (HAVE_NETCDF4)
-  nc_inq_format(fileID, &format);
-#endif
+  int nzaxis = vlistNzaxis(vlistID);
 
-  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+  size_t dimlen = (size_t)zaxisInqSize(zaxisID);
+  int type = zaxisInqType(zaxisID);
 
-  if ( CDI_Debug )
-    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+  int ndims = 1;
 
-  if ( ndims == 0 )
+  if ( dimlen == 1 )
     {
-      Warning("ndims = %d", ndims);
-      return (CDI_EUFSTRUCT);
+      bool is_scalar = zaxisInqScalar(zaxisID) > 0;
+      if ( !is_scalar && CDI_cmor_mode )
+        {
+          is_scalar = true;
+          zaxisDefScalar(zaxisID);
+        }
+
+      if ( is_scalar ) ndims = 0;
+      if ( CDI_reduce_dim ) return;
+
+      switch (type)
+        {
+        case ZAXIS_SURFACE:
+        case ZAXIS_CLOUD_BASE:
+        case ZAXIS_CLOUD_TOP:
+        case ZAXIS_ISOTHERM_ZERO:
+        case ZAXIS_TOA:
+        case ZAXIS_SEA_BOTTOM:
+        case ZAXIS_ATMOSPHERE:
+        case ZAXIS_MEANSEA:
+        case ZAXIS_LAKE_BOTTOM:
+        case ZAXIS_SEDIMENT_BOTTOM:
+        case ZAXIS_SEDIMENT_BOTTOM_TA:
+        case ZAXIS_SEDIMENT_BOTTOM_TW:
+        case ZAXIS_MIX_LAYER:
+          return;
+        }
     }
 
-  /* alloc ncdims */
-  ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
-  init_ncdims(ndims, ncdims);
+  zaxisInqName(zaxisID, axisname);
 
-  if ( nvars > 0 )
+  if ( dimID == CDI_UNDEFID )
     {
-      /* alloc ncvars */
-      ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
-      init_ncvars(nvars, ncvars);
+      checkZaxisName(axisname, fileID, vlistID, zaxisID, nzaxis);
 
-      for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
-        ncvars[ncvarid].ncid = fileID;
-    }
+      char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
+      //cdiZaxisInqKeyStr(zaxisID, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
+      if ( dimname[0] == 0 ) strcpy(dimname, axisname);
 
-#if  defined  (TEST_GROUPS)
-#if  defined  (HAVE_NETCDF4)
-  if ( format == NC_FORMAT_NETCDF4 )
-    {
-      int ncid;
-      int numgrps;
-      int ncids[NC_MAX_VARS];
-      char name1[CDI_MAX_NAME];
-      int gndims, gnvars, gngatts, gunlimdimid;
-      nc_inq_grps(fileID, &numgrps, ncids);
-      for ( int i = 0; i < numgrps; ++i )
-        {
-          ncid = ncids[i];
-          nc_inq_grpname (ncid, name1);
-          cdf_inq(ncid, &gndims , &gnvars, &gngatts, &gunlimdimid);
+      if ( type == ZAXIS_REFERENCE ) cdfDefZaxisUUID(streamptr, zaxisID);
 
-          if ( CDI_Debug )
-            Message("%s: ndims %d, nvars %d, ngatts %d", name1, gndims, gnvars, gngatts);
+      if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
+        {
+          cdf_def_zaxis_hybrid(streamptr, type, &ncvarid, zaxisID, zaxisindex, xtype, dimlen, &dimID, axisname);
 
-          if ( gndims == 0 )
-            {
-            }
+          int natts;
+          cdiInqNatts(zaxisID, CDI_GLOBAL, &natts);
+          if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
+          cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
+          if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
         }
-    }
-#endif
-#endif
+      else if ( type == ZAXIS_CHAR )
+        cdfDefZaxisChar(streamptr, zaxisID, axisname, &dimID, dimlen, zaxisindex);
+      else
+        {
+          dimID = checkDimName(fileID, dimlen, dimname);
 
-  if ( nvars == 0 )
-    {
-      Warning("nvars = %d", nvars);
-      return (CDI_EUFSTRUCT);
-    }
+          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  /* scan global attributes */
-  scan_global_attributes(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
-                         uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
+          if ( ndims && dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
 
-  /* find time dim */
-  if ( unlimdimid >= 0 )
-    timedimid = unlimdimid;
-  else
-    timedimid = cdfTimeDimID(fileID, ndims, nvars);
+          if ( zaxisInqLevels(zaxisID, NULL) )
+            {
+              cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
 
-  streamptr->basetime.ncdimid = timedimid;
+              cdfPutGridStdAtts(fileID, ncvarid, zaxisID, 'Z', &gridInqsZ);
 
-  if ( timedimid != UNDEFID )
-    cdf_inq_dimlen(fileID, timedimid, &ntsteps);
-  else
-    ntsteps = 0;
+              {
+                int positive = zaxisInqPositive(zaxisID);
+                static const char positive_up[] = "up",
+                                  positive_down[] = "down";
+                static const struct attTxtTab tab[2] = {
+                  { positive_up, sizeof (positive_up) - 1 },
+                  { positive_down, sizeof (positive_down) - 1 },
+                };
+                if ( positive == POSITIVE_UP || positive == POSITIVE_DOWN )
+                  {
+                    size_t select = positive == POSITIVE_DOWN;
+                    cdf_put_att_text(fileID, ncvarid, "positive", tab[select].txtLen, tab[select].txt);
+                  }
+              }
+              cdf_put_att_text(fileID, ncvarid, "axis", 1, "Z");
 
-  if ( CDI_Debug ) Message("Number of timesteps = %d", ntsteps);
-  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
+              if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+                {
+                  int nvdimID = CDI_UNDEFID;
+                  size_t nvertex = 2;
+                  if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
+                    cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
 
-  /* read ncdims */
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      cdf_inq_dimlen(fileID, ncdimid, &ncdims[ncdimid].len);
-      cdf_inq_dimname(fileID, ncdimid, ncdims[ncdimid].name);
-      if ( timedimid == ncdimid )
-	ncdims[ncdimid].dimtype = T_AXIS;
-    }
+                  if ( nvdimID != CDI_UNDEFID )
+                    {
+                      size_t axisnameLen = strlen(axisname);
+                      axisname[axisnameLen] = '_';
+                      memcpy(axisname + axisnameLen + 1, bndsName, sizeof (bndsName));
+                      int dimIDs[2];
+                      dimIDs[0] = dimID;
+                      dimIDs[ndims] = nvdimID;
+                      cdf_def_var(fileID, axisname, (nc_type) xtype, ndims+1, dimIDs, &ncbvarid);
+                      cdf_put_att_text(fileID, ncvarid, "bounds", strlen(axisname), axisname);
+                    }
+                }
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "cdfScanVarAttributes");
+              cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
+            }
 
-  /* scan attributes of all variables */
-  cdfScanVarAttributes(nvars, ncvars, ncdims, timedimid, modelID, format);
+          cdf_enddef(fileID);
+          streamptr->ncmode = 2;
 
+          if ( zaxisInqLevels(zaxisID, NULL) )
+            {
+              cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "find coordinate vars");
+              if ( ncbvarid != CDI_UNDEFID )
+                {
+                  double lbounds[dimlen], ubounds[dimlen], zbounds[2*dimlen];
+                  zaxisInqLbounds(zaxisID, lbounds);
+                  zaxisInqUbounds(zaxisID, ubounds);
+                  for ( size_t i = 0; i < dimlen; ++i )
+                    {
+                      zbounds[2*i  ] = lbounds[i];
+                      zbounds[2*i+1] = ubounds[i];
+                    }
 
-  /* find coordinate vars */
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-	{
-	  if ( ncvars[ncvarid].ndims == 1 )
-	    {
-	      if ( timedimid != UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
-		{
-		  if ( ncvars[ncvarid].isvar != FALSE ) cdfSetVar(ncvars, ncvarid, TRUE);
-		}
-	      else
-		{
-                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
-		}
-	      // if ( ncvars[ncvarid].isvar != TRUE ) cdfSetVar(ncvars, ncvarid, FALSE);
+                  cdf_put_var_double(fileID, ncbvarid, zbounds);
+                }
 
-	      if ( ncdimid == ncvars[ncvarid].dimids[0] && ncdims[ncdimid].ncvarid == UNDEFID )
-		if ( strcmp(ncvars[ncvarid].name, ncdims[ncdimid].name) == 0 )
-		  {
-		    ncdims[ncdimid].ncvarid = ncvarid;
-		    ncvars[ncvarid].isvar = FALSE;
-		  }
-	    }
-	}
+              if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
+            }
+        }
     }
 
-  /* find time vars */
-  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
-
-  leadtime_id = find_leadtime(nvars, ncvars);
-  if ( leadtime_id != UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+  if ( dimID != CDI_UNDEFID )
+    streamptr->zaxisID[zaxisindex] = dimID;
+}
 
-  /* check ncvars */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+static
+void cdf_def_mapping(stream_t *streamptr, int gridID)
+{
+  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+  if ( mapping[0] )
     {
-      if ( timedimid != UNDEFID )
-	if ( ncvars[ncvarid].isvar == -1 &&
-	     ncvars[ncvarid].ndims > 1   &&
-	     timedimid == ncvars[ncvarid].dimids[0] )
-	  cdfSetVar(ncvars, ncvarid, TRUE);
+      char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, gmapvarname);
 
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
-	cdfSetVar(ncvars, ncvarid, FALSE);
+      int fileID = streamptr->fileID;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
-	cdfSetVar(ncvars, ncvarid, TRUE);
+      int ncvarid;
+      int ncerrcode = nc_def_var(fileID, gmapvarname, (nc_type) NC_INT, 0, NULL, &ncvarid);
+      if ( ncerrcode == NC_NOERR )
+        cdfDefineAttributes(gridID, CDI_GLOBAL, fileID, ncvarid);
 
-      if ( ncvars[ncvarid].isvar == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
+      cdf_enddef(fileID);
 
-      if ( ncvars[ncvarid].ndims > 4 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("%d dimensional variables are not supported, skipped variable %s!",
-		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
-	  continue;
-	}
+      if ( ncerrcode == NC_NOERR )
+        {
+          int dummy = 1;
+          cdf_put_var_int(fileID, ncvarid, &dummy);
+        }
+    }
+}
 
-      if ( ncvars[ncvarid].ndims == 4 && timedimid == UNDEFID )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("%d dimensional variables without time dimension are not supported, skipped variable %s!",
-		ncvars[ncvarid].ndims, ncvars[ncvarid].name);
-	  continue;
-	}
+static
+void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, int strlen)
+{
+  if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
 
-      if ( xtypeIsText(ncvars[ncvarid].xtype) )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  continue;
-	}
+  size_t dimlen = ( xory == 0 ) ? gridInqXsize(gridID) : gridInqYsize(gridID);
+  int dimID, strlenID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-      if ( cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned) == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unsupported data type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
+  /* Check for all grids up to gridindex whether it already is defined */
 
-      if ( timedimid != UNDEFID && ntsteps == 0 && ncvars[ncvarid].ndims > 0 )
-	{
-	  if ( timedimid == ncvars[ncvarid].dimids[0] )
-	    {
-	      ncvars[ncvarid].isvar = 0;
-	      Warning("Number of time steps undefined, skipped variable %s!", ncvars[ncvarid].name);
-	      continue;
-	    }
-	}
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      int gridID0 = ncgrid[index].gridID;
+      int gridtype0 = gridInqType(gridID0);
+      if ( gridtype0 == GRID_CHARXY )
+        {
+          if ( gridInqXIsc(gridID0) == strlen &&
+               gridInqXsize(gridID0) == dimlen )
+            return;
+          else if ( gridInqYIsc(gridID0) == strlen &&
+               gridInqYsize(gridID0) == dimlen )
+            return;
+        }
     }
 
-  /* verify coordinate vars - first scan (dimname == varname) */
-  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid);
+  int fileID  = streamptr->fileID;
+
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+/* Define Dims */
 
-  /* verify coordinate vars - second scan (all other variables) */
-  verify_coordinate_vars_2(nvars, ncvars);
+  char dimname[CDI_MAX_NAME+3];
+  dimname[0] = 0;
+  if ( xory == 0 )
+    cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, dimname);
+  else
+    cdiGridInqKeyStr(gridID, CDI_KEY_YDIMNAME, CDI_MAX_NAME, dimname);
+  if ( dimname[0] == 0 ) { memcpy(dimname, "region", 7); dimname[6] = 0; }
+  dimID = checkDimName(fileID, dimlen, dimname);
+  if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+
+/* Define strlength dim */
+
+  strcpy(dimname, "strlen");
+  strlenID = checkDimName(fileID, strlen, dimname);
+  if ( strlenID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, strlen, &strlenID);
+
+/* Define Variable */
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "verify_coordinate_vars");
+  int dimIDs[2];
+  dimIDs[0] = dimID;
+  dimIDs[1] = strlenID;
 
-  if ( ucla_les == TRUE )
+  char axisname[CDI_MAX_NAME]; axisname[0] = 0;
+  char **cvals = (char **) Malloc(dimlen * sizeof(char *));
+  for ( size_t i = 0; i < dimlen; i++ )
+    cvals[i] = Malloc(strlen * sizeof(char) );
+  int ncaxisid;
+  if ( xory == 0 )
     {
-      for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-	{
-	  ncvarid = ncdims[ncdimid].ncvarid;
-	  if ( ncvarid != -1 )
-	    {
-	      if ( ncdims[ncdimid].dimtype == UNDEFID && ncvars[ncvarid].units[0] == 'm' )
-		{
-		  if      ( ncvars[ncvarid].name[0] == 'x' ) ncdims[ncdimid].dimtype = X_AXIS;
-		  else if ( ncvars[ncvarid].name[0] == 'y' ) ncdims[ncdimid].dimtype = Y_AXIS;
-		  else if ( ncvars[ncvarid].name[0] == 'z' ) ncdims[ncdimid].dimtype = Z_AXIS;
-		}
-	    }
-	}
+      cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, axisname);
+      gridInqXCvals(gridID, cvals);
     }
-  /*
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+  else
     {
-      ncvarid = ncdims[ncdimid].ncvarid;
-      if ( ncvarid != -1 )
-	{
-	  printf("coord var %d %s %s\n", ncvarid, ncvars[ncvarid].name, ncvars[ncvarid].units);
-	  if ( ncdims[ncdimid].dimtype == X_AXIS )
-	    printf("coord var %d %s is x dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == Y_AXIS )
-	    printf("coord var %d %s is y dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == Z_AXIS )
-	    printf("coord var %d %s is z dim\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncdims[ncdimid].dimtype == T_AXIS )
-	    printf("coord var %d %s is t dim\n", ncvarid, ncvars[ncvarid].name);
+      cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, axisname);
+      gridInqXCvals(gridID, cvals);
+    }
+  int status = nc_inq_varid(fileID, axisname, &ncaxisid);
+  if ( status != NC_NOERR )
+    {
+      cdf_def_var(fileID, axisname, NC_CHAR, 2, dimIDs, &ncaxisid);
+      if ( xory == 0 )
+        cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'X', &gridInqsX);
+      else
+        cdfPutGridStdAtts(fileID, ncaxisid, gridID, 'Y', &gridInqsY);
+    }
+  else
+    return;
+  cdf_enddef(fileID);
 
-	  if ( ncvars[ncvarid].islon )
-	    printf("coord var %d %s is lon\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncvars[ncvarid].islat )
-	    printf("coord var %d %s is lat\n", ncvarid, ncvars[ncvarid].name);
-	  if ( ncvars[ncvarid].islev )
-	    printf("coord var %d %s is lev\n", ncvarid, ncvars[ncvarid].name);
-	}
+/* Write Var */
+
+  size_t start[2], count[2];
+  start[1] = 0;
+  count[0] = 1;
+  count[1] = strlen;
+  for (size_t i = 0; i < dimlen; i++)
+    {
+      start[0] = i;
+      status = nc_put_vara_text(fileID, ncaxisid, start, count, cvals[i]);
     }
-  */
 
-  /* Set coordinate varids (att: associate)  */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  ncgrid[gridindex].gridID = gridID;
+  if ( xory == 0 )
     {
-      if ( ncvars[ncvarid].isvar == TRUE && ncvars[ncvarid].ncoordvars )
-	{
-	  /* ndims = ncvars[ncvarid].ndims; */
-	  ndims = ncvars[ncvarid].ncoordvars;
-	  for ( i = 0; i < ndims; i++ )
-	    {
-	      if ( ncvars[ncvars[ncvarid].coordvarids[i]].islon )
-		ncvars[ncvarid].xvarid = ncvars[ncvarid].coordvarids[i];
-	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islat )
-		ncvars[ncvarid].yvarid = ncvars[ncvarid].coordvarids[i];
-	      else if ( ncvars[ncvars[ncvarid].coordvarids[i]].islev )
-		ncvars[ncvarid].zvarid = ncvars[ncvarid].coordvarids[i];
-	    }
-	}
+      ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+      ncgrid[gridindex].ncIDs[CDF_VARID_X] = ncaxisid;
+    }
+  else
+    {
+      ncgrid[gridindex].ncIDs[CDF_DIMID_Y] = dimID;
+      ncgrid[gridindex].ncIDs[CDF_VARID_Y] = ncaxisid;
     }
+  streamptr->ncmode = 2;
+}
+
+static
+void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  /* set dim type */
-  setDimType(nvars, ncvars, ncdims);
+  size_t dimlen = gridInqSize(gridID);
 
-  /* read ECHAM VCT if present */
-  size_t vctsize = 0;
-  double *vct = NULL;
-  read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+  int iz;
+  int dimID;
+  {
+    struct idSearch search
+      = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X,
+                          GRID_GAUSSIAN_REDUCED, (int)dimlen,
+                          gridInqType, gridInqSize);
+    iz = search.numNonMatching;
+    dimID = search.foundID;
+  }
 
+  if ( dimID == CDI_UNDEFID )
+    {
+      int fileID  = streamptr->fileID;
+      static bool lwarn = true;
+      if ( lwarn )
+        {
+          Warning("Creating a NetCDF file with data on a gaussian reduced grid.");
+          Warning("The further processing of the resulting file is unsupported!");
+          lwarn = false;
+        }
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "define_all_grids");
+      char axisname[16] = "rgridX";
+      if ( iz == 0 ) axisname[5] = '\0';
+      else           sprintf(&axisname[5], "%1d", iz+1);
 
-  /* define all grids */
-  define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-  /* define all zaxes */
-  define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
-  if ( vct ) Free(vct);
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
 
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+}
 
-  /* select vars */
-  varids = (int *) Malloc((size_t)nvars * sizeof (int));
-  nvarids = 0;
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    if ( ncvars[ncvarid].isvar == TRUE ) varids[nvarids++] = ncvarid;
+static
+void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+  int iz = 0;
+  int dimID = CDI_UNDEFID;
 
-  nvars_data = nvarids;
+  size_t dimlen = gridInqSize(gridID);
 
-  if ( CDI_Debug ) Message("time varid = %d", streamptr->basetime.ncvarid);
-  if ( CDI_Debug ) Message("ntsteps = %d", ntsteps);
-  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+  if ( gridInqYsize(gridID) == 0 )
+    {
+      struct idSearch search
+        = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_X,
+                            GRID_GENERIC, (int)dimlen,
+                            gridInqType, gridInqSize);
+      iz = search.numNonMatching;
+      dimID = search.foundID;
+    }
 
+  if ( gridInqXsize(gridID) == 0 )
+    {
+      struct idSearch search
+        = cdfSearchIDBySize(0, (size_t)gridindex, ncgrid, CDF_DIMID_Y,
+                            GRID_GENERIC, (int)dimlen,
+                            gridInqType, gridInqSize);
+      iz += search.numNonMatching;
+      dimID = search.foundID;
+    }
 
-  if ( nvars_data == 0 )
+  if ( dimID == CDI_UNDEFID )
     {
-      streamptr->ntsteps = 0;
-      return (CDI_EUFSTRUCT);
+      int fileID  = streamptr->fileID;
+      char dimname[CDI_MAX_NAME];
+      strcpy(dimname, "gsize");
+
+      dimID = checkDimName(fileID, dimlen, dimname);
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
     }
 
-  if ( ntsteps == 0 && streamptr->basetime.ncdimid == UNDEFID && streamptr->basetime.ncvarid != UNDEFID )
-    ntsteps = 1;
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ncIDs[CDF_DIMID_X] = dimID;
+}
 
-  streamptr->ntsteps = (long)ntsteps;
+static
+void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
+{
+  if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
 
-  /* define all data variables */
-  define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
+  int gridtype = gridInqType(gridID);
+  size_t size = gridInqSize(gridID);
 
+  if ( CDI_Debug )
+    Message("gridtype = %d  size = %zu", gridtype, size);
 
-  cdiCreateTimesteps(streamptr);
+  if ( CDI_reduce_dim && size == 1 )
+    {
+      // no grid information
+      streamptr->ncgrid[gridindex].gridID = gridID;
+      return;
+    }
 
-  /* time varID */
-  int nctimevarid = streamptr->basetime.ncvarid;
+  if ( gridtype == GRID_GAUSSIAN    ||
+       gridtype == GRID_LONLAT      ||
+       gridtype == GRID_PROJECTION  ||
+       gridtype == GRID_GENERIC )
+    {
+      if ( gridtype == GRID_GENERIC )
+        {
+          if ( size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0 )
+            {
+              // no grid information
+              streamptr->ncgrid[gridindex].gridID = gridID;
+            }
+          else
+            {
+              bool lx = false, ly = false;
+              if ( gridInqXsize(gridID) > 0 /*&& gridInqXvals(gridID, NULL) > 0*/ )
+                {
+                  cdfDefXaxis(streamptr, gridID, gridindex, 1);
+                  lx = true;
+                }
 
-  if ( time_has_units )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+              if ( gridInqYsize(gridID) > 0 /*&& gridInqYvals(gridID, NULL) > 0*/ )
+                {
+                  cdfDefYaxis(streamptr, gridID, gridindex, 1);
+                  ly = true;
+                }
 
-      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
-        {
-          nctimevarid = UNDEFID;
-          streamptr->basetime.ncvarid = UNDEFID;
+              if ( !lx && !ly ) cdfDefGdim(streamptr, gridID, gridindex);
+            }
         }
-
-      if ( leadtime_id != UNDEFID && taxis->type == TAXIS_RELATIVE )
+      else
         {
-          streamptr->basetime.leadtimeid = leadtime_id;
-          taxis->type = TAXIS_FORECAST;
+          int ndims = !(gridtype == GRID_LONLAT && size == 1 && !gridInqHasDims(gridID));
 
-          int timeunit = -1;
-          if ( ncvars[leadtime_id].units[0] != 0 ) timeunit = scanTimeUnit(ncvars[leadtime_id].units);
-          if ( timeunit == -1 ) timeunit = taxis->unit;
-          taxis->fc_unit = timeunit;
+          if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, ndims);
+          if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, ndims);
 
-          setForecastTime(fcreftime, taxis);
+          cdf_def_mapping(streamptr, gridID);
         }
     }
-
-  if ( time_has_bounds )
+  else if ( gridtype == GRID_CURVILINEAR )
     {
-      streamptr->tsteps[0].taxis.has_bounds = TRUE;
-      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = TRUE;
+      cdfDefCurvilinear(streamptr, gridID, gridindex);
     }
-
-  if ( nctimevarid != UNDEFID )
+  else if ( gridtype == GRID_UNSTRUCTURED )
     {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      ptaxisDefName(taxis, ncvars[nctimevarid].name);
-      if ( ncvars[nctimevarid].longname[0] )
-        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+      cdfDefUnstructured(streamptr, gridID, gridindex);
     }
-
-  if ( nctimevarid != UNDEFID )
-    if ( ncvars[nctimevarid].calendar == TRUE )
-      {
-        enum {attstringlen = 8192};
-        char attstring[attstringlen];
-
-	cdfGetAttText(fileID, nctimevarid, "calendar", attstringlen, attstring);
-	strtolower(attstring);
-
-	if ( memcmp(attstring, "standard", 8)  == 0 ||
-	     memcmp(attstring, "gregorian", 9) == 0 )
-	  calendar = CALENDAR_STANDARD;
-	else if ( memcmp(attstring, "none", 4) == 0 )
-	  calendar = CALENDAR_NONE;
-	else if ( memcmp(attstring, "proleptic", 9) == 0 )
-	  calendar = CALENDAR_PROLEPTIC;
-	else if ( memcmp(attstring, "360", 3) == 0 )
-	  calendar = CALENDAR_360DAYS;
-	else if ( memcmp(attstring, "365", 3) == 0 ||
-		  memcmp(attstring, "noleap", 6)  == 0 )
-	  calendar = CALENDAR_365DAYS;
-	else if ( memcmp(attstring, "366", 3)  == 0 ||
-		  memcmp(attstring, "all_leap", 8) == 0 )
-	  calendar = CALENDAR_366DAYS;
-	else
-	  Warning("calendar >%s< unsupported!", attstring);
-      }
-
-  if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
     {
-      taxisID = taxisCreate(TAXIS_FORECAST);
+      cdfDefRgrid(streamptr, gridID, gridindex);
     }
-  else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
+  else if ( gridtype == GRID_SPECTRAL )
     {
-      taxisID = taxisCreate(TAXIS_RELATIVE);
+      cdfDefComplex(streamptr, gridID, gridindex);
+      cdfDefSP(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_FOURIER )
+    {
+      cdfDefComplex(streamptr, gridID, gridindex);
+      cdfDefFC(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_TRAJECTORY )
+    {
+      cdfDefTrajLon(streamptr, gridID, gridindex);
+      cdfDefTrajLat(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_CHARXY )
+    {
+      int strlen = 0;
+      if ( (strlen = gridInqXIsc(gridID)) )
+        cdfDefCharacter(streamptr, gridID, gridindex, 0, strlen);
+      else
+        if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, 1);
+      if ( (strlen = gridInqYIsc(gridID)) )
+        cdfDefCharacter(streamptr, gridID, gridindex, 1, strlen);
+      else
+        if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, 1);
     }
   else
     {
-      taxisID = taxisCreate(TAXIS_ABSOLUTE);
-      if ( !time_has_units )
-	{
-	  taxisDefTunit(taxisID, TUNIT_DAY);
-	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
-	}
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
+}
+
+
+void cdfDefHistory(stream_t *streamptr, int size, const char *history)
+{
+  int ncid = streamptr->fileID;
+  cdf_put_att_text(ncid, NC_GLOBAL, "history", (size_t) size, history);
+}
+
+
+void cdfDefVars(stream_t *streamptr)
+{
+  int vlistID = streamptr->vlistID;
+  if ( vlistID == CDI_UNDEFID )
+    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
 
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
 
-  if ( calendar == UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
+  int ngrids = vlistNgrids(vlistID);
+  if ( 2*ngrids > MAX_GRIDS_PS ) Error("Internal problem! Too many grids per stream (max=%d)\n", MAX_GRIDS_PS);
+  for ( int index = 0; index < 2*ngrids; ++index )
     {
-      calendar = CALENDAR_STANDARD;
+      streamptr->ncgrid[index].gridID = CDI_UNDEFID;
+      for (size_t i = 0; i < CDF_SIZE_ncIDs; ++i)
+        streamptr->ncgrid[index].ncIDs[i] = CDI_UNDEFID;
     }
 
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Wstrict-overflow"
-#endif
-  if ( calendar != UNDEFID )
+  for ( int index = 0; index < ngrids; ++index )
     {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      taxis->calendar = calendar;
-      taxisDefCalendar(taxisID, calendar);
+      int gridID = vlistGrid(vlistID, index);
+      cdfDefGrid(streamptr, gridID, index);
+    }
+  {
+    int index = ngrids-1;
+    for ( int i = 0; i < ngrids; ++i )
+      {
+        int gridID = vlistGrid(vlistID, i);
+        int projID = gridInqProj(gridID);
+        if ( projID != CDI_UNDEFID ) cdfDefGrid(streamptr, projID, ++index);
+      }
+  }
+  int nzaxis = vlistNzaxis(vlistID);
+  for ( int index = 0; index < nzaxis; ++index )
+    {
+      int zaxisID = vlistZaxis(vlistID, index);
+      if ( streamptr->zaxisID[index] == CDI_UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
     }
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic pop
-#endif
-
-  vlistDefTaxis(vlistID, taxisID);
 
-  streamptr->curTsID = 0;
-  streamptr->rtsteps = 1;
+  if ( streamptr->ncmode != 2 )
+    {
+      cdf_enddef(streamptr->fileID);
+      streamptr->ncmode = 2;
+    }
+}
 
-  (void) cdfInqTimestep(streamptr, 0);
+#endif
 
-  cdfCreateRecords(streamptr, 0);
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  /* free ncdims */
-  Free(ncdims);
+#ifdef HAVE_LIBNETCDF
 
-  /* free ncvars */
-  Free(ncvars);
+#include <stdio.h>
+#include <string.h>
 
-  return (0);
-}
 
 static
-void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
+int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis)
 {
-  size_t start[2], count[2];
-  char stvalue[32];
-  start[0] = (size_t) tsID; start[1] = 0;
-  count[0] = 1; count[1] = 19;
-  stvalue[0] = 0;
-  cdf_get_vara_text(fileID, nctimevarid, start, count, stvalue);
-  stvalue[19] = 0;
-  {
-    int year = 1, month = 1, day = 1 , hour = 0, minute = 0, second = 0;
-    if ( strlen(stvalue) == 19 )
-      sscanf(stvalue, "%d-%d-%d_%d:%d:%d", &year, &month, &day, &hour, &minute, &second);
-    taxis->vdate = cdiEncodeDate(year, month, day);
-    taxis->vtime = cdiEncodeTime(hour, minute, second);
-    taxis->type = TAXIS_ABSOLUTE;
-  }
-}
+  int time_bndsid = -1;
+  int dims[2];
 
-static
-double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
-{
-  double timevalue = 0;
-  size_t index = (size_t) tsID;
+  dims[0] = nctimedimid;
 
-  if ( tcache )
-    {
-      if ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
-        {
-          int maxvals = MAX_TIMECACHE_SIZE;
-          tcache->startid = (tsID/MAX_TIMECACHE_SIZE)*MAX_TIMECACHE_SIZE;
-          if ( (tcache->startid + maxvals) > tcache->maxvals ) maxvals = (tcache->maxvals)%MAX_TIMECACHE_SIZE;
-          tcache->size = maxvals;
-          index = (size_t) tcache->startid;
-          // fprintf(stderr, "fill time cache: %d %d %d %d %d\n", tcache->maxvals, tsID, tcache->startid, tcache->startid+maxvals-1, maxvals);
-          for ( int ival = 0; ival < maxvals; ++ival )
-            {
-              cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
-              tcache->cache[ival] = timevalue;
-              index++;
-            }
-        }
+  /* fprintf(stderr, "time has bounds\n"); */
+  static const char bndsName[] = "bnds";
+  if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
+    cdf_def_dim(fileID, bndsName, 2, &dims[1]);
 
-      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
+  const char *bndsAttName, *bndsAttVal;
+  size_t bndsAttValLen;
+  char tmpstr[CDI_MAX_NAME];
+  if ( taxis->climatology )
+    {
+      static const char climatology_bndsName[] = "climatology_bnds",
+        climatology_bndsAttName[] = "climatology";
+      bndsAttName = climatology_bndsAttName;
+      bndsAttValLen = sizeof (climatology_bndsName) - 1;
+      bndsAttVal = climatology_bndsName;
     }
   else
     {
-      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+      size_t taxisnameLen = strlen(taxis_name);
+      memcpy(tmpstr, taxis_name, taxisnameLen);
+      tmpstr[taxisnameLen] = '_';
+      memcpy(tmpstr + taxisnameLen + 1, bndsName, sizeof (bndsName));
+      size_t tmpstrLen = taxisnameLen + sizeof (bndsName);
+      static const char generic_bndsAttName[] = "bounds";
+      bndsAttName = generic_bndsAttName;
+      bndsAttValLen = tmpstrLen;
+      bndsAttVal = tmpstr;
     }
+  cdf_def_var(fileID, bndsAttVal, NC_DOUBLE, 2, dims, &time_bndsid);
+  cdf_put_att_text(fileID, nctimevarid, bndsAttName, bndsAttValLen, bndsAttVal);
 
-  return timevalue;
+  return time_bndsid;
 }
 
-
-int cdfInqTimestep(stream_t * streamptr, int tsID)
+static
+void cdfDefTimeUnits(char *unitstr, taxis_t *taxis0, taxis_t *taxis)
 {
-  long nrecs = 0;
-  double timevalue;
-  int fileID;
-  taxis_t *taxis;
+  if ( taxis->units && taxis->units[0] )
+    {
+      strcpy(unitstr, taxis->units);
+    }
+  else
+    {
+      unitstr[0] = 0;
 
-  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+      if ( taxis0->type == TAXIS_ABSOLUTE )
+        {
+          static const char *const unitstrfmt[3]
+            = { "year as %Y.%f",
+                "month as %Y%m.%f",
+                "day as %Y%m%d.%f" };
+          size_t fmtidx = (taxis0->unit == TUNIT_YEAR ? 0
+                           : (taxis0->unit == TUNIT_MONTH ? 1
+                              : 2));
+          strcpy(unitstr, unitstrfmt[fmtidx]);
+        }
+      else
+        {
+          int year, month, day, hour, minute, second;
+          cdiDecodeDate(taxis->rdate, &year, &month, &day);
+          cdiDecodeTime(taxis->rtime, &hour, &minute, &second);
+
+          int timeunit = taxis->unit  != -1 ? taxis->unit  : TUNIT_HOUR;
+          if      ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
+          else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
+          else if (    timeunit == TUNIT_3HOURS
+                    || timeunit == TUNIT_6HOURS
+                    || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
+
+          sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d",
+                  tunitNamePtr(timeunit), year, month, day, hour, minute, second);
+        }
+    }
+}
 
-  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
+static
+void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
+{
+  unitstr[0] = 0;
 
-  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
-    {
-      cdfCreateRecords(streamptr, tsID);
+  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
+  else if ( timeunit == TUNIT_QUARTER   ) timeunit = TUNIT_MINUTE;
+  else if ( timeunit == TUNIT_30MINUTES ) timeunit = TUNIT_MINUTE;
+  else if (    timeunit == TUNIT_3HOURS
+            || timeunit == TUNIT_6HOURS
+            || timeunit == TUNIT_12HOURS ) timeunit = TUNIT_HOUR;
 
-      taxis = &streamptr->tsteps[tsID].taxis;
-      if ( tsID > 0 )
-	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
+  strcpy(unitstr, tunitNamePtr(timeunit));
+}
 
-      timevalue = tsID;
+static
+void cdfDefCalendar(int fileID, int ncvarid, int calendar)
+{
+  static const struct { int calCode; const char *calStr; } calTab[] = {
+    { CALENDAR_STANDARD, "standard" },
+    { CALENDAR_GREGORIAN, "gregorian" },
+    { CALENDAR_PROLEPTIC, "proleptic_gregorian" },
+    { CALENDAR_NONE, "none" },
+    { CALENDAR_360DAYS, "360_day" },
+    { CALENDAR_365DAYS, "365_day" },
+    { CALENDAR_366DAYS, "366_day" },
+  };
+  enum { calTabSize = sizeof calTab / sizeof calTab[0] };
 
-      int nctimevarid = streamptr->basetime.ncvarid;
-      if ( nctimevarid != UNDEFID )
-	{
-	  fileID = streamptr->fileID;
-	  size_t index  = (size_t)tsID;
+  for ( size_t i = 0; i < calTabSize; ++i )
+    if ( calTab[i].calCode == calendar )
+      {
+        const char *calstr = calTab[i].calStr;
+        size_t len = strlen(calstr);
+        cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
+        break;
+      }
+}
 
-	  if ( streamptr->basetime.lwrf )
-	    {
-              wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
-	    }
-	  else
-	    {
-#if defined (USE_TIMECACHE)
-              if ( streamptr->basetime.timevar_cache == NULL )
-                {
-                  streamptr->basetime.timevar_cache = (timecache_t *) Malloc(MAX_TIMECACHE_SIZE*sizeof(timecache_t));
-                  streamptr->basetime.timevar_cache->size = 0;
-                  streamptr->basetime.timevar_cache->maxvals = streamptr->ntsteps;
-                }
-#endif
-              timevalue = get_timevalue(fileID, nctimevarid, tsID, streamptr->basetime.timevar_cache);
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate, &taxis->vtime);
-	    }
 
-	  int nctimeboundsid = streamptr->basetime.ncvarboundsid;
-	  if ( nctimeboundsid != UNDEFID )
-	    {
-	      size_t start[2], count[2];
-              start[0] = index; count[0] = 1; start[1] = 0; count[1] = 1;
-	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+void cdfDefTime(stream_t* streamptr)
+{
+  int time_varid;
+  int time_dimid;
+  int time_bndsid = -1;
+  static const char default_name[] = "time";
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
+  if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return;
 
-              start[0] = index; count[0] = 1; start[1] = 1; count[1] = 1;
-	      cdf_get_vara_double(fileID, nctimeboundsid, start, count, &timevalue);
-              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+  int fileID = streamptr->fileID;
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
-	    }
+  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-          int leadtimeid = streamptr->basetime.leadtimeid;
-          if ( leadtimeid != UNDEFID )
-            {
-              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
-              cdiSetForecastPeriod(timevalue, taxis);
-            }
-	}
-    }
+  taxis_t *taxis = &streamptr->tsteps[0].taxis;
 
-  streamptr->curTsID = tsID;
-  nrecs = streamptr->tsteps[tsID].nrecs;
+  const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ;
 
-  return ((int) nrecs);
-}
+  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
+  streamptr->basetime.ncdimid = time_dimid;
 
+  nc_type xtype = (taxis->datatype == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
 
-void cdfDefHistory(stream_t *streamptr, int size, const char *history)
-{
-  int ncid = streamptr->fileID;
-  cdf_put_att_text(ncid, NC_GLOBAL, "history", (size_t) size, history);
-}
+  cdf_def_var(fileID, taxis_name, xtype, 1, &time_dimid, &time_varid);
 
+  streamptr->basetime.ncvarid = time_varid;
 
-int cdfInqHistorySize(stream_t *streamptr)
-{
-  size_t size = 0;
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
-    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
+#if  defined  (HAVE_NETCDF4)
+  if ( streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C )
+    {
+      size_t chunk = 512;
+      cdf_def_var_chunking(fileID, time_varid, NC_CHUNKED, &chunk);
+    }
+#endif
 
-  return ((int) size);
-}
+  {
+    static const char timeStr[] = "time";
+    cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr);
+  }
 
+  if ( taxis->longname && taxis->longname[0] )
+    cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);
 
-void cdfInqHistoryString(stream_t *streamptr, char *history)
-{
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
+  if ( taxis->has_bounds )
     {
-      nc_type atttype;
-      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
-
-      if ( atttype == NC_CHAR )
-        {
-          cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
-        }
-#if  defined  (HAVE_NETCDF4)
-      else if ( atttype == NC_STRING )
-        {
-          // ToDo
-          Warning("History attribute with type NC_STRING unsupported!");
-        }
-#endif
+      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
+      streamptr->basetime.ncvarboundsid = time_bndsid;
     }
-}
 
+  {
+    char unitstr[CDI_MAX_NAME];
+    cdfDefTimeUnits(unitstr, &streamptr->tsteps[0].taxis, taxis);
+    size_t len = strlen(unitstr);
+    if ( len )
+      {
+        cdf_put_att_text(fileID, time_varid, "units", len, unitstr);
+        /*
+          if ( taxis->has_bounds )
+          cdf_put_att_text(fileID, time_bndsid, "units", len, unitstr);
+        */
+      }
+  }
 
-void cdfDefVars(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  if ( vlistID == UNDEFID )
-    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
+  if ( taxis->calendar != -1 )
+    {
+      cdfDefCalendar(fileID, time_varid, taxis->calendar);
+      /*
+      if ( taxis->has_bounds )
+        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
+      */
+    }
+
+  if ( taxis->type == TAXIS_FORECAST )
+    {
+      int leadtimeid;
+      cdf_def_var(fileID, "leadtime", xtype, 1, &time_dimid, &leadtimeid);
+      streamptr->basetime.leadtimeid = leadtimeid;
 
-  int ngrids = vlistNgrids(vlistID);
-  int nzaxis = vlistNzaxis(vlistID);
-  /*
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-  */
-  if ( ngrids > 0 )
-    for ( int index = 0; index < ngrids; index++ )
       {
-        int gridID = vlistGrid(vlistID, index);
-        cdfDefGrid(streamptr, gridID);
+        static const char stdname[] = "forecast_period";
+        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
       }
 
-  if ( nzaxis > 0 )
-    for ( int index = 0; index < nzaxis; index++ )
       {
-        int zaxisID = vlistZaxis(vlistID, index);
-        if ( streamptr->zaxisID[index] == UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
+        static const char lname[] = "Time elapsed since the start of the forecast";
+        cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
       }
 
-  /* define time first!!!
-    int nvars  = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int ncvarid = cdfDefVar(streamptr, varID);
+      {
+          char unitstr[CDI_MAX_NAME];
+          cdfDefForecastTimeUnits(unitstr, taxis->fc_unit);
+          size_t len = strlen(unitstr);
+          if ( len )
+            cdf_put_att_text(fileID, leadtimeid, "units", len, unitstr);
+      }
     }
-  */
+
+  cdf_put_att_text(fileID, time_varid, "axis", 1, "T");
+
+  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
 }
+
+
 #endif
 /*
  * Local Variables:
@@ -45078,21 +45094,26 @@ datetimeCmp(DateTime dt1, DateTime dt2)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _STREAM_CGRIBEX_H
-#define _STREAM_CGRIBEX_H
+#ifndef STREAM_CGRIBEX_H
+#define STREAM_CGRIBEX_H
 
 int cgribexScanTimestep1(stream_t * streamptr);
 int cgribexScanTimestep2(stream_t * streamptr);
 int cgribexScanTimestep(stream_t * streamptr);
 
-int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
-		  int unreduced, int *nmiss, double missval);
+int cgribexDecode(int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval);
 
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize);
+		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize);
+
+void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t recsize);
+void cgribex_handle_delete(void *gh);
 
-#endif  /* _STREAM_CGRIBEX_H */
+void cgribexChangeParameterIdentification(void *gh, int code, int ltype, int lev);
+
+#endif  /* STREAM_CGRIBEX_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -45129,17 +45150,12 @@ int cgribexGetGridType(int *isec2)
 
   switch (ISEC2_GridType)
     {
-    case  GRIB1_GTYPE_LATLON:     { if ( ISEC2_Reduced )      break; }
-    case  GRIB1_GTYPE_LATLON_ROT: { gridtype = GRID_LONLAT;   break; }
-    case  GRIB1_GTYPE_LCC:        { gridtype = GRID_LCC;      break; }
-    case  GRIB1_GTYPE_GAUSSIAN:   { if ( ISEC2_Reduced )
-	                              gridtype = GRID_GAUSSIAN_REDUCED;
-                         	    else
-				      gridtype = GRID_GAUSSIAN;
-          	                    break;
-                                  }
-    case  GRIB1_GTYPE_SPECTRAL:   { gridtype = GRID_SPECTRAL; break; }
-    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;      break; }
+    case  GRIB1_GTYPE_LATLON:     { gridtype = GRID_LONLAT;     break; }
+    case  GRIB1_GTYPE_LATLON_ROT: { gridtype = GRID_PROJECTION; break; }
+    case  GRIB1_GTYPE_LCC:        { gridtype = GRID_LCC;        break; }
+    case  GRIB1_GTYPE_GAUSSIAN:   { gridtype = ISEC2_Reduced ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN; break; }
+    case  GRIB1_GTYPE_SPECTRAL:   { gridtype = GRID_SPECTRAL;   break; }
+    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;        break; }
     }
 
   return gridtype;
@@ -45148,9 +45164,7 @@ int cgribexGetGridType(int *isec2)
 static
 bool cgribexGetIsRotated(int *isec2)
 {
-  bool isRotated = (ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT) ? true : false;
-
-  return isRotated;
+  return (ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT);
 }
 
 static
@@ -45211,9 +45225,9 @@ bool cgribexTimeIsFC(int *isec1)
 static
 int cgribexGetTsteptype(int timerange)
 {
-  int tsteptype = TSTEP_INSTANT;
   static bool lprint = true;
 
+  int tsteptype = TSTEP_INSTANT;
   switch ( timerange )
     {
     case  0:  tsteptype = TSTEP_INSTANT;  break;
@@ -45236,15 +45250,21 @@ int cgribexGetTsteptype(int timerange)
 }
 
 static
-void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4, grid_t *grid, int iret)
+void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, int iret)
 {
   bool compyinc = true;
   int gridtype = cgribexGetGridType(isec2);
+  int projtype = (gridtype == GRID_PROJECTION && cgribexGetIsRotated(isec2)) ? CDI_PROJ_RLL : CDI_UNDEFID;
+  if ( gridtype == GRID_LCC )
+    {
+      gridtype = GRID_PROJECTION;
+      projtype = CDI_PROJ_LCC;
+    }
 
   if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
     {
-      int ilat, nlon = 0;
-      for ( ilat = 0; ilat < ISEC2_NumLat; ++ilat )
+      int nlon = 0;
+      for ( int ilat = 0; ilat < ISEC2_NumLat; ++ilat )
         if ( ISEC2_RowLon(ilat) > nlon ) nlon = ISEC2_RowLon(ilat);
       gridtype = GRID_GAUSSIAN;
       ISEC2_NumLon = nlon;
@@ -45254,197 +45274,194 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4,
 
   grid_init(grid);
   cdiGridTypeInit(grid, gridtype, 0);
-  switch (gridtype)
+
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
     {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
-      {
-	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-	  Error("numberOfPoints (%d) and gridSize (%d) differ!", ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = ISEC2_NumLon;
-	grid->ysize = ISEC2_NumLat;
-        if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
-	grid->xinc  = 0;
-	grid->yinc  = 0;
-	grid->xdef  = 0;
-	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
-	  {
-	    if ( grid->xsize > 1 )
-	      {
-                bool recompinc = true;
+      bool ijDirectionIncrementGiven = gribbyte_get_bit(ISEC2_ResFlag, 1);
+      bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
+      if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
 
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
+      size_t nvalues = (size_t) ISEC4_NumValues;
+      size_t nlon = (size_t) ISEC2_NumLon;
+      size_t nlat = (size_t) ISEC2_NumLat;
+      if ( nvalues != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
 
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
-                  {
-                    if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->xsize-1))) <= 2 )
-                      {
-                        recompinc = false;
-                        grid->xinc = ISEC2_LonIncr * 0.001;
-                      }
-                  }
+      grid->size   = nvalues;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
 
-		/* recompute xinc if necessary */
-                if ( recompinc ) grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize-1);
+      if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
+      grid->x.inc  = 0;
+      grid->y.inc  = 0;
+      grid->x.flag = 0;
+      /* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
+      {
+        if ( grid->x.size > 1 )
+          {
+            bool recompinc = true;
 
-		/* correct xinc if necessary */
-		if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
-		  {
-		    double xinc = 360. / grid->xsize;
+            if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-		    if ( fabs(grid->xinc-xinc) > 0.0 )
-		      {
-			grid->xinc = xinc;
-			if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
-		      }
-		  }
-	      }
-	    grid->xfirst = ISEC2_FirstLon * 0.001;
-	    grid->xlast  = ISEC2_LastLon  * 0.001;
-	    grid->xdef   = 2;
-	  }
-	grid->ydef  = 0;
-	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
-	  {
-	    if ( grid->ysize > 1 && compyinc )
-	      {
-                bool recompinc = true;
-		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
+            if ( ijDirectionIncrementGiven && ISEC2_LonIncr > 0 )
+              {
+                if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->x.size-1))) <= 2 )
                   {
-                    if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->ysize-1))) <= 2 )
-                      {
-                        recompinc = false;
-                        grid->yinc = ISEC2_LatIncr * 0.001;
-                      }
+                    recompinc = false;
+                    grid->x.inc = ISEC2_LonIncr * 0.001;
                   }
+              }
 
-		/* recompute yinc if necessary */
-                if ( recompinc ) grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
-	      }
-	    grid->yfirst = ISEC2_FirstLat * 0.001;
-	    grid->ylast  = ISEC2_LastLat  * 0.001;
-	    grid->ydef   = 2;
-	  }
-	break;
-      }
-    case GRID_GAUSSIAN_REDUCED:
-      {
-        grid->np      = ISEC2_NumPar;
-	grid->size    = ISEC4_NumValues;
-        grid->rowlon  = ISEC2_RowLonPtr;
-	grid->nrowlon = ISEC2_NumLat;
-	grid->ysize   = ISEC2_NumLat;
-	grid->xinc    = 0;
-	grid->yinc    = 0;
-	grid->xdef    = 0;
-	/* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
-	  {
-	    if ( grid->xsize > 1 )
-	      {
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
+            /* recompute xinc if necessary */
+            if ( recompinc ) grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size-1);
 
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
-		  grid->xinc = ISEC2_LonIncr * 0.001;
-		else
-		  grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize - 1);
-	      }
-	    grid->xfirst = ISEC2_FirstLon * 0.001;
-	    grid->xlast  = ISEC2_LastLon  * 0.001;
-	    grid->xdef   = 2;
-	  }
-	grid->ydef  = 0;
-	/* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
-	  {
-	    if ( grid->ysize > 1 )
-	      {
-		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
-		  grid->yinc = ISEC2_LatIncr * 0.001;
-		else
-		  grid->yinc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->ysize - 1);
-	      }
-	    grid->yfirst = ISEC2_FirstLat * 0.001;
-	    grid->ylast  = ISEC2_LastLat  * 0.001;
-	    grid->ydef   = 2;
-	  }
-	break;
+            /* correct xinc if necessary */
+            if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
+              {
+                double xinc = 360. / grid->x.size;
+                if ( fabs(grid->x.inc-xinc) > 0.0 )
+                  {
+                    grid->x.inc = xinc;
+                    if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
+                  }
+              }
+          }
+        grid->x.first = ISEC2_FirstLon * 0.001;
+        grid->x.last  = ISEC2_LastLon  * 0.001;
+        grid->x.flag  = 2;
       }
-    case GRID_LCC:
+      grid->y.flag = 0;
+      /* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
       {
-	if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-	  Error("numberOfPoints (%d) and gridSize (%d) differ!",
-		ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
-
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = ISEC2_NumLon;
-	grid->ysize = ISEC2_NumLat;
-
-	grid->lcc_xinc      = ISEC2_Lambert_dx;
-	grid->lcc_yinc      = ISEC2_Lambert_dy;
-	grid->lcc_originLon = ISEC2_FirstLon * 0.001;
-	grid->lcc_originLat = ISEC2_FirstLat * 0.001;
-	grid->lcc_lonParY   = ISEC2_Lambert_Lov * 0.001;
-	grid->lcc_lat1      = ISEC2_Lambert_LatS1 * 0.001;
-	grid->lcc_lat2      = ISEC2_Lambert_LatS2 * 0.001;
-	grid->lcc_projflag  = ISEC2_Lambert_ProjFlag;
-	grid->lcc_scanflag  = ISEC2_ScanFlag;
-
-	grid->xdef   = 0;
-	grid->ydef   = 0;
+        if ( grid->y.size > 1 && compyinc )
+          {
+            bool recompinc = true;
+            if ( ijDirectionIncrementGiven && ISEC2_LatIncr > 0 )
+              {
+                if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->y.size-1))) <= 2 )
+                  {
+                    recompinc = false;
+                    grid->y.inc = ISEC2_LatIncr * 0.001;
+                  }
+              }
 
-	break;
+            /* recompute yinc if necessary */
+            if ( recompinc ) grid->y.inc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->y.size - 1);
+          }
+        grid->y.first = ISEC2_FirstLat * 0.001;
+        grid->y.last  = ISEC2_LastLat  * 0.001;
+        grid->y.flag  = 2;
       }
-    case GRID_SPECTRAL:
+    }
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      bool ijDirectionIncrementGiven = gribbyte_get_bit(ISEC2_ResFlag, 1);
+      bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
+      if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
+      grid->np      = ISEC2_NumPar;
+      grid->size    = (size_t)ISEC4_NumValues;
+      grid->rowlon  = ISEC2_RowLonPtr;
+      grid->nrowlon = (size_t)ISEC2_NumLat;
+      grid->y.size  = (size_t)ISEC2_NumLat;
+      grid->x.inc   = 0;
+      grid->y.inc   = 0;
+      grid->x.flag  = 0;
+      /* if ( ISEC2_FirstLon != 0 || ISEC2_LastLon != 0 ) */
       {
-	grid->size  = ISEC4_NumValues;
-	grid->trunc = ISEC2_PentaJ;
-	if ( ISEC2_RepMode == 2 )
-	  grid->lcomplex = 1;
-	else
-	  grid->lcomplex = 0;
+        if ( grid->x.size > 1 )
+          {
+            if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-	break;
-      }
-    case GRID_GME:
-      {
-	grid->size  = ISEC4_NumValues;
-	grid->nd    = ISEC2_GME_ND;
-	grid->ni    = ISEC2_GME_NI;
-	grid->ni2   = ISEC2_GME_NI2;
-	grid->ni3   = ISEC2_GME_NI3;
-	break;
-      }
-    case GRID_GENERIC:
-      {
-	grid->size  = ISEC4_NumValues;
-	grid->xsize = 0;
-	grid->ysize = 0;
-	break;
+            if ( ijDirectionIncrementGiven && ISEC2_LonIncr > 0 )
+              grid->x.inc = ISEC2_LonIncr * 0.001;
+            else
+              grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size - 1);
+          }
+        grid->x.first = ISEC2_FirstLon * 0.001;
+        grid->x.last  = ISEC2_LastLon  * 0.001;
+        grid->x.flag  = 2;
       }
-    default:
+      grid->y.flag = 0;
+      /* if ( ISEC2_FirstLat != 0 || ISEC2_LastLat != 0 ) */
       {
-	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-	break;
+        if ( grid->y.size > 1 )
+          {
+            if ( ijDirectionIncrementGiven && ISEC2_LatIncr > 0 )
+              grid->y.inc = ISEC2_LatIncr * 0.001;
+            else
+              grid->y.inc = (ISEC2_LastLat - ISEC2_FirstLat) * 0.001 / (grid->y.size - 1);
+          }
+        grid->y.first = ISEC2_FirstLat * 0.001;
+        grid->y.last  = ISEC2_LastLat  * 0.001;
+        grid->y.flag  = 2;
       }
     }
+  else if ( projtype == CDI_PROJ_LCC )
+    {
+      bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
+      if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
+
+      size_t nvalues = (size_t) ISEC4_NumValues;
+      size_t nlon = (size_t) ISEC2_NumLon;
+      size_t nlat = (size_t) ISEC2_NumLat;
+      if ( nvalues != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
 
-  grid->isRotated = FALSE;
-  if ( cgribexGetIsRotated(isec2) )
+      grid->size   = nvalues;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
+
+      grid->x.first = 0;
+      grid->x.last  = 0;
+      grid->x.inc   = ISEC2_Lambert_dx;
+      grid->y.first = 0;
+      grid->y.last  = 0;
+      grid->y.inc   = ISEC2_Lambert_dy;
+      grid->x.flag  = 2;
+      grid->y.flag  = 2;
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      grid->size  = (size_t) ISEC4_NumValues;
+      grid->trunc = ISEC2_PentaJ;
+      grid->lcomplex = (ISEC2_RepMode == 2) ? 1 : 0;
+   }
+  else if ( gridtype == GRID_GME )
+    {
+      grid->size  = (size_t) ISEC4_NumValues;
+      grid->gme.nd  = ISEC2_GME_ND;
+      grid->gme.ni  = ISEC2_GME_NI;
+      grid->gme.ni2 = ISEC2_GME_NI2;
+      grid->gme.ni3 = ISEC2_GME_NI3;
+    }
+  else if ( gridtype == GRID_GENERIC )
+    {
+      grid->size  = (size_t) ISEC4_NumValues;
+      grid->x.size = 0;
+      grid->y.size = 0;
+    }
+  else
     {
-      grid->isRotated = TRUE;
-      grid->ypole     = - ISEC2_LatSP*0.001;
-      grid->xpole     =   ISEC2_LonSP*0.001 - 180;
-      grid->angle     = - FSEC2_RotAngle;
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  grid->type  = gridtype;
+  grid->type = gridtype;
+  grid->projtype = projtype;
+}
+
+static
+void cgribexGetLevel(int *isec1, int *leveltype, int *level1, int *level2)
+{
+  *leveltype = ISEC1_LevelType;
+  *level1 = ISEC1_Level1;
+  *level2 = ISEC1_Level2;
+  if ( *leveltype == GRIB1_LTYPE_ISOBARIC ) *level1 *= 100;
+  else if ( *leveltype == GRIB1_LTYPE_99 || *leveltype == GRIB1_LTYPE_ISOBARIC_PA ) *leveltype = GRIB1_LTYPE_ISOBARIC;
 }
 
 static
 void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, double *fsec2, double *fsec3,
-		      int *isec4, long recsize, off_t position, int datatype, int comptype, int lmv, int iret)
+		      int *isec4, size_t recsize, off_t position, int datatype, int comptype, int lmv, int iret)
 {
   int varID;
   int levelID = 0;
@@ -45457,23 +45474,23 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
   int tsteptype = cgribexGetTsteptype(ISEC1_TimeRange);
   int numavg    = ISEC1_AvgNum;
 
-  int level1  = ISEC1_Level1;
-  int level2  = ISEC1_Level2;
+  int leveltype, level1, level2;
+  cgribexGetLevel(isec1, &leveltype, &level1, &level2);
 
-  /* fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, ISEC1_LevelType); */
+  /* fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype); */
 
-  record->size      = (size_t)recsize;
+  record->size      = recsize;
   record->position  = position;
   record->param     = param;
   record->ilevel    = level1;
   record->ilevel2   = level2;
-  record->ltype     = ISEC1_LevelType;
+  record->ltype     = leveltype;
   record->tsteptype = (short)tsteptype;
 
   grid_t *gridptr = (grid_t*) Malloc(sizeof(*gridptr));
-  cgribexGetGrid(streamptr, isec2, fsec2, isec4, gridptr, iret);
+  cgribexGetGrid(streamptr, isec2, isec4, gridptr, iret);
 
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, gridptr, 0);
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, gridptr, 0);
   int gridID = gridAdded.Id;
   if ( gridAdded.isNew )
     {
@@ -45484,11 +45501,44 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
           gridptr->rowlon = (int*) Malloc(nrowlon * sizeof(int));
           memcpy(gridptr->rowlon, rowlon, nrowlon * sizeof(int));
         }
+      else if ( gridptr->projtype == CDI_PROJ_RLL )
+        {
+          double xpole =   ISEC2_LonSP*0.001 - 180;
+          double ypole = - ISEC2_LatSP*0.001;
+          double angle = - FSEC2_RotAngle;
+          gridDefParamRLL(gridID, xpole, ypole, angle);
+        }
+      else if ( gridptr->projtype == CDI_PROJ_LCC )
+        {
+          double a = 6367470., rf = 0;
+          bool earthIsOblate = gribbyte_get_bit(ISEC2_ResFlag, 2);
+          if ( earthIsOblate ) { a = 6378160.; rf = 297.0; }
+          double xval_0 = ISEC2_FirstLon * 0.001;
+          double yval_0 = ISEC2_FirstLat * 0.001;
+          double lon_0  = ISEC2_Lambert_Lov * 0.001;
+          double lat_1  = ISEC2_Lambert_LatS1 * 0.001;
+          double lat_2  = ISEC2_Lambert_LatS2 * 0.001;
+          bool lsouth = gribbyte_get_bit(ISEC2_Lambert_ProjFlag, 1);
+          if ( lsouth ) { lat_1 = -lat_1; lat_2 = -lat_2; }
+
+          double lat_0 = lat_2;
+          double x_0 = grid_missval;
+          double y_0 = grid_missval;
+
+          if ( proj_lonlat_to_lcc_func )
+            {
+              x_0 = xval_0; y_0 = yval_0;
+              proj_lonlat_to_lcc_func(grid_missval, lon_0, lat_0, lat_1, lat_2, a, rf, (size_t)1, &x_0, &y_0);
+              if ( IS_NOT_EQUAL(x_0, grid_missval) && IS_NOT_EQUAL(y_0, grid_missval) )
+                { x_0 = -x_0; y_0 = -y_0; }
+            }
+          gridDefParamLCC(gridID, grid_missval, lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0);
+        }
     }
   else
     Free(gridptr);
 
-  int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
+  int zaxistype = grib1ltypeToZaxisType(leveltype);
 
   if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
     {
@@ -45498,13 +45548,13 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
       varDefVCT(vctsize, vctptr);
     }
 
-  int lbounds = cgribexGetZaxisHasBounds(ISEC1_LevelType);
+  int lbounds = cgribexGetZaxisHasBounds(leveltype);
 
-  if ( datatype > 32 ) datatype = DATATYPE_PACK32;
-  if ( datatype <  0 ) datatype = DATATYPE_PACK;
+  if ( datatype > 32 ) datatype = CDI_DATATYPE_PACK32;
+  if ( datatype <  0 ) datatype = CDI_DATATYPE_PACK;
 
   varAddRecord(recID, param, gridID, zaxistype, lbounds, level1, level2, 0, 0,
-	       datatype, &varID, &levelID, tsteptype, numavg, ISEC1_LevelType, -1,
+	       datatype, &varID, &levelID, tsteptype, numavg, leveltype, -1,
                NULL, NULL, NULL, NULL, NULL, NULL);
 
   record->varID   = (short)varID;
@@ -45524,10 +45574,9 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
 
   if ( varInqInst(varID) == CDI_UNDEFID )
     {
-      int center, subcenter, instID;
-      center    = ISEC1_CenterID;
-      subcenter = ISEC1_SubCenterID;
-      instID    = institutInq(center, subcenter, NULL, NULL);
+      int center    = ISEC1_CenterID;
+      int subcenter = ISEC1_SubCenterID;
+      int instID    = institutInq(center, subcenter, NULL, NULL);
       if ( instID == CDI_UNDEFID )
 	instID = institutDef(center, subcenter, NULL, NULL);
       varDefInst(varID, instID);
@@ -45535,8 +45584,7 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
 
   if ( varInqModel(varID) == CDI_UNDEFID )
     {
-      int modelID;
-      modelID = modelInq(varInqInst(varID), ISEC1_ModelID, NULL);
+      int modelID = modelInq(varInqInst(varID), ISEC1_ModelID, NULL);
       if ( modelID == CDI_UNDEFID )
 	modelID = modelDef(varInqInst(varID), ISEC1_ModelID, NULL);
       varDefModel(varID, modelID);
@@ -45544,10 +45592,7 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
 
   if ( varInqTable(varID) == CDI_UNDEFID )
     {
-      int tableID;
-
-      tableID = tableInq(varInqModel(varID), ISEC1_CodeTable, NULL);
-
+      int tableID = tableInq(varInqModel(varID), ISEC1_CodeTable, NULL);
       if ( tableID == CDI_UNDEFID )
 	tableID = tableDef(varInqModel(varID), ISEC1_CodeTable, NULL);
       varDefTable(varID, tableID);
@@ -45590,16 +45635,18 @@ void cgribexDecodeHeader(int *isec0, int *isec1, int *isec2, double *fsec2,
   int ipunp = 0, iword = 0;
 
   memset(isec1, 0, 256*sizeof(int));
+  memset(isec2, 0, 32*sizeof(int));
 
   gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, fsec4,
 	   ipunp, (int *) gribbuffer, recsize, &iword, "J", iret);
 
+  if ( !(ISEC1_Sec2Or3Flag & 128) ) isec2[0] = -1; // default generic grid
+
   *lmv = 0;
 
   if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
     {
       double undef_pds, undef_eps;
-
       MCH_get_undef(isec1, &undef_pds, &undef_eps);
       FSEC3_MissVal = undef_pds;
       *lmv = 1;
@@ -45609,9 +45656,9 @@ void cgribexDecodeHeader(int *isec0, int *isec1, int *isec2, double *fsec2,
 static
 compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int trange)
 {
-  compvar_t compVar;
   int tsteptype = cgribexGetTsteptype(trange);
 
+  compvar_t compVar;
   compVar.param     = param;
   compVar.level1    = level1;
   compVar.level2    = level2;
@@ -45624,11 +45671,10 @@ compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int tr
 static inline int
 cgribexVarCompare(compvar_t compVar, record_t record, int flag)
 {
-  int tstepDiff = (!((flag == 0) & (((compVar.tsteptype == TSTEP_INSTANT)
-                                     & (record.tsteptype == TSTEP_INSTANT3))
-                                    |((compVar.tsteptype == TSTEP_INSTANT3)
-                                      & (record.tsteptype == TSTEP_INSTANT)))))
-    & (compVar.tsteptype != record.tsteptype);
+  bool vinst = compVar.tsteptype == TSTEP_INSTANT || compVar.tsteptype == TSTEP_INSTANT2 || compVar.tsteptype == TSTEP_INSTANT3;
+  bool rinst = record.tsteptype == TSTEP_INSTANT || record.tsteptype == TSTEP_INSTANT2 || record.tsteptype == TSTEP_INSTANT3;
+  int tstepDiff = (!((flag == 0) & (vinst && rinst)))
+                & (compVar.tsteptype != record.tsteptype);
   int rstatus = (compVar.param != record.param)
     |           (compVar.level1 != record.ilevel)
     |           (compVar.level2 != record.ilevel2)
@@ -45652,7 +45698,7 @@ cgribexScanTsFixNtsteps(stream_t *streamptr, off_t recpos)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 }
@@ -45666,16 +45712,14 @@ cgribexScanTsConstAdjust(stream_t *streamptr, taxis_t *taxis)
       if ( taxis->vdate == 0 && taxis->vtime == 0 )
 	{
 	  streamptr->ntsteps = 0;
-	  for (int varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+            vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
     }
 }
 
 
-int cgribexScanTimestep1(stream_t * streamptr)
+int cgribexScanTimestep1(stream_t *streamptr)
 {
   double fsec2[512], fsec3[2], *fsec4 = NULL;
   int lmv = 0, iret = 0;
@@ -45684,13 +45728,13 @@ int cgribexScanTimestep1(stream_t * streamptr)
   size_t buffersize = 0;
   int rstatus;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  int leveltype = 0, level1 = 0, level2 = 0, vdate = 0, vtime = 0;
   DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
   size_t readsize;
   unsigned nrecords, recID;
   int nrecs_scanned = 0;
   int datatype;
-  long recsize = 0;
+  size_t recsize = 0;
   bool warn_time = true;
   bool warn_numavg = true;
   int taxisID = -1;
@@ -45698,7 +45742,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
   bool fcast = false;
   int vlistID;
   int comptype;
-  long unzipsize;
+  size_t unzipsize;
   char paramstr[32];
   int nskip = cdiSkipRecords;
 
@@ -45729,7 +45773,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
     }
 
   unsigned nrecs = 0;
-  while ( TRUE )
+  while ( true )
     {
       recsize = gribGetSize(fileID);
       recpos  = fileGetPos(fileID);
@@ -45742,24 +45786,24 @@ int cgribexScanTimestep1(stream_t * streamptr)
 	  streamptr->ntsteps = 1;
 	  break;
 	}
-      if ( (size_t)recsize > buffersize )
+      if ( recsize > buffersize )
 	{
-	  buffersize = (size_t)recsize;
+	  buffersize = recsize;
 	  gribbuffer = Realloc(gribbuffer, buffersize);
 	}
 
-      readsize = (size_t)recsize;
+      readsize = recsize;
       rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
       if ( rstatus ) break;
 
-      comptype = COMPRESS_NONE;
+      comptype = CDI_COMPRESS_NONE;
       if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
 	{
-	  comptype = COMPRESS_SZIP;
+	  comptype = CDI_COMPRESS_SZIP;
 	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	  if ( buffersize < (size_t)unzipsize )
+	  if ( buffersize < unzipsize )
 	    {
-	      buffersize = (size_t)unzipsize;
+	      buffersize = unzipsize;
 	      gribbuffer = Realloc(gribbuffer, buffersize);
 	    }
 	}
@@ -45771,17 +45815,11 @@ int cgribexScanTimestep1(stream_t * streamptr)
       param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
       cdiParamToString(param, paramstr, sizeof(paramstr));
 
-      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-      level1   = ISEC1_Level1;
-      level2   = ISEC1_Level2;
+      cgribexGetLevel(isec1, &leveltype, &level1, &level2);
 
       gribDateTime(isec1, &vdate, &vtime);
 
-      if ( ISEC4_NumBits > 0 && ISEC4_NumBits <= 32 )
-	datatype = ISEC4_NumBits;
-      else
-        datatype = DATATYPE_PACK;
+      datatype = (ISEC4_NumBits > 0 && ISEC4_NumBits <= 32) ? ISEC4_NumBits : CDI_DATATYPE_PACK;
 
       if ( nrecs == 0 )
 	{
@@ -45794,9 +45832,9 @@ int cgribexScanTimestep1(stream_t * streamptr)
 	}
       else
 	{
-	  datetime.date  = vdate;
-	  datetime.time  = vtime;
-	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
+	  datetime.date = vdate;
+	  datetime.time = vtime;
+	  compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
 	  for ( recID = 0; recID < nrecs; recID++ )
 	    {
 	      if ( cgribexVarCompare(compVar, streamptr->tsteps[0].records[recID], 0) == 0 ) break;
@@ -45887,7 +45925,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
     streamptr->tsteps[0].recIDs[recID] = (int)recID;
 
   streamptr->record->buffer     = gribbuffer;
-  streamptr->record->buffersize = (size_t)buffersize;
+  streamptr->record->buffersize = buffersize;
 
   cgribexScanTsFixNtsteps(streamptr, recpos);
   cgribexScanTsConstAdjust(streamptr, taxis);
@@ -45903,15 +45941,15 @@ int cgribexScanTimestep2(stream_t * streamptr)
   int lmv = 0, iret = 0;
   off_t recpos = 0;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  int leveltype = 0, level1 = 0, level2 = 0, vdate = 0, vtime = 0;
   DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
   int varID, gridID;
   size_t readsize;
   int nrecs, recID;
-  long recsize = 0;
+  size_t recsize = 0;
   bool warn_numavg = true;
   int tsteptype;
-  long unzipsize;
+  size_t unzipsize;
   char paramstr[32];
 
   streamptr->curTsID = 1;
@@ -45954,7 +45992,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
 
   int nrecs_scanned = nrecords;
   int rindex = 0;
-  while ( TRUE )
+  while ( true )
     {
       if ( rindex > nrecords ) break;
 
@@ -45965,22 +46003,22 @@ int cgribexScanTimestep2(stream_t * streamptr)
 	  streamptr->ntsteps = 2;
 	  break;
 	}
-      if ( (size_t)recsize > buffersize )
+      if ( recsize > buffersize )
 	{
-	  buffersize = (size_t)recsize;
+	  buffersize = recsize;
 	  gribbuffer = Realloc(gribbuffer, buffersize);
 	}
 
-      readsize = (size_t)recsize;
+      readsize = recsize;
       rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
       if ( rstatus ) break;
 
       if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
 	{
 	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	  if ( buffersize < (size_t)unzipsize )
+	  if ( buffersize < unzipsize )
 	    {
-	      buffersize = (size_t)unzipsize;
+	      buffersize = unzipsize;
 	      gribbuffer = Realloc(gribbuffer, buffersize);
 	    }
 	}
@@ -45993,10 +46031,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
       param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
       cdiParamToString(param, paramstr, sizeof(paramstr));
 
-      if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-      if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-      level1    = ISEC1_Level1;
-      level2    = ISEC1_Level2;
+      cgribexGetLevel(isec1, &leveltype, &level1, &level2);
 
       gribDateTime(isec1, &vdate, &vtime);
 
@@ -46041,7 +46076,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
       datetime.date  = vdate;
       datetime.time  = vtime;
 
-      compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
+      compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
 
       for ( recID = 0; recID < nrecords; recID++ )
 	{
@@ -46062,7 +46097,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
 	    }
 	  else
 	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].records[recID].used = true;
 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
 	    }
 	}
@@ -46077,7 +46112,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
 	    }
 	  else
 	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].records[recID].used = true;
 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
 	    }
 	}
@@ -46085,7 +46120,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
       if ( CDI_Debug )
 	Message("Read record %2d (id=%s lev1=%d lev2=%d) %8d %6d", nrecs_scanned, paramstr, level1, level2, vdate, vtime);
 
-      streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
+      streamptr->tsteps[tsID].records[recID].size = recsize;
 
       if ( cgribexVarCompare(compVar, streamptr->tsteps[tsID].records[recID], 0) != 0 )
 	{
@@ -46118,7 +46153,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
       if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
 	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+          vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
       else
 	{
@@ -46145,13 +46180,13 @@ int cgribexScanTimestep(stream_t * streamptr)
   int rstatus = 0;
   double fsec2[512], fsec3[2], *fsec4 = NULL;
   int lmv = 0, iret = 0;
-  long recsize = 0;
+  size_t recsize = 0;
   off_t recpos = 0;
   void *gribbuffer;
   size_t buffersize = 0;
   int fileID;
   int param = 0;
-  int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
+  int leveltype = 0, level1 = 0, level2 = 0, vdate = 0, vtime = 0;
   DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
   int vrecID, recID;
   bool warn_numavg = true;
@@ -46159,7 +46194,7 @@ int cgribexScanTimestep(stream_t * streamptr)
   int taxisID = -1;
   int rindex, nrecs = 0;
   int nrecs_scanned;
-  long unzipsize;
+  size_t unzipsize;
   char paramstr[32];
 
   /*
@@ -46200,7 +46235,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 
       nrecs_scanned = streamptr->tsteps[0].nallrecs + streamptr->tsteps[1].nrecs*(tsID-1);
       rindex = 0;
-      while ( TRUE )
+      while ( true )
 	{
 	  if ( rindex > nrecs ) break;
 
@@ -46211,15 +46246,15 @@ int cgribexScanTimestep(stream_t * streamptr)
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
 	      break;
 	    }
-	  if ( recsize > 0 && (size_t)recsize > buffersize )
+	  if ( recsize > 0 && recsize > buffersize )
 	    {
-	      buffersize = (size_t)recsize;
+	      buffersize = recsize;
 	      gribbuffer = Realloc(gribbuffer, buffersize);
 	    }
 
 	  if ( rindex >= nrecs ) break;
 
-	  readsize = (size_t)recsize;
+	  readsize = recsize;
 	  rstatus = gribRead(fileID, (unsigned char *)gribbuffer, &readsize);
 	  if ( rstatus )
 	    {
@@ -46231,9 +46266,9 @@ int cgribexScanTimestep(stream_t * streamptr)
 	  if ( gribGetZip(recsize, (unsigned char *)gribbuffer, &unzipsize) > 0 )
 	    {
 	      unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
-	      if ( buffersize < (size_t)unzipsize )
+	      if ( buffersize < unzipsize )
 		{
-		  buffersize = (size_t)unzipsize;
+		  buffersize = unzipsize;
 		  gribbuffer = Realloc(gribbuffer, buffersize);
 		}
 	    }
@@ -46246,10 +46281,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	  param = cdiEncodeParam(ISEC1_Parameter, ISEC1_CodeTable, 255);
           cdiParamToString(param, paramstr, sizeof(paramstr));
 
-	  if ( ISEC1_LevelType == 100 ) ISEC1_Level1 *= 100;
-	  if ( ISEC1_LevelType ==  99 ) ISEC1_LevelType = 100;
-	  level1   = ISEC1_Level1;
-	  level2   = ISEC1_Level2;
+          cgribexGetLevel(isec1, &leveltype, &level1, &level2);
 
 	  gribDateTime(isec1, &vdate, &vtime);
 
@@ -46296,7 +46328,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	  datetime.date  = vdate;
 	  datetime.time  = vtime;
 
-	  compvar_t compVar = cgribexVarSet(param, level1, level2, ISEC1_LevelType, ISEC1_TimeRange);
+	  compvar_t compVar = cgribexVarSet(param, level1, level2, leveltype, ISEC1_TimeRange);
 
 	  for ( vrecID = 0; vrecID < nrecs; vrecID++ )
 	    {
@@ -46316,7 +46348,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 
 	  if ( cdiInventoryMode == 1 )
 	    {
-	      streamptr->tsteps[tsID].records[recID].used = TRUE;
+	      streamptr->tsteps[tsID].records[recID].used = true;
 	      streamptr->tsteps[tsID].recIDs[rindex] = recID;
 	    }
 	  else
@@ -46335,7 +46367,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 		}
 	      else
 		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].records[recID].used = true;
 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
 		}
 	    }
@@ -46353,7 +46385,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	    }
 
 	  streamptr->tsteps[tsID].records[recID].position = recpos;
-	  streamptr->tsteps[tsID].records[recID].size = (size_t)recsize;
+	  streamptr->tsteps[tsID].records[recID].size = recsize;
 
 	  rindex++;
 	}
@@ -46380,7 +46412,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID-1].next   = true;
 	  streamptr->tsteps[tsID].position = recpos;
 	}
 
@@ -46408,8 +46440,8 @@ int cgribexScanTimestep(stream_t * streamptr)
 #endif
 
 #if  defined  (HAVE_LIBCGRIBEX)
-int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
-		  int unreduced, int *nmiss, double missval)
+int cgribexDecode(int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval)
 {
   int status = 0;
   int iret = 0, iword = 0;
@@ -46425,15 +46457,12 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
 
   if ( memtype == MEMTYPE_FLOAT )
     gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
-             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+             (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
   else
     gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
-             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+             (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
 
-  if ( ISEC1_Sec2Or3Flag & 64 )
-    *nmiss = ISEC4_NumValues - ISEC4_NumNonMissValues;
-  else
-    *nmiss = 0;
+  *nmiss = (ISEC1_Sec2Or3Flag & 64) ? ISEC4_NumValues - ISEC4_NumNonMissValues : 0;
 
   if ( ISEC1_CenterID == 215 && (isec1[34] != 0 && isec1[34] != 255) )
     {
@@ -46444,7 +46473,7 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
       if ( memtype == MEMTYPE_FLOAT )
         {
           float *restrict dataf = (float*) data;
-          for ( long i = 0; i < datasize; i++ )
+          for ( size_t i = 0; i < datasize; i++ )
             if ( (fabs(dataf[i]-undef_pds) < undef_eps) || IS_EQUAL(dataf[i],FSEC3_MissVal) ) {
               dataf[i] = (float)missval;
               (*nmiss)++;
@@ -46453,7 +46482,7 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
       else
         {
           double *restrict datad = (double*) data;
-          for ( long i = 0; i < datasize; i++ )
+          for ( size_t i = 0; i < datasize; i++ )
             if ( (fabs(datad[i]-undef_pds) < undef_eps) || IS_EQUAL(datad[i],FSEC3_MissVal) ) {
               datad[i] = missval;
               (*nmiss)++;
@@ -46470,33 +46499,18 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
 static
 void cgribexDefInstitut(int *isec1, int vlistID, int varID)
 {
-  int instID;
-
-  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID )
-    instID = vlistInqInstitut(vlistID);
-  else
-    instID = vlistInqVarInstitut(vlistID, varID);
-
+  int instID = (vlistInqInstitut(vlistID) != CDI_UNDEFID) ? vlistInqInstitut(vlistID) : vlistInqVarInstitut(vlistID, varID);
   if ( instID != CDI_UNDEFID )
     {
-      int center, subcenter;
-      center    = institutInqCenter(instID);
-      subcenter = institutInqSubcenter(instID);
-      ISEC1_CenterID    = center;
-      ISEC1_SubCenterID = subcenter;
+      ISEC1_CenterID    = institutInqCenter(instID);
+      ISEC1_SubCenterID = institutInqSubcenter(instID);
     }
 }
 
 static
 void cgribexDefModel(int *isec1, int vlistID, int varID)
 {
-  int modelID;
-
-  if ( vlistInqModel(vlistID) != CDI_UNDEFID )
-    modelID = vlistInqModel(vlistID);
-  else
-    modelID = vlistInqVarModel(vlistID, varID);
-
+  int modelID = (vlistInqModel(vlistID) != CDI_UNDEFID) ? vlistInqModel(vlistID) : vlistInqVarModel(vlistID, varID);
   if ( modelID != CDI_UNDEFID )
     ISEC1_ModelID = modelInqGribID(modelID);
 }
@@ -46505,9 +46519,7 @@ static
 void cgribexDefParam(int *isec1, int param)
 {
   int pdis, pcat, pnum;
-
   cdiDecodeParam(param, &pnum, &pcat, &pdis);
-
   if ( pnum < 0 ) pnum = -pnum;
 
   static bool lwarn_pdis = true;
@@ -46535,10 +46547,8 @@ static
 int cgribexDefTimerange(int tsteptype, int factor, int calendar,
 			int rdate, int rtime, int vdate, int vtime, int *pip1, int *pip2)
 {
-  int timerange = -1;
   int year, month, day, hour, minute, second;
   int julday1, secofday1, julday2, secofday2, days, secs;
-  int ip1 = 0, ip2 = 0;
 
   cdiDecodeDate(rdate, &year, &month, &day);
   cdiDecodeTime(rtime, &hour, &minute, &second);
@@ -46550,6 +46560,8 @@ int cgribexDefTimerange(int tsteptype, int factor, int calendar,
 
   (void) julday_sub(julday1, secofday1, julday2, secofday2, &days, &secs);
 
+  int timerange = -1;
+  int ip1 = 0, ip2 = 0;
   if ( !(int)(fmod(days*86400.0 + secs, factor)) )
     {
       int ip = (int) ((days*86400.0 + secs)/factor);
@@ -46579,13 +46591,10 @@ static
 int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
 {
   int year, month, day, hour, minute, second;
-  int century = 0;
-  int factor = 1;
-
   cdiDecodeDate(date, &year, &month, &day);
   cdiDecodeTime(time, &hour, &minute, &second);
 
-  century =  year / 100;
+  int century =  year / 100;
 
   ISEC1_Year = year - century*100;
 
@@ -46611,6 +46620,7 @@ int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
 
   ISEC1_Century = century;
 
+  int factor = 1;
   switch (timeunit)
     {
     case TUNIT_MINUTE:    factor =    60; ISEC1_TimeUnit = ISEC1_TABLE4_MINUTE;    break;
@@ -46642,16 +46652,12 @@ void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg,
 
   if ( timetype == TAXIS_RELATIVE )
     {
-      int factor = 1;
-      int rdate, rtime;
-      int ip1 = 0, ip2 = 0;
-      int calendar;
-
-      calendar = taxisInqCalendar(taxisID);
-      rdate    = taxisInqRdate(taxisID);
-      rtime    = taxisInqRtime(taxisID);
+      int calendar = taxisInqCalendar(taxisID);
+      int rdate    = taxisInqRdate(taxisID);
+      int rtime    = taxisInqRtime(taxisID);
 
-      factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+      int factor = cgribexDefDateTime(isec1, timeunit, rdate, rtime);
+      int ip1 = 0, ip2 = 0;
       timerange = cgribexDefTimerange(tsteptype, factor, calendar,
 				      rdate, rtime, vdate, vtime, &ip1, &ip2);
 
@@ -46709,8 +46715,8 @@ void cgribexDefTime(int *isec1, int vdate, int vtime, int tsteptype, int numavg,
 static
 void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridID)
 {
+  bool lrotated = false;
   bool lcurvi = false;
-  static bool lwarning = true;
 
   memset(isec2, 0, 16*sizeof(int));
 
@@ -46722,9 +46728,9 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 
   if ( gridtype == GRID_GENERIC )
     {
-      int gridsize = gridInqSize(gridID);
-      int xsize = gridInqXsize(gridID);
-      int ysize = gridInqYsize(gridID);
+      int gridsize = (int)gridInqSize(gridID);
+      int xsize = (int)gridInqXsize(gridID);
+      int ysize = (int)gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -46748,16 +46754,39 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
-      if ( lwarning && gridInqSize(gridID) > 1 )
-	{
-	  lwarning = false;
-	  Warning("Curvilinear grids are unsupported in GRIB1! Created wrong Grid Description Section!");
-	}
-      gridtype = GRID_LONLAT;
-      lcurvi = true;
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID && gridInqType(projID) == GRID_PROJECTION )
+        {
+          gridID = projID;
+          gridtype = GRID_PROJECTION;
+        }
+      else
+        {
+          static bool lwarning = true;
+          if ( lwarning && gridInqSize(gridID) > 1 )
+            {
+              lwarning = false;
+              Warning("Curvilinear grid is unsupported in GRIB1! Created wrong Grid Description Section!");
+            }
+          lcurvi = true;
+          gridtype = GRID_LONLAT;
+        }
+    }
+
+  if ( gridtype == GRID_PROJECTION )
+    {
+      if ( gridInqProjType(gridID) == CDI_PROJ_RLL )
+        {
+          gridtype = GRID_LONLAT;
+          lrotated = true;
+        }
+      else if ( gridInqProjType(gridID) == CDI_PROJ_LCC )
+        {
+          gridtype = GRID_LCC;
+        }
     }
 
-  ISEC2_Reduced  = FALSE;
+  ISEC2_Reduced  = false;
   ISEC2_ScanFlag = 0;
 
   switch (gridtype)
@@ -46769,45 +46798,38 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
       {
 	double xfirst = 0, xlast = 0, xinc = 0;
 	double yfirst = 0, ylast = 0, yinc = 0;
-        bool isRotated = gridIsRotated(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
           ISEC2_GridType = GRIB1_GTYPE_GAUSSIAN;
-        else if ( gridtype == GRID_LONLAT && isRotated )
+        else if ( gridtype == GRID_LONLAT && lrotated )
 	  ISEC2_GridType = GRIB1_GTYPE_LATLON_ROT;
 	else
 	  ISEC2_GridType = GRIB1_GTYPE_LATLON;
 
-	int nlon = gridInqXsize(gridID);
-	int nlat = gridInqYsize(gridID);
+	int nlon = (int)gridInqXsize(gridID);
+	int nlat = (int)gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
-	    ISEC2_Reduced = TRUE;
+	    ISEC2_Reduced = true;
 	    nlon = 0;
 	    gridInqRowlon(gridID, ISEC2_RowLonPtr);
 	  }
 	else
 	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
+	    if ( nlon == 0 ) nlon = 1;
 	    else
 	      {
-		xfirst = gridInqXval(gridID,      0);
+		xfirst = gridInqXval(gridID, 0);
                 xlast  = gridInqXval(gridID, (lcurvi ? nlon*nlat : nlon) - 1);
-		xinc   = gridInqXinc(gridID);
+		xinc   = fabs(gridInqXinc(gridID));
 	      }
 	  }
 
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
+	if ( nlat == 0 ) nlat = 1;
 	else
 	  {
-	    yfirst = gridInqYval(gridID,      0);
+	    yfirst = gridInqYval(gridID, 0);
             ylast  = gridInqYval(gridID, (lcurvi ? nlon*nlat : nlat) - 1);
 	    yinc   = fabs(gridInqYinc(gridID));
 	  }
@@ -46838,7 +46860,6 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	else
 	  {
 	    ISEC2_LatIncr = (int)lround(yinc*1000);
-	    if ( ISEC2_LatIncr < 0 ) ISEC2_LatIncr = -ISEC2_LatIncr;
 	  }
 
 	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
@@ -46847,51 +46868,64 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
 	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
 
-        ISEC2_ResFlag = ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 ) ? 0 : 128;
+        ISEC2_ResFlag = 0;
+        if ( ISEC2_LatIncr && ISEC2_LonIncr )   gribbyte_set_bit(&ISEC2_ResFlag, 1);
+        if ( gridInqUvRelativeToGrid(gridID) )  gribbyte_set_bit(&ISEC2_ResFlag, 5);
 
-	if ( isRotated )
-	  {
-	    ISEC2_LatSP = - (int)lround(gridInqYpole(gridID) * 1000);
-	    ISEC2_LonSP =   (int)lround((gridInqXpole(gridID) + 180) * 1000);
-            double angle = gridInqAngle(gridID);
+	if ( lrotated )
+          {
+            double xpole = 0, ypole = 0, angle = 0;
+            gridInqParamRLL(gridID, &xpole, &ypole, &angle);
+
+	    ISEC2_LatSP = - (int)lround(ypole * 1000);
+	    ISEC2_LonSP =   (int)lround((xpole + 180) * 1000);
             if ( fabs(angle) > 0 ) angle = -angle;
             FSEC2_RotAngle = angle;
-	  }
-
-	/* East -> West */
-	if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
+          }
 
-	/* South -> North */
-	if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+        ISEC2_ScanFlag = 0;
+	if ( ISEC2_LastLon < ISEC2_FirstLon ) gribbyte_set_bit(&ISEC2_ScanFlag, 1); // East -> West
+	if ( ISEC2_LastLat > ISEC2_FirstLat ) gribbyte_set_bit(&ISEC2_ScanFlag, 2); // South -> North
 
 	break;
       }
     case GRID_LCC:
       {
-	double originLon = 0.0, originLat = 0.0, lonParY = 0.0,
-          lat1 = 0.0, lat2 = 0.0, xincm = 0.0, yincm = 0.0;
-	int projflag = 0, scanflag = 0;
+	int xsize = (int)gridInqXsize(gridID);
+        int ysize = (int)gridInqYsize(gridID);
 
-	int xsize = gridInqXsize(gridID),
-          ysize = gridInqYsize(gridID);
+        double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
+	gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
+	gridVerifyGribParamLCC(grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
+        bool lsouth = (lat_1 < 0);
+        if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; }
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+        double xinc = gridInqXinc(gridID);
+        double yinc = gridInqYinc(gridID);
 
 	ISEC2_GridType = GRIB1_GTYPE_LCC;
 	ISEC2_NumLon   = xsize;
 	ISEC2_NumLat   = ysize;
-	ISEC2_FirstLon = (int)lround(originLon * 1000);
-	ISEC2_FirstLat = (int)lround(originLat * 1000);
-	ISEC2_Lambert_Lov    = (int)lround(lonParY * 1000);
-	ISEC2_Lambert_LatS1  = (int)lround(lat1 * 1000);
-	ISEC2_Lambert_LatS2  = (int)lround(lat2 * 1000);
-	ISEC2_Lambert_dx     = (int)lround(xincm);
-	ISEC2_Lambert_dy     = (int)lround(yincm);
+	ISEC2_FirstLon       = (int)lround(xval_0 * 1000);
+	ISEC2_FirstLat       = (int)lround(yval_0 * 1000);
+	ISEC2_Lambert_Lov    = (int)lround(lon_0 * 1000);
+	ISEC2_Lambert_LatS1  = (int)lround(lat_1 * 1000);
+	ISEC2_Lambert_LatS2  = (int)lround(lat_2 * 1000);
+	ISEC2_Lambert_dx     = (int)lround(xinc);
+	ISEC2_Lambert_dy     = (int)lround(yinc);
 	ISEC2_Lambert_LatSP  = 0;
 	ISEC2_Lambert_LonSP  = 0;
-	ISEC2_Lambert_ProjFlag = projflag;
-	ISEC2_ScanFlag = scanflag;
+	ISEC2_Lambert_ProjFlag = 0;
+        if ( lsouth ) gribbyte_set_bit(&ISEC2_Lambert_ProjFlag, 1);
+
+        bool earthIsOblate = (IS_EQUAL(a, 6378160.) && IS_EQUAL(rf, 297.));
+        ISEC2_ResFlag = 0;
+        if ( ISEC2_Lambert_dx && ISEC2_Lambert_dy ) gribbyte_set_bit(&ISEC2_ResFlag, 1);
+        if ( earthIsOblate )                        gribbyte_set_bit(&ISEC2_ResFlag, 2);
+        if ( gridInqUvRelativeToGrid(gridID) )      gribbyte_set_bit(&ISEC2_ResFlag, 5);
+
+	ISEC2_ScanFlag = 0;
+        gribbyte_set_bit(&ISEC2_ScanFlag, 2); // South -> North
 
 	break;
       }
@@ -46922,10 +46956,12 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
     case GRID_GME:
       {
 	ISEC2_GridType   = GRIB1_GTYPE_GME;
-	ISEC2_GME_ND     = gridInqGMEnd(gridID);
-	ISEC2_GME_NI     = gridInqGMEni(gridID);
-	ISEC2_GME_NI2    = gridInqGMEni2(gridID);
-	ISEC2_GME_NI3    = gridInqGMEni3(gridID);
+        int nd = 0, ni = 0, ni2 = 0, ni3 = 0;
+        gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+	ISEC2_GME_ND     = nd;
+	ISEC2_GME_NI     = ni;
+	ISEC2_GME_NI2    = ni2;
+	ISEC2_GME_NI3    = ni3;
 	ISEC2_GME_AFlag  = 0;
 	ISEC2_GME_LatPP  = 90000;
 	ISEC2_GME_LonPP  = 0;
@@ -46933,20 +46969,45 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	ISEC2_GME_BFlag  = 0;
 	break;
       }
+    case GRID_GENERIC:
+      {
+        ISEC1_Sec2Or3Flag = 0;
+	break;
+      }
     default:
       {
-	Warning("The CGRIBEX library can not store fields on the used grid!");
-	Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+        ISEC1_Sec2Or3Flag = 0;
+	Warning("CGRIBEX library doesn't support %s grids, grid information will be lost!", gridNamePtr(gridtype));
 	break;
       }
     }
+
+
+  if ( cdiGribChangeModeUvRelativeToGrid.active )
+    {
+      // this will overrule/change the UvRelativeToGrid flag;
+      // typically when the wind is rotated with respect to north pole
+      bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
+      if      ( uvRelativeToGrid && !cdiGribChangeModeUvRelativeToGrid.mode )
+        gribbyte_clear_bit(&ISEC2_ResFlag, 5);
+      else if ( !uvRelativeToGrid && cdiGribChangeModeUvRelativeToGrid.mode )
+        gribbyte_set_bit(&ISEC2_ResFlag, 5);
+    }
+}
+
+static
+void isec1DefLevel(int *isec1, int leveltype, int level1, int level2)
+{
+  ISEC1_LevelType = leveltype;
+  ISEC1_Level1    = level1;
+  ISEC1_Level2    = level2;
 }
 
 static
 void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int levelID)
 {
+  char units[CDI_MAX_NAME];
   static bool lwarning_vct = true;
-  double level;
 
   int zaxistype = zaxisInqType(zaxisID);
   int ltype = zaxisInqLtype(zaxisID);
@@ -46954,8 +47015,7 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
   if ( zaxistype == ZAXIS_GENERIC && ltype == 0 )
     {
       Message("Changed zaxis type from %s to %s",
-	      zaxisNamePtr(zaxistype),
-	      zaxisNamePtr(ZAXIS_PRESSURE));
+	      zaxisNamePtr(zaxistype), zaxisNamePtr(ZAXIS_PRESSURE));
       zaxistype = ZAXIS_PRESSURE;
       zaxisChangeType(zaxisID, zaxistype);
       zaxisDefUnits(zaxisID, "Pa");
@@ -46973,9 +47033,7 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
     case ZAXIS_DEPTH_BELOW_SEA:
     case ZAXIS_ISENTROPIC:
       {
-        ISEC1_LevelType = grib_ltype;
-	ISEC1_Level1    = (int) (zaxisInqLevel(zaxisID, levelID));
-	ISEC1_Level2    = 0;
+        isec1DefLevel(isec1, grib_ltype, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
 	break;
       }
     case ZAXIS_CLOUD_BASE:
@@ -46985,26 +47043,17 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
     case ZAXIS_SEA_BOTTOM:
     case ZAXIS_ATMOSPHERE:
       {
-        ISEC1_LevelType = grib_ltype;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
+        isec1DefLevel(isec1, grib_ltype, 0, 0);
 	break;
       }
     case ZAXIS_HYBRID:
     case ZAXIS_HYBRID_HALF:
       {
 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID_LAYER;
-	    ISEC1_Level1    = (int) (zaxisInqLbound(zaxisID, levelID));
-	    ISEC1_Level2    = (int) (zaxisInqUbound(zaxisID, levelID));
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_HYBRID_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
+                        (int)(zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_HYBRID;
-	    ISEC1_Level1    = (int) (zaxisInqLevel(zaxisID, levelID));
-	    ISEC1_Level2    = 0;
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_HYBRID, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
 
 	int vctsize = zaxisInqVctSize(zaxisID);
 	if ( vctsize > 255 )
@@ -47025,33 +47074,25 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
       }
     case ZAXIS_PRESSURE:
       {
-	level = zaxisInqLevel(zaxisID, levelID);
-	if ( level < 0 )
-	  Warning("Pressure level of %f Pa is below zero!", level);
+	double level = zaxisInqLevel(zaxisID, levelID);
+	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
 
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
 	if ( (units[0] != 'P') | (units[1] != 'a') ) level *= 100;
 
 	double dum;
 	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-	  {
-	    grib_ltype = GRIB1_LTYPE_99;
-	  }
+          grib_ltype = GRIB1_LTYPE_ISOBARIC_PA;
 	else
-	  {
-	    level = level/100;
-	  }
-        ISEC1_LevelType = grib_ltype;
-        ISEC1_Level1    = (int) level;
-        ISEC1_Level2    = 0;
+          level = level/100;
+
+        isec1DefLevel(isec1, grib_ltype, (int) level, 0);
 	break;
       }
     case ZAXIS_HEIGHT:
       {
-	level = zaxisInqLevel(zaxisID, levelID);
+	double level = zaxisInqLevel(zaxisID, levelID);
 
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
         if ( units[1] == 'm' && !units[2] )
           {
@@ -47060,61 +47101,39 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
             else if ( units[0] == 'k' ) level *= 1000;
           }
 
-	ISEC1_LevelType = grib_ltype;
-	ISEC1_Level1    = (int) level;
-	ISEC1_Level2    = 0;
-
+        isec1DefLevel(isec1, grib_ltype, (int) level, 0);
 	break;
       }
     case ZAXIS_SIGMA:
       {
 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_SIGMA_LAYER;
-	    ISEC1_Level1    = (int) zaxisInqLbound(zaxisID, levelID);
-	    ISEC1_Level2    = (int) zaxisInqUbound(zaxisID, levelID);
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_SIGMA_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
+                        (int)(zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-            ISEC1_LevelType = GRIB1_LTYPE_SIGMA;
-            ISEC1_Level1    = (int) zaxisInqLevel(zaxisID, levelID);
-            ISEC1_Level2    = 0;
-          }
+          isec1DefLevel(isec1, GRIB1_LTYPE_SIGMA, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
 
 	break;
       }
     case ZAXIS_DEPTH_BELOW_LAND:
       {
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
 
-	double factor;
+	double factor = 100; // default: meter
         if      ( units[0] == 'm' && units[1] == 'm' ) factor =   0.1;
         else if ( units[0] == 'c' && units[1] == 'm' ) factor =   1;
         else if ( units[0] == 'd' && units[1] == 'm' ) factor =  10;
-        else                                           factor = 100; // meter
 
 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH_LAYER;
-	    ISEC1_Level1    = (int) (factor*zaxisInqLbound(zaxisID, levelID));
-	    ISEC1_Level2    = (int) (factor*zaxisInqUbound(zaxisID, levelID));
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH_LAYER, (int) (factor*zaxisInqLbound(zaxisID, levelID)),
+                        (int) (factor*zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH;
-	    ISEC1_Level1    = (int) (factor*zaxisInqLevel(zaxisID, levelID));
-	    ISEC1_Level2    = 0;
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH, (int) (factor*zaxisInqLevel(zaxisID, levelID)), 0);
 
 	break;
       }
     case ZAXIS_GENERIC:
       {
-	ISEC1_LevelType = ltype;
-	ISEC1_Level1    = (int) zaxisInqLevel(zaxisID, levelID);
-	ISEC1_Level2    = 0;
-
+        isec1DefLevel(isec1, ltype, (int)(zaxisInqLevel(zaxisID, levelID)), 0);
 	break;
       }
     default:
@@ -47178,23 +47197,19 @@ void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
 #if  defined  (HAVE_LIBCGRIBEX)
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize)
+		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize)
 {
-  size_t nbytes = 0;
-  int gribsize;
   int iret = 0, iword = 0;
   int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
   float fsec2f[512], fsec3f[2];
   double fsec2[512], fsec3[2];
-  int datatype;
-  int param;
 
   memset(isec1, 0, 256*sizeof(int));
   fsec2[0] = 0; fsec2[1] = 0;
   fsec2f[0] = 0; fsec2f[1] = 0;
 
-  gribsize = (int)(gribbuffersize / sizeof(int));
-  param    = vlistInqVarParam(vlistID, varID);
+  int gribsize = (int)(gribbuffersize / sizeof(int));
+  int param    = vlistInqVarParam(vlistID, varID);
 
   cgribexDefaultSec0(isec0);
   cgribexDefaultSec1(isec1);
@@ -47203,7 +47218,7 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
   cgribexDefInstitut(isec1, vlistID, varID);
   cgribexDefModel(isec1, vlistID, varID);
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  int datatype = vlistInqVarDatatype(vlistID, varID);
 
   cgribexDefParam(isec1, param);
   cgribexDefTime(isec1, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID));
@@ -47212,7 +47227,9 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
   cgribexDefEnsembleVar(isec1, vlistID, varID);
 
-  ISEC4_NumValues = gridInqSize(gridID);
+  cdi_check_gridsize_int_limit("GRIB1", datasize);
+
+  ISEC4_NumValues = (int) datasize;
   ISEC4_NumBits   = grbBitsPerValue(datatype);
 
   if ( nmiss > 0 )
@@ -47248,27 +47265,69 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
   if ( iret ) Error("Problem during GRIB encode (errno = %d)!", iret);
 
-  nbytes = (size_t)iword * sizeof (int);
+  size_t nbytes = (size_t)iword * sizeof(int);
   return nbytes;
 }
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef STREAM_FCOMMON_H
-#define STREAM_FCOMMON_H
 
-#ifndef  _CDI_INT_H
-#endif
 
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
-                       const char *container_name);
+typedef struct
+{
+  void *gribbuffer;
+  size_t gribbuffersize;
+  unsigned char *pds;
+  unsigned char *gds;
+  unsigned char *bms;
+  unsigned char *bds;
+} cgribex_handle;
+
+
+int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
+		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize);
+
+void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t gribbuffersize)
+{
+  cgribex_handle *gh = (cgribex_handle*) Malloc(sizeof(cgribex_handle));
+  gh->gribbuffer = NULL;
+  gh->gribbuffersize = 0;
+  gh->pds = NULL;
+
+  if ( gribbuffersize && gribbuffer )
+    {
+      unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+      long gribrecsize;
+      int status = grib1Sections((unsigned char *)gribbuffer, (long)gribbuffersize, &pds, &gds, &bms, &bds, &gribrecsize);
+      if ( status >= 0 )
+        {
+          gh->gribbuffer = gribbuffer;
+          gh->gribbuffersize = gribbuffersize;
+          gh->pds = pds;
+          gh->gds = gds;
+          gh->bms = bms;
+          gh->bds = bds;
+        }
+    }
+
+  return (void*)gh;
+}
+
+
+void cgribex_handle_delete(void *gh)
+{
+  if ( gh ) Free(gh);
+}
+
+
+void cgribexChangeParameterIdentification(void *gh, int code, int ltype, int lev)
+{
+  if ( !gh ) return;
+
+  unsigned char *pds = ((cgribex_handle*)gh)->pds;
+  if ( !pds ) return;
+
+  pds[8]  = (unsigned char) code;
+  pds[9]  = (unsigned char) ltype;
+  pds[10] = (unsigned char) lev;
+}
 
 #endif
 /*
@@ -47283,22 +47342,11 @@ void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBEXTRA)
 
-
 typedef struct {
   int param;
   int level;
@@ -47310,36 +47358,24 @@ int extInqDatatype(int prec, int number)
   int datatype;
 
   if ( number == 2 )
-    {
-      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_CPX64;
-      else                            datatype = DATATYPE_CPX32;
-    }
+    datatype = (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_CPX64 : CDI_DATATYPE_CPX32;
   else
-    {
-      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-      else                            datatype = DATATYPE_FLT32;
-    }
+    datatype = (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
 
-  return (datatype);
+  return datatype;
 }
 
 static
 void extDefDatatype(int datatype, int *prec, int *number)
 {
 
-  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 &&
-       datatype != DATATYPE_CPX32 && datatype != DATATYPE_CPX64 )
-    datatype = DATATYPE_FLT32;
+  if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 &&
+       datatype != CDI_DATATYPE_CPX32 && datatype != CDI_DATATYPE_CPX64 )
+    datatype = CDI_DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    *number = 2;
-  else
-    *number = 1;
+  *number = (datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64) ? 2 : 1;
 
-  if ( datatype == DATATYPE_FLT64 || datatype == DATATYPE_CPX64 )
-    *prec = DOUBLE_PRECISION;
-  else 
-    *prec = SINGLE_PRECISION;
+  *prec = (datatype == CDI_DATATYPE_FLT64 || datatype == CDI_DATATYPE_CPX64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -47360,7 +47396,7 @@ int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
   *levelID = -1;
 
   status = extRead(fileID, extp);
-  if ( status != 0 ) return (0);
+  if ( status != 0 ) return 0;
 
   extInqHeader(extp, header);
 
@@ -47369,55 +47405,46 @@ int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
 
   *varID = vlistInqVarID(vlistID, icode);
 
-  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
+  if ( *varID == CDI_UNDEFID ) Error("Code %d undefined", icode);
 
   zaxisID = vlistInqVarZaxis(vlistID, *varID);
 
   *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
 
-  return (1);
+  return 1;
 }
 */
 
-void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void extReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
-  int vlistID, fileID;
-  int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
-  int header[4];
-  int varID, gridID;
-  int i, size;
-  double missval;
-  void *extp = streamptr->record->exsep;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
 
   fileSetPos(fileID, recpos, SEEK_SET);
 
-  status = extRead(fileID, extp);
-  if ( status != 0 )
-    Error("Failed to read EXTRA record");
+  void *extp = streamptr->record->exsep;
+  int status = extRead(fileID, extp);
+  if ( status != 0 ) Error("Failed to read EXTRA record");
 
+  int header[4];
   extInqHeader(extp, header);
   extInqDataDP(extp, data);
 
-  missval = vlistInqVarMissval(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  size    = gridInqSize(gridID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( i = 0; i < size; i++ )
+      for ( size_t i = 0; i < size; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -47426,7 +47453,7 @@ void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
     }
   else
     {
-      for ( i = 0; i < 2*size; i+=2 )
+      for ( size_t i = 0; i < 2*size; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -47444,21 +47471,19 @@ void extCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 
 void extDefRecord(stream_t *streamptr)
 {
-  int gridID;
-  int header[4];
   int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
-
-  gridID   = streamptr->record->gridID;
-
   cdiDecodeParam(streamptr->record->param, &pnum, &pcat, &pdis);
+
+  int header[4];
   header[0] = streamptr->record->date;
   header[1] = pnum;
   header[2] = streamptr->record->level;
-  header[3] = gridInqSize(gridID);
+  int gridID = streamptr->record->gridID;
+  cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
+  header[3] = (int) gridInqSize(gridID);
 
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
-
   extDefHeader(extp, header);
 }
 
@@ -47473,13 +47498,13 @@ void extWriteRecord(stream_t *streamptr, const double *data)
 }
 
 static
-void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
+void extAddRecord(stream_t *streamptr, int param, int level, size_t xysize,
 		  size_t recsize, off_t position, int prec, int number)
 {
   int vlistID = streamptr->vlistID;
   int tsID    = streamptr->curTsID;
   int recID   = recordNewEntry(streamptr, tsID);
-  record_t *record  = &streamptr->tsteps[tsID].records[recID];
+  record_t *record = &streamptr->tsteps[tsID].records[recID];
 
   record->size     = recsize;
   record->position = position;
@@ -47489,11 +47514,9 @@ void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
   grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
   grid_init(grid);
   cdiGridTypeInit(grid, GRID_GENERIC, xysize);
-  grid->xsize = xysize;
-  grid->ysize = 0;
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  grid->x.size = xysize;
+  grid->y.size = 0;
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
   int gridID = gridAdded.Id;
   if (!gridAdded.isNew) Free(grid);
   /*
@@ -47513,46 +47536,36 @@ void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
   streamptr->nrecs++;
 
   if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
+    Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
 }
 
 static
 void extScanTimestep1(stream_t *streamptr)
 {
   int header[4];
-  int status;
-  int fileID;
-  int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
   DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
   int varID;
+  off_t recpos = 0;
   long recsize;
-  off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
-  taxis_t *taxis;
-  int vlistID;
+  int recID;
   extcompvar_t compVar, compVar0;
   extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 
   streamptr->curTsID = 0;
 
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
+  int tsID  = tstepsNewEntry(streamptr);
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   if ( tsID != 0 )
     Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  fileID = streamptr->fileID;
+  int fileID = streamptr->fileID;
 
-  nrecs = 0;
-  while ( TRUE )
+  int nrecs = 0;
+  while ( true )
     {
       recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
+      int status = extRead(fileID, extp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 1;
@@ -47562,13 +47575,13 @@ void extScanTimestep1(stream_t *streamptr)
 
       extInqHeader(extp, header);
 
-      vdate   = header[0];
-      vtime   = 0;
-      rcode   = header[1];
-      rlevel  = header[2];
-      rxysize = header[3];
+      int vdate   = header[0];
+      int vtime   = 0;
+      int rcode   = header[1];
+      int rlevel  = header[2];
+      int rxysize = header[3];
 
-      param = cdiEncodeParam(rcode, 255, 255);
+      int param = cdiEncodeParam(rcode, 255, 255);
 
       if ( nrecs == 0 )
 	{
@@ -47604,17 +47617,17 @@ void extScanTimestep1(stream_t *streamptr)
 
   cdi_generate_vars(streamptr);
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
   taxis->type  = TAXIS_ABSOLUTE;
   taxis->vdate = (int)datetime0.date;
   taxis->vtime = (int)datetime0.time;
 
-  vlistID = streamptr->vlistID;
+  int vlistID = streamptr->vlistID;
   vlistDefTaxis(vlistID, taxisID);
 
   vlist_check_contents(vlistID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   if ( nrecords < streamptr->tsteps[0].recordSize )
     {
       streamptr->tsteps[0].recordSize = nrecords;
@@ -47633,7 +47646,7 @@ void extScanTimestep1(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
@@ -47643,9 +47656,7 @@ void extScanTimestep1(stream_t *streamptr)
 	{
 	  streamptr->ntsteps = 0;
 	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
+            vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
     }
 }
@@ -47654,43 +47665,33 @@ static
 int extScanTimestep2(stream_t *streamptr)
 {
   int header[4];
-  int status;
-  int fileID;
-  // int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
   int varID;
   off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
   extcompvar_t compVar, compVar0;
   void *extp = streamptr->record->exsep;
 
   streamptr->curTsID = 1;
 
-  fileID  = streamptr->fileID;
-  vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
 
-  tsID = streamptr->rtsteps;
+  int tsID = streamptr->rtsteps;
   if ( tsID != 1 )
     Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
   cdi_create_records(streamptr, tsID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
   streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[1].recIDs[recID] = -1;
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       varID = streamptr->tsteps[0].records[recID].varID;
       streamptr->tsteps[tsID].records[recID].position =
@@ -47699,10 +47700,10 @@ int extScanTimestep2(stream_t *streamptr)
 	streamptr->tsteps[0].records[recID].size;
     }
 
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
+  for ( int rindex = 0; rindex <= nrecords; rindex++ )
     {
       recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
+      int status = extRead(fileID, extp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 2;
@@ -47712,13 +47713,13 @@ int extScanTimestep2(stream_t *streamptr)
 
       extInqHeader(extp, header);
 
-      vdate  = header[0];
-      vtime  = 0;
-      rcode  = header[1];
-      rlevel = header[2];
+      int vdate  = header[0];
+      int vtime  = 0;
+      int rcode  = header[1];
+      int rlevel = header[2];
       // rxysize = header[3];
 
-      param = cdiEncodeParam(rcode, 255, 255);
+      int param = cdiEncodeParam(rcode, 255, 255);
 
       if ( rindex == 0 )
 	{
@@ -47729,7 +47730,8 @@ int extScanTimestep2(stream_t *streamptr)
 
       compVar.param = param;
       compVar.level = rlevel;
-      nextstep = FALSE;
+      bool nextstep = false;
+      int recID;
       for ( recID = 0; recID < nrecords; recID++ )
 	{
 	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
@@ -47739,11 +47741,11 @@ int extScanTimestep2(stream_t *streamptr)
 	    {
 	      if ( streamptr->tsteps[tsID].records[recID].used )
 		{
-		  nextstep = TRUE;
+		  nextstep = true;
 		}
 	      else
 		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].records[recID].used = true;
 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
 		}
 	      break;
@@ -47752,7 +47754,7 @@ int extScanTimestep2(stream_t *streamptr)
       if ( recID == nrecords )
 	{
 	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       if ( nextstep ) break;
@@ -47771,19 +47773,19 @@ int extScanTimestep2(stream_t *streamptr)
 		  tsID, recID,
 		  streamptr->tsteps[tsID].records[recID].param, param,
 		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       streamptr->tsteps[1].records[recID].position = recpos;
     }
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  int nrecs = 0;
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
 	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+          vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
       else
 	{
@@ -47800,44 +47802,36 @@ int extScanTimestep2(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
-  return (0);
+  return 0;
 }
 
 
 int extInqContents(stream_t *streamptr)
 {
-  int fileID;
-  int status = 0;
-
-  fileID = streamptr->fileID;
-
   streamptr->curTsID = 0;
 
   extScanTimestep1(streamptr);
 
+  int status = 0;
   if ( streamptr->ntsteps == -1 ) status = extScanTimestep2(streamptr);
 
+  int fileID = streamptr->fileID;
   fileSetPos(fileID, 0, SEEK_SET);
 
-  return (status);
+  return status;
 }
 
 static
 long extScanTimestep(stream_t *streamptr)
 {
   int header[4];
-  int status;
-  int fileID;
-  // int rxysize = 0;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
   off_t recpos = 0;
   int recID;
-  int rindex, nrecs = 0;
+  int nrecs = 0;
   extcompvar_t compVar, compVar0;
   void *extp = streamptr->record->exsep;
   /*
@@ -47864,14 +47858,14 @@ long extScanTimestep(stream_t *streamptr)
       for ( recID = 0; recID < nrecs; recID++ )
 	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-      fileID = streamptr->fileID;
+      int fileID = streamptr->fileID;
 
       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
+      for ( int rindex = 0; rindex <= nrecs; rindex++ )
 	{
 	  recpos = fileGetPos(fileID);
-	  status = extRead(fileID, extp);
+	  int status = extRead(fileID, extp);
 	  if ( status != 0 )
 	    {
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
@@ -47881,13 +47875,13 @@ long extScanTimestep(stream_t *streamptr)
 
 	  extInqHeader(extp, header);
 
-	  vdate  = header[0];
-	  vtime  = 0;
-	  rcode  = header[1];
-	  rlevel = header[2];
+	  int vdate  = header[0];
+	  int vtime  = 0;
+	  int rcode  = header[1];
+	  int rlevel = header[2];
 	  // rxysize = header[3];
 
-	  param = cdiEncodeParam(rcode, 255, 255);
+	  int param = cdiEncodeParam(rcode, 255, 255);
 
 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
 	  if ( rindex == nrecs ) continue;
@@ -47929,7 +47923,7 @@ long extScanTimestep(stream_t *streamptr)
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID-1].next   = true;
 	  streamptr->tsteps[tsID].position = recpos;
 	}
 
@@ -47943,131 +47937,54 @@ long extScanTimestep(stream_t *streamptr)
       streamptr->ntsteps = tsID;
     }
 
-  return (streamptr->ntsteps);
+  return streamptr->ntsteps;
 }
 
 
 int extInqTimestep(stream_t *streamptr, int tsID)
 {
-  int nrecs;
-  long ntsteps;
-
   if ( tsID == 0 && streamptr->rtsteps == 0 )
     Error("Call to cdiInqContents missing!");
 
   if ( CDI_Debug )
     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
 
-  ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+  long ntsteps = CDI_UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
     ntsteps = extScanTimestep(streamptr);
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
+  int nrecs = 0;
+  if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
     {
       streamptr->curTsID = tsID;
       nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  return (nrecs);
+  return nrecs;
 }
 
 
-void extReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[4];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *extp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
-
-  for (levID = 0; levID < nlevs; levID++)
-    {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      extRead(fileID, extp);
-      extInqHeader(extp, header);
-      extInqDataDP(extp, &data[levID*gridsize]);
-    }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-
-  *nmiss = 0;
-  if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
-    {
-      for ( i = 0; i < nlevs*gridsize; i++ )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
-    }
-  else
-    {
-      for ( i = 0; i < 2*nlevs*gridsize; i+=2 )
-	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-	  {
-	    data[i] = missval;
-	    (*nmiss)++;
-	  }
-    }
-}
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
-
-void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[4];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
   void *extp = streamptr->record->exsep;
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  int tsid     = streamptr->curTsID;
 
-  currentfilepos = fileGetPos(fileID);
+  off_t currentfilepos = fileGetPos(fileID);
 
   /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
+  int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  off_t recpos = streamptr->tsteps[tsid].records[recID].position;
   fileSetPos(fileID, recpos, SEEK_SET);
   extRead(fileID, extp);
+  int header[4];
   extInqHeader(extp, header);
   extInqDataDP(extp, data);
 
@@ -48076,7 +47993,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( i = 0; i < gridsize; i++ )
+      for ( size_t i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -48085,7 +48002,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
     }
   else
     {
-      for ( i = 0; i < 2*gridsize; i+=2 )
+      for ( size_t i = 0; i < 2*gridsize; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -48095,126 +48012,61 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
+void extReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  double level;
-  int header[4];
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
-
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
-
-  header[0] = streamptr->tsteps[tsID].taxis.vdate;
-  header[1] = pnum;
-  header[3] = gridInqSize(gridID);
-
-  extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
-
-  for ( levID = 0;  levID < nlevs; levID++ )
-    {
-      level = zaxisInqLevel(zaxisID, levID);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
-      header[2] = (int) level;
-      extDefHeader(extp, header);
-      extDefDataDP(extp, &data[levID*gridsize]);
-      extWrite(fileID, extp);
-    }
+  for ( size_t levID = 0; levID < nlevs; levID++)
+    extReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
 }
 
 
 void extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
 {
-  int fileID;
-  int gridID;
-  int zaxisID;
-  double level;
-  int header[4];
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  level    = zaxisInqLevel(zaxisID, levID);
-
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
 
+  int pdis, pcat, pnum;
   cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
+  int header[4];
   header[0] = streamptr->tsteps[tsID].taxis.vdate;
   header[1] = pnum;
-  header[2] = (int) level;
-  header[3] = gridInqSize(gridID);
+  header[2] = (int)(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
+  int gridID = vlistInqVarGrid(vlistID, varID);
+  cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
+  header[3] = (int) gridInqSize(gridID);
 
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
-
   extDefHeader(extp, header);
+
   extDefDataDP(extp, data);
   extWrite(fileID, extp);
 }
 
-#endif /* HAVE_LIBEXTRA */
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#include <stdlib.h>
 
-
-
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name)
+void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
 {
-  int fileID1 = streamptr1->fileID;
-  int fileID2 = streamptr2->fileID;
-
-  int tsID    = streamptr1->curTsID;
-  int vrecID  = streamptr1->tsteps[tsID].curRecID;
-  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
-  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
-  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
-
-  if (fileSetPos(fileID1, recpos, SEEK_SET) != 0)
-    Error("Cannot seek input file for %s record copy!", container_name);
-
-  char *buffer = (char *) Malloc(recsize);
-
-  if (fileRead(fileID1, buffer, recsize) != recsize)
-    Error("Failed to read record from %s file for copying!", container_name);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  if (fileWrite(fileID2, buffer, recsize) != recsize)
-    Error("Failed to write record to %s file when copying!", container_name);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
 
-  Free(buffer);
+  for ( size_t levID = 0;  levID < nlevs; levID++ )
+    extWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
 }
 
+#endif /* HAVE_LIBEXTRA */
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -48224,21 +48076,31 @@ void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *c
  * require-trailing-newline: t
  * End:
  */
-#ifndef _STREAM_GRIBAPI_H
-#define _STREAM_GRIBAPI_H
+#ifndef STREAM_GRIBAPI_H
+#define STREAM_GRIBAPI_H
+
+#ifdef HAVE_LIBGRIB_API
+
 
 int gribapiScanTimestep1(stream_t * streamptr);
 int gribapiScanTimestep2(stream_t * streamptr);
 int gribapiScanTimestep(stream_t * streamptr);
 
-int gribapiDecode(void *gribbuffer, int gribsize, double *data, long datasize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID);
+int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval, int vlistID, int varID);
 
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int ljpeg, void *gribContainer);
 
+int gribapiGetScanningMode(grib_handle *gh);
+void gribapiSetScanningMode(grib_handle *gh, int scanningMode);
+
+void gribapiChangeParameterIdentification(grib_handle *gh, int code, int ltype, int lev);
+
+#endif
+
 #endif  /* _STREAM_GRIBAPI_H */
 /*
  * Local Variables:
@@ -48253,6 +48115,55 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 #endif
 
 
+int cdiDebugExt                        =  0;      //  Debug level for the KNMI extensions
+#ifdef HIRLAM_EXTENSIONS
+// *** RELATED to GRIB only ***
+int cdiGribUseTimeRangeIndicator        = 0;       // normaly cdo looks in grib for attribute called "stepType"
+                                                   // but NWP models such as Harmonie 37h1.2, use "timeRangeIndicator"
+                                                   // where:  0: for instanteneous fields; 4: for accumulated fields
+#endif // HIRLAM_EXTENSIONS
+
+
+// Regarding operation to change parameter identification:
+// change if cdiGribChangeParameterID.active
+struct cdiGribParamChange cdiGribChangeParameterID;
+
+// Used only for CDO module Selmulti
+void streamGrbChangeParameterIdentification(int code, int ltype, int lev)
+{
+  // NOTE this is a "PROXY" function for gribapiChangeParameterIdentification();
+  // This just sets the globals. There are probably better solutions to this.
+  // The parameter change is done by function  gribapiChangeParameterIdentification() in stream_gribapi.c
+  // Setting this control variable to true will cause calling fnc. gribapiChangeParameterIdentification later.
+  // After grib attributes have been changed this variable goes to false.
+  cdiGribChangeParameterID.active = true;
+  cdiGribChangeParameterID.code = code;
+  cdiGribChangeParameterID.ltype = ltype;
+  cdiGribChangeParameterID.lev = lev;
+}
+
+struct cdiGribModeChange cdiGribChangeModeUvRelativeToGrid;
+
+// Used only for CDO module WindTrans
+void streamGrbChangeModeUvRelativeToGrid(int mode)
+{
+  cdiGribChangeModeUvRelativeToGrid.active = true;
+  cdiGribChangeModeUvRelativeToGrid.mode = (mode > 0);
+}
+
+struct cdiGribScanModeChange cdiGribDataScanningMode;
+
+void streamGrbDefDataScanningMode(int scanmode)
+{
+  cdiGribDataScanningMode.active = true;
+  cdiGribDataScanningMode.value = scanmode;
+}
+
+int  streamGrbInqDataScanningMode(void)
+{
+  return cdiGribDataScanningMode.value;
+}
+
 
 int grib1ltypeToZaxisType(int grib_ltype)
 {
@@ -48269,6 +48180,7 @@ int grib1ltypeToZaxisType(int grib_ltype)
     case GRIB1_LTYPE_ATMOSPHERE:         zaxistype = ZAXIS_ATMOSPHERE;             break;
     case GRIB1_LTYPE_MEANSEA:            zaxistype = ZAXIS_MEANSEA;                break;
     case GRIB1_LTYPE_99:
+    case GRIB1_LTYPE_ISOBARIC_PA:
     case GRIB1_LTYPE_ISOBARIC:           zaxistype = ZAXIS_PRESSURE;               break;
     case GRIB1_LTYPE_HEIGHT:             zaxistype = ZAXIS_HEIGHT;                 break;
     case GRIB1_LTYPE_ALTITUDE:           zaxistype = ZAXIS_ALTITUDE;	           break;
@@ -48408,14 +48320,14 @@ int grbBitsPerValue(int datatype)
 {
   int bitsPerValue = 16;
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+  if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
     Error("CDI/GRIB library does not support complex numbers!");
 
   if ( datatype != CDI_UNDEFID )
     {
       if ( datatype > 0 && datatype <= 32 )
 	bitsPerValue = datatype;
-      else if ( datatype == DATATYPE_FLT64 )
+      else if ( datatype == CDI_DATATYPE_FLT64 )
 	bitsPerValue = 24;
       else
 	bitsPerValue = 16;
@@ -48449,7 +48361,7 @@ int grbScanTimestep1(stream_t * streamptr)
 #if  defined  (HAVE_LIBCGRIBEX)
   int filetype  = streamptr->filetype;
 
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     status = cgribexScanTimestep1(streamptr);
 #endif
 #if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
@@ -48470,10 +48382,8 @@ int grbScanTimestep2(stream_t * streamptr)
 #if  defined  (HAVE_LIBCGRIBEX)
   int filetype = streamptr->filetype;
 
-  if ( filetype == FILETYPE_GRB )
-    {
-      status = cgribexScanTimestep2(streamptr);
-    }
+  if ( filetype == CDI_FILETYPE_GRB )
+    status = cgribexScanTimestep2(streamptr);
 #endif
 #if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
   else
@@ -48489,15 +48399,12 @@ static
 int grbScanTimestep(stream_t * streamptr)
 {
   int status = CDI_EUFTYPE;
-  int filetype;
-
-  filetype  = streamptr->filetype;
 
 #if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
-    {
-      status = cgribexScanTimestep(streamptr);
-    }
+  int filetype  = streamptr->filetype;
+
+  if ( filetype == CDI_FILETYPE_GRB )
+    status = cgribexScanTimestep(streamptr);
   else
 #endif
 #ifdef HAVE_LIBGRIB_API
@@ -48513,17 +48420,12 @@ int grbScanTimestep(stream_t * streamptr)
 #if  defined  (HAVE_LIBGRIB)
 int grbInqContents(stream_t * streamptr)
 {
-  int fileID;
-  int status = 0;
-
-  fileID = streamptr->fileID;
-
   streamptr->curTsID = 0;
 
-  status = grbScanTimestep1(streamptr);
-
+  int status = grbScanTimestep1(streamptr);
   if ( status == 0 && streamptr->ntsteps == -1 ) status = grbScanTimestep2(streamptr);
 
+  int fileID = streamptr->fileID;
   fileSetPos(fileID, 0, SEEK_SET);
 
   return status;
@@ -48532,15 +48434,13 @@ int grbInqContents(stream_t * streamptr)
 
 int grbInqTimestep(stream_t * streamptr, int tsID)
 {
-  int ntsteps, nrecs;
-
   if ( tsID == 0 && streamptr->rtsteps == 0 )
     Error("Call to cdiInqContents missing!");
 
   if ( CDI_Debug )
     Message("tsid = %d rtsteps = %d", tsID, streamptr->rtsteps);
 
-  ntsteps = CDI_UNDEFID;
+  int ntsteps = CDI_UNDEFID;
   while ( (tsID + 1) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
     {
       ntsteps = grbScanTimestep(streamptr);
@@ -48551,6 +48451,8 @@ int grbInqTimestep(stream_t * streamptr, int tsID)
 	}
     }
 
+  int nrecs;
+
   if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
     {
       nrecs = 0;
@@ -48571,7 +48473,7 @@ void streamInqGRIBinfo(int streamID, int *intnum, float *fltnum, off_t *bignum)
 
   int filetype = streamptr->filetype;
 
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       int tsID     = streamptr->curTsID;
       int vrecID   = streamptr->tsteps[tsID].curRecID;
@@ -48705,14 +48607,11 @@ int vlistInsertTrivialTileSubtype(int vlistID);
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#if  defined  (HAVE_LIBGRIB_API)
-#include <limits.h>
-#include <stdio.h>
-
+#ifdef HAVE_LIBGRIB_API
 
 
 
-#  include <grib_api.h>
+#include <grib_api.h>
 
 extern int cdiInventoryMode;
 
@@ -48724,6 +48623,14 @@ typedef struct {
   int level2;
   int ltype;
   int tsteptype;
+#ifdef HIRLAM_EXTENSIONS
+    // NOTE: tsteptype MUST be part of attributes used to compare variables!
+    // Modern NWP models (HARMONIE, HIRLAM) use timeRangeIndicator to specify
+    // if the field is instantanous or accumulated.
+    // Both types are typically in the same GRIB-file.
+    // (181; 105, 0, timeRangeIndicator=0) .. instantanous rain
+    // (181; 105, 0, timeRangeIndicator=4) .. accumulated rain  .. both can be in the same grib file
+#endif // HIRLAM_EXTENSIONS
   char name[32];
 
   var_tile_t tiles;
@@ -48887,7 +48794,7 @@ int gribapiGetValidityDateTime(grib_handle *gh, int *vdate, int *vtime)
 	}
 
       {
-	static int lprint = TRUE;
+	static bool lprint = true;
 	extern int grib_calendar;
 	int ryear, rmonth, rday, rhour, rminute, rsecond;
 	int julday, secofday;
@@ -48915,7 +48822,7 @@ int gribapiGetValidityDateTime(grib_handle *gh, int *vdate, int *vtime)
                 if ( lprint )
                   {
                     Warning("Time unit %d unsupported", timeUnits);
-                    lprint = FALSE;
+                    lprint = false;
                   }
                 break;
               }
@@ -48965,9 +48872,9 @@ void grib1GetLevel(grib_handle *gh, int *leveltype, int *lbounds, int *level1, i
 	{
           double dlevel;
 	  GRIB_CHECK(grib_get_double(gh, "level", &dlevel), 0); //2 byte
-	  if ( *leveltype == 100 ) dlevel *= 100;
+	  if ( *leveltype == GRIB1_LTYPE_ISOBARIC ) dlevel *= 100;
 	  if ( dlevel < -2.e9 || dlevel > 2.e9 ) dlevel = 0;
-	  if ( *leveltype == GRIB1_LTYPE_99 ) *leveltype = 100;
+	  if ( *leveltype == GRIB1_LTYPE_99 || *leveltype == GRIB1_LTYPE_ISOBARIC_PA ) *leveltype = GRIB1_LTYPE_ISOBARIC;
 
 	  *level1 = (int) dlevel;
 	  *level2 = 0;
@@ -49119,11 +49026,11 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   int vlistID = streamptr->vlistID;
   int tsID    = streamptr->curTsID;
   int recID   = recordNewEntry(streamptr, tsID);
-  record_t *record  = &streamptr->tsteps[tsID].records[recID];
+  record_t *record = &streamptr->tsteps[tsID].records[recID];
 
   int tsteptype = gribapiGetTsteptype(gh);
   // numavg  = ISEC1_AvgNum;
-  int numavg  = 0;
+  int numavg = 0;
 
   // fprintf(stderr, "param %d %d %d %d\n", param, level1, level2, leveltype1);
 
@@ -49148,12 +49055,54 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   //       I. e. kick the fixed size array and allocate enough space, whatever that may be.
   strncpy(record->varname, varname, sizeof(record->varname));
 
-  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_t *grid = (grid_t *)Malloc(sizeof(*grid));
   gribapiGetGrid(gh, grid);
 
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
   int gridID = gridAdded.Id;
-  if (!gridAdded.isNew) Free(grid);
+  if ( !gridAdded.isNew ) Free(grid);
+  else if ( grid->projtype == CDI_PROJ_RLL )
+    {
+      double xpole = 0, ypole = 0, angle = 0;
+      grib_get_double(gh, "latitudeOfSouthernPoleInDegrees",  &ypole);
+      grib_get_double(gh, "longitudeOfSouthernPoleInDegrees", &xpole);
+      grib_get_double(gh, "angleOfRotation", &angle);
+      xpole -= 180;
+      if ( fabs(ypole) > 0 ) ypole = -ypole; // change from south to north pole
+      if ( fabs(angle) > 0 ) angle = -angle;
+
+      gridDefParamRLL(gridID, xpole, ypole, angle);
+    }
+  else if ( grid->projtype == CDI_PROJ_LCC )
+    {
+      double a = 6367470., rf = 0;
+      long earthIsOblate;
+      grib_get_long(gh, "earthIsOblate", &earthIsOblate);
+      if ( earthIsOblate ) { a = 6378160.; rf = 297.0; }
+      double lon_0, lat_1, lat_2, xval_0, yval_0;
+      long projflag = 0;
+      grib_get_double(gh, "longitudeOfFirstGridPointInDegrees", &xval_0);
+      grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &yval_0);
+      grib_get_double(gh, "LoVInDegrees", &lon_0);
+      grib_get_double(gh, "Latin1InDegrees", &lat_1);
+      grib_get_double(gh, "Latin2InDegrees", &lat_2);
+      grib_get_long(gh, "projectionCentreFlag", &projflag);
+      bool lsouth = gribbyte_get_bit((int)projflag, 1);
+      if ( lsouth ) { lat_1 = -lat_1; lat_2 = -lat_2; }
+
+      double lat_0 = lat_2;
+      double x_0 = grid_missval;
+      double y_0 = grid_missval;
+
+      if ( proj_lonlat_to_lcc_func )
+        {
+          x_0 = xval_0; y_0 = yval_0;
+          proj_lonlat_to_lcc_func(grid_missval, lon_0, lat_0, lat_1, lat_2, a, rf, (size_t)1, &x_0, &y_0);
+          if ( IS_NOT_EQUAL(x_0, grid_missval) && IS_NOT_EQUAL(y_0, grid_missval) )
+            { x_0 = -x_0; y_0 = -y_0; }
+        }
+      gridDefParamLCC(gridID, grid_missval, lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0);
+    }
 
   int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
 
@@ -49181,10 +49130,7 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
         unsigned char uuid[CDI_UUID_SIZE];
         long lpar;
         GRIB_CHECK(grib_get_long(gh, "NV", &lpar), 0);
-        if ( lpar != 6 )
-          {
-            fprintf(stderr, "Warning ...\n");
-          }
+        if ( lpar != 6 ) fprintf(stderr, "Warning ...\n");
         GRIB_CHECK(grib_get_long(gh, "nlev", &lpar), 0);
         int nhlev = (int)lpar;
         GRIB_CHECK(grib_get_long(gh, "numberOfVGridUsed", &lpar), 0);
@@ -49197,8 +49143,8 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
       }
     }
 
-  // if ( datatype > 32 ) datatype = DATATYPE_PACK32;
-  if ( datatype <  0 ) datatype = DATATYPE_PACK;
+  // if ( datatype > 32 ) datatype = CDI_DATATYPE_PACK32;
+  if ( datatype <  0 ) datatype = CDI_DATATYPE_PACK;
 
   stdname[0] = 0;
   longname[0] = 0;
@@ -49249,12 +49195,11 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   if ( grib_get_long(gh, "productDefinitionTemplateNumber", &productDefinitionTemplate) == 0 )
     varDefProductDefinitionTemplate(varID, (int) productDefinitionTemplate);
 
-  int    i;
   long   lval;
   double dval;
 
   if (lread_additional_keys)
-    for ( i = 0; i < cdiNAdditionalGRIBKeys; i++ )
+    for ( int i = 0; i < cdiNAdditionalGRIBKeys; i++ )
       {
         /* note: if the key is not defined, we do not throw an error! */
         if ( grib_get_long(gh, cdiAdditionalGRIBKeys[i], &lval) == 0 )
@@ -49266,10 +49211,9 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   if ( varInqInst(varID) == CDI_UNDEFID )
     {
       long center, subcenter;
-      int instID;
       GRIB_CHECK(grib_get_long(gh, "centre", &center), 0);
       GRIB_CHECK(grib_get_long(gh, "subCentre", &subcenter), 0);
-      instID    = institutInq((int)center, (int)subcenter, NULL, NULL);
+      int instID = institutInq((int)center, (int)subcenter, NULL, NULL);
       if ( instID == CDI_UNDEFID )
 	instID = institutDef((int)center, (int)subcenter, NULL, NULL);
       varDefInst(varID, instID);
@@ -49277,12 +49221,11 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
 
   if ( varInqModel(varID) == CDI_UNDEFID )
     {
-      int modelID;
       long processID;
       if ( grib_get_long(gh, "generatingProcessIdentifier", &processID) == 0 )
 	{
           /* FIXME: assert(processID >= INT_MIN && processID <= INT_MAX) */
-	  modelID = modelInq(varInqInst(varID), (int)processID, NULL);
+	  int modelID = modelInq(varInqInst(varID), (int)processID, NULL);
 	  if ( modelID == CDI_UNDEFID )
 	    modelID = modelDef(varInqInst(varID), (int)processID, NULL);
 	  varDefModel(varID, modelID);
@@ -49292,16 +49235,12 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
   if ( varInqTable(varID) == CDI_UNDEFID )
     {
       int pdis, pcat, pnum;
-
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
 
       if ( pdis == 255 )
 	{
-	  int tableID;
 	  int tabnum = pcat;
-
-	  tableID = tableInq(varInqModel(varID), tabnum, NULL);
-
+	  int tableID = tableInq(varInqModel(varID), tabnum, NULL);
 	  if ( tableID == CDI_UNDEFID )
 	    tableID = tableDef(varInqModel(varID), tabnum, NULL);
 	  varDefTable(varID, tableID);
@@ -49316,7 +49255,7 @@ void gribapiAddRecord(stream_t * streamptr, int param, grib_handle *gh,
 	    varID, param, zaxistype, gridID, levelID);
 }
 
-static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype, 
+static compvar2_t gribapiVarSet(int param, int level1, int level2, int leveltype,
                                 int tsteptype, char *name, var_tile_t tiles_data)
 {
   compvar2_t compVar;
@@ -49369,12 +49308,28 @@ void ensureBufferSize(size_t requiredSize, size_t *curSize, void **buffer)
 }
 
 static
-grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType, long *outUnzipsize)
+grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, void **gribbuffer, int *outDatatype, int *outCompressionType, size_t *outUnzipsize)
 {
-  bool lieee = false;
+  int gribversion = (int)((char*)*gribbuffer)[7];
+
+  if ( gribversion <= 1 )
+    {
+      if ( gribGetZip(recsize, *gribbuffer, outUnzipsize) > 0 )
+        {
+          *outCompressionType = CDI_COMPRESS_SZIP;
+          ensureBufferSize(*outUnzipsize + 100, buffersize, gribbuffer);
+        }
+      else
+        {
+          *outCompressionType = CDI_COMPRESS_NONE;
+        }
+    }
 
   grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize);
-  if(gribEditionNumber(gh) > 1)
+
+  bool lieee = false;
+
+  if ( gribversion > 1 )
     {
       size_t len = 256;
       char typeOfPacking[256];
@@ -49382,40 +49337,29 @@ grib_handle *gribapiGetDiskRepresentation(size_t recsize, size_t *buffersize, vo
       if ( grib_get_string(gh, "packingType", typeOfPacking, &len) == 0 )
         {
           // fprintf(stderr, "packingType %d %s\n", len, typeOfPacking);
-          if      ( strncmp(typeOfPacking, "grid_jpeg", len) == 0 ) *outCompressionType = COMPRESS_JPEG;
-          else if ( strncmp(typeOfPacking, "grid_ccsds", len) == 0 ) *outCompressionType = COMPRESS_SZIP;
+          if      ( strncmp(typeOfPacking, "grid_jpeg", len) == 0 ) *outCompressionType = CDI_COMPRESS_JPEG;
+          else if ( strncmp(typeOfPacking, "grid_ccsds", len) == 0 ) *outCompressionType = CDI_COMPRESS_SZIP;
           else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = true;
         }
     }
-  else
-    {
-      if( gribGetZip((long)recsize, *gribbuffer, outUnzipsize) > 0 )
-        {
-          *outCompressionType = COMPRESS_SZIP;
-          ensureBufferSize((size_t)*outUnzipsize + 100, buffersize, gribbuffer);
-        }
-      else
-        {
-          *outCompressionType = COMPRESS_NONE;
-        }
-    }
 
   if ( lieee )
     {
-      *outDatatype = DATATYPE_FLT64;
+      *outDatatype = CDI_DATATYPE_FLT64;
       long precision;
       int status = grib_get_long(gh, "precision", &precision);
-      if ( status == 0 && precision == 1 ) *outDatatype = DATATYPE_FLT32;
+      if ( status == 0 && precision == 1 ) *outDatatype = CDI_DATATYPE_FLT32;
     }
   else
     {
-      *outDatatype = DATATYPE_PACK;
+      *outDatatype = CDI_DATATYPE_PACK;
       long bitsPerValue;
       if ( grib_get_long(gh, "bitsPerValue", &bitsPerValue) == 0 )
         {
           if ( bitsPerValue > 0 && bitsPerValue <= 32 ) *outDatatype = (int)bitsPerValue;
         }
     }
+
   return gh;
 }
 
@@ -49462,8 +49406,8 @@ int gribapiScanTimestep1(stream_t * streamptr)
   size_t buffersize = 0;
   DateTime datetime0 = { .date = 10101, .time = 0 };
   int nrecs_scanned = 0;        //Only used for debug output.
-  int warn_time = TRUE;
-  // int warn_numavg = TRUE;
+  bool warn_time = true;
+  // bool warn_numavg = true;
   int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
   grib_handle *gh = NULL;
 
@@ -49478,11 +49422,11 @@ int gribapiScanTimestep1(stream_t * streamptr)
   int fileID = streamptr->fileID;
 
   unsigned nrecs = 0;
-  while ( TRUE )
+  while ( true )
     {
       int level1 = 0, level2 = 0;
-      size_t recsize = (size_t)gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
+      size_t recsize = gribGetSize(fileID);
+      recpos = fileGetPos(fileID);
 
       if ( recsize == 0 )
         {
@@ -49496,7 +49440,7 @@ int gribapiScanTimestep1(stream_t * streamptr)
       if ( rstatus ) break;
 
       int datatype, comptype = 0;
-      long unzipsize;
+      size_t unzipsize;
       gh = gribapiGetDiskRepresentation(recsize, &buffersize, &gribbuffer, &datatype, &comptype, &unzipsize);
 
       nrecs_scanned++;
@@ -49548,7 +49492,7 @@ int gribapiScanTimestep1(stream_t * streamptr)
           else if ( result == CHECKTIME_INCONSISTENT && warn_time )
             {
               gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, varname, param, level1, level2);
-              warn_time = FALSE;
+              warn_time = false;
             }
           assert(result == CHECKTIME_OK || result == CHECKTIME_INCONSISTENT);
         }
@@ -49559,7 +49503,7 @@ int gribapiScanTimestep1(stream_t * streamptr)
             {
               Message("Change numavg from %d to %d not allowed!",
                       taxis->numavg, ISEC1_AvgNum);
-              warn_numavg = FALSE;
+              warn_numavg = false;
             }
           else
             {
@@ -49637,7 +49581,7 @@ int gribapiScanTimestep1(stream_t * streamptr)
       if ( tsID != streamptr->rtsteps )
         Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
@@ -49647,9 +49591,7 @@ int gribapiScanTimestep1(stream_t * streamptr)
         {
           streamptr->ntsteps = 0;
           for ( int varID = 0; varID < streamptr->nvars; varID++ )
-            {
-              vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-            }
+            vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
         }
     }
 
@@ -49664,7 +49606,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
   DateTime datetime0 = { LONG_MIN, LONG_MIN };
   // int gridID;
   int recID;
-  //  int warn_numavg = TRUE;
+  //  bool warn_numavg = true;
   grib_handle *gh = NULL;
 
   streamptr->curTsID = 1;
@@ -49700,12 +49642,12 @@ int gribapiScanTimestep2(stream_t * streamptr)
 
   int nrecs_scanned = nrecords; //Only used for debug output
   int rindex = 0;
-  while ( TRUE )
+  while ( true )
     {
       if ( rindex > nrecords ) break;
 
-      size_t recsize = (size_t)gribGetSize(fileID);
-      recpos  = fileGetPos(fileID);
+      size_t recsize = gribGetSize(fileID);
+      recpos = fileGetPos(fileID);
       if ( recsize == 0 )
 	{
 	  streamptr->ntsteps = 2;
@@ -49717,9 +49659,9 @@ int gribapiScanTimestep2(stream_t * streamptr)
       rstatus = gribRead(fileID, gribbuffer, &readsize);
       if ( rstatus ) break;
 
-      long unzipsize;
-      if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
-        ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
+      size_t unzipsize;
+      if ( gribGetZip(recsize, gribbuffer, &unzipsize) > 0 )
+        ensureBufferSize(unzipsize + 100, &buffersize, &gribbuffer);
 
       nrecs_scanned++;
       gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
@@ -49765,7 +49707,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
 	  if (  taxis->numavg && warn_numavg &&
 		(taxis->numavg != ISEC1_AvgNum) )
 	    {
-	      warn_numavg = FALSE;
+	      warn_numavg = false;
 	    }
 	  else
 	    {
@@ -49801,7 +49743,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
 	    }
 	}
 
-      streamptr->tsteps[tsID].records[recID].used = TRUE;
+      streamptr->tsteps[tsID].records[recID].used = true;
       streamptr->tsteps[tsID].recIDs[rindex] = recID;
 
       if ( CDI_Debug )
@@ -49851,7 +49793,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
       if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
 	  int varID = streamptr->tsteps[tsID].records[recID].varID;
-	  vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	  vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
       else
 	{
@@ -49868,7 +49810,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
@@ -49882,7 +49824,7 @@ int gribapiScanTimestep2(stream_t * streamptr)
 int gribapiScanTimestep(stream_t * streamptr)
 {
   int vrecID, recID;
-  //int warn_numavg = TRUE;
+  //bool warn_numavg = true;
   int nrecs = 0;
   int vlistID = streamptr->vlistID;
 
@@ -49921,12 +49863,12 @@ int gribapiScanTimestep(stream_t * streamptr)
       DateTime datetime0 = { LONG_MIN, LONG_MIN };
       grib_handle *gh = NULL;
       char varname[256];
-      while ( TRUE )
+      while ( true )
 	{
 	  if ( rindex > nrecs ) break;
 
-	  size_t recsize = (size_t)gribGetSize(fileID);
-	  recpos  = fileGetPos(fileID);
+	  size_t recsize = gribGetSize(fileID);
+	  recpos = fileGetPos(fileID);
 	  if ( recsize == 0 )
 	    {
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
@@ -49945,9 +49887,9 @@ int gribapiScanTimestep(stream_t * streamptr)
 	      break;
 	    }
 
-          long unzipsize;
-	  if ( gribGetZip((long)recsize, gribbuffer, &unzipsize) > 0 )
-            ensureBufferSize((size_t)unzipsize + 100, &buffersize, &gribbuffer);
+          size_t unzipsize;
+	  if ( gribGetZip(recsize, gribbuffer, &unzipsize) > 0 )
+            ensureBufferSize(unzipsize + 100, &buffersize, &gribbuffer);
 
           nrecs_scanned++;
 	  gh = grib_handle_new_from_message(NULL, gribbuffer, recsize);
@@ -49993,7 +49935,7 @@ int gribapiScanTimestep(stream_t * streamptr)
 	      if (  taxis->numavg && warn_numavg &&
 		   (taxis->numavg != ISEC1_AvgNum) )
 		{
-		  warn_numavg = FALSE;
+		  warn_numavg = false;
 		}
 	      else
 		{
@@ -50039,7 +49981,7 @@ int gribapiScanTimestep(stream_t * streamptr)
 		}
 	    }
 
-          streamptr->tsteps[tsID].records[recID].used = TRUE;
+          streamptr->tsteps[tsID].records[recID].used = true;
           streamptr->tsteps[tsID].recIDs[rindex] = recID;
 
 	  if ( CDI_Debug )
@@ -50089,7 +50031,7 @@ int gribapiScanTimestep(stream_t * streamptr)
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID-1].next   = true;
 	  streamptr->tsteps[tsID].position = recpos;
 	}
 
@@ -50113,8 +50055,8 @@ int gribapiScanTimestep(stream_t * streamptr)
 #undef gribWarning
 #endif
 
-int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID)
+int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t gridsize,
+		  int unreduced, size_t *nmiss, double missval, int vlistID, int varID)
 {
   int status = 0;
   long lpar;
@@ -50145,8 +50087,8 @@ int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
 
   // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
 
-  if ( gridsize != (long) datasize )
-    Error("Internal problem: gridsize(%ld) != datasize(%zu)!", gridsize, datasize);
+  if ( gridsize != datasize )
+    Error("Internal problem: gridsize(%zu) != datasize(%zu)!", gridsize, datasize);
   size_t dummy = datasize;
   GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
 
@@ -50352,10 +50294,12 @@ void gribapiDefStepUnits(int editionNumber, grib_handle *gh, int timeunit, int p
       else if ( grib2ProDefTempHasStatisticalDef(proDefTempNum) )
         {
           GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitForTimeRange", unitsOfTime), 0);
-          //  GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
+          GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
         }
       else
         {
+	  // NOTE KNMI:  HIRLAM model files LAMH_D11 are in grib1 and do NOT have key indicatorOfUnitForTimeRange
+	  // Watch out for compatibility issues.
           GRIB_CHECK(my_grib_set_long(gh, "indicatorOfUnitOfTimeRange", unitsOfTime), 0);
         }
     }
@@ -50368,25 +50312,10 @@ int gribapiDefSteptype(int editionNumber, grib_handle *gh, int productDefinition
   size_t len = 64;
   const char *stepType;
 
-  static struct {
-    long productionTemplate;
-    const char sname[8];
-  } ts_tab[] = {
-    [TSTEP_INSTANT] = {  0, "instant" },
-    [TSTEP_AVG] = { 8, "avg" },
-    [TSTEP_ACCUM] = {  8, "accum" },
-    [TSTEP_MAX] = {  8, "max" },
-    [TSTEP_MIN] = {  8, "min" },
-    [TSTEP_DIFF] = {  8, "diff" },
-    [TSTEP_RMS] = {  8, "rms" },
-    [TSTEP_SD] = {  8, "sd" },
-    [TSTEP_COV] = { 8, "cov" },
-    [TSTEP_RATIO] = {  8, "ratio" }
-  };
   if (tsteptype >= TSTEP_INSTANT && tsteptype <= TSTEP_RATIO)
     {
-      stepType = ts_tab[tsteptype].sname;
-      proDefTempNum = ts_tab[tsteptype].productionTemplate;
+      stepType = cdiGribAPI_ts_str_map[tsteptype].sname;
+      proDefTempNum = cdiGribAPI_ts_str_map[tsteptype].productionTemplate;
     }
   else
     {
@@ -50447,7 +50376,7 @@ int gribapiDefDateTimeRel(int editionNumber, grib_handle *gh, int rdate, int rti
 
   int factor = getTimeunitFactor(timeunit);
 
-  if ( !(int) fmod(days*86400.0 + secs, factor) )
+  if ( !(int)(fmod(days*86400.0 + secs, factor)))
     {
       int proDefTempNum = gribapiDefSteptype(editionNumber, gh, productDefinitionTemplate, typeOfGeneratingProcess, tsteptype, gcinit);
 
@@ -50526,18 +50455,18 @@ struct gribApiMsg {
 };
 
 static struct gribApiMsg
-getGribApiCompTypeMsg(grib_handle *gh, int comptype, int gridsize)
+getGribApiCompTypeMsg(int comptype, size_t gridsize)
 {
   const char *mesg;
   size_t len;
 
-  if ( comptype == COMPRESS_JPEG && gridsize > 1 )
+  if ( comptype == CDI_COMPRESS_JPEG && gridsize > 1 )
     {
       static const char mesg_grid_jpeg[] = "grid_jpeg";
       len = sizeof (mesg_grid_jpeg) - 1;
       mesg = mesg_grid_jpeg;
     }
-  else if ( comptype == COMPRESS_SZIP && gridsize > 1 )
+  else if ( comptype == CDI_COMPRESS_SZIP && gridsize > 1 )
     {
       static const char mesg_grid_ccsds[] = "grid_ccsds";
       len = sizeof (mesg_grid_ccsds) - 1;
@@ -50555,12 +50484,14 @@ getGribApiCompTypeMsg(grib_handle *gh, int comptype, int gridsize)
 
 
 static
-void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, int nmiss, int gcinit)
+void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, size_t nmiss, int gcinit)
 {
   UNUSED(nmiss);
+  bool lrotated = false;
+  bool lcurvi = false;
 
   int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   if ( editionNumber <= 1 )
     if ( gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED )
@@ -50568,8 +50499,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 
   if ( gridtype == GRID_GENERIC )
     {
-      int xsize = gridInqXsize(gridID);
-      int ysize = gridInqYsize(gridID);
+      int xsize = (int) gridInqXsize(gridID);
+      int ysize = (int) gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -50593,13 +50524,36 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
-      static bool lwarn = true;
-      if ( lwarn && gridsize > 1 )
-	{
-	  lwarn = false;
-	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong Grid Description Section!");
-	}
-      gridtype = GRID_LONLAT;
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID && gridInqType(projID) == GRID_PROJECTION )
+        {
+          gridID = projID;
+          gridtype = GRID_PROJECTION;
+        }
+      else
+        {
+          static bool lwarning = true;
+          if ( lwarning && gridsize > 1 )
+            {
+              lwarning = false;
+              Warning("Curvilinear grid is unsupported in GRIB format! Created wrong Grid Description Section!");
+            }
+          lcurvi = true;
+          gridtype = GRID_LONLAT;
+        }
+    }
+
+  if ( gridtype == GRID_PROJECTION )
+    {
+      if ( gridInqProjType(gridID) == CDI_PROJ_RLL )
+        {
+          gridtype = GRID_LONLAT;
+          lrotated = true;
+        }
+      else if ( gridInqProjType(gridID) == CDI_PROJ_LCC )
+        {
+          gridtype = GRID_LCC;
+        }
     }
 
   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
@@ -50608,8 +50562,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 
       if ( comptype )
         {
-          struct gribApiMsg gaMsg
-            = getGribApiCompTypeMsg(gh, comptype, gridsize);
+          struct gribApiMsg gaMsg = getGribApiCompTypeMsg(comptype, gridsize);
           size_t len = gaMsg.msgLen;
           const char *mesg = gaMsg.msg;
           GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
@@ -50627,45 +50580,40 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
       {
 	double xfirst = 0, xlast = 0, xinc = 0;
 	double yfirst = 0, ylast = 0, yinc = 0;
-	double latIncr;
 
-        {
-          const char *mesg;
-          size_t len;
-          if ( gridtype == GRID_GAUSSIAN )
-            {
-              static const char mesg_gaussian[] = "regular_gg";
-              len = sizeof (mesg_gaussian) - 1;
-              mesg = mesg_gaussian;
-            }
-          else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-            {
-              static const char mesg_gaussian_reduced[] = "reduced_gg";
-              len = sizeof (mesg_gaussian_reduced) - 1;
-              mesg = mesg_gaussian_reduced;
-            }
-          else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
-            {
-              static const char mesg_rot_lonlat[] = "rotated_ll";
-              len = sizeof (mesg_rot_lonlat) - 1;
-              mesg = mesg_rot_lonlat;
-            }
-          else
-            {
-              static const char mesg_regular_ll[] = "regular_ll";
-              len = sizeof (mesg_regular_ll) - 1;
-              mesg = mesg_regular_ll;
-	  }
-          GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-        }
+        const char *mesg;
+        size_t len;
+        if ( gridtype == GRID_GAUSSIAN )
+          {
+            static const char mesg_gaussian[] = "regular_gg";
+            len = sizeof(mesg_gaussian) - 1;
+            mesg = mesg_gaussian;
+          }
+        else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+          {
+            static const char mesg_gaussian_reduced[] = "reduced_gg";
+            len = sizeof(mesg_gaussian_reduced) - 1;
+            mesg = mesg_gaussian_reduced;
+          }
+        else if ( lrotated )
+          {
+            static const char mesg_rot_lonlat[] = "rotated_ll";
+            len = sizeof(mesg_rot_lonlat) - 1;
+            mesg = mesg_rot_lonlat;
+          }
+        else
+          {
+            static const char mesg_regular_ll[] = "regular_ll";
+            len = sizeof(mesg_regular_ll) - 1;
+            mesg = mesg_regular_ll;
+          }
+        GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 
-	long nlon = gridInqXsize(gridID);
-	long nlat = gridInqYsize(gridID);
+	int nlon = (int) gridInqXsize(gridID);
+	int nlat = (int) gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
-            //GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize), 0);
-
 	    nlon = 0;
 
 	    int *rowlon = (int *) Malloc((size_t)nlat*sizeof(int));
@@ -50673,38 +50621,32 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	    gridInqRowlon(gridID, rowlon);
 	    for ( int i = 0; i < nlat; ++i ) pl[i] = rowlon[i];
 
-            GRIB_CHECK(grib_set_long_array(gh, "pl", pl, nlat), 0);
+            GRIB_CHECK(grib_set_long_array(gh, "pl", pl, (size_t)nlat), 0);
 
 	    Free(pl);
 	    Free(rowlon);
 
 	    xfirst = 0;
-	    xlast  = 360.-360./(nlat*2);
-	    xinc   = 360./(nlat*2);
+	    xinc   =        360. * 0.5 / (double)nlat;
+	    xlast  = 360. - 360. * 0.5 / (double)nlat;
 	  }
 	else
 	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
+	    if ( nlon == 0 ) nlon = 1;
 	    else
 	      {
-		xfirst = gridInqXval(gridID,      0);
-		xlast  = gridInqXval(gridID, nlon-1);
-		xinc   = gridInqXinc(gridID);
+		xfirst = gridInqXval(gridID, 0);
+                xlast  = gridInqXval(gridID, (lcurvi ? nlon*nlat : nlon) - 1);
+		xinc   = fabs(gridInqXinc(gridID));
 	      }
 	  }
 
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
+	if ( nlat == 0 ) nlat = 1;
 	else
 	  {
-	    yfirst = gridInqYval(gridID,      0);
-	    ylast  = gridInqYval(gridID, nlat-1);
-	    yinc   = gridInqYinc(gridID);
+	    yfirst = gridInqYval(gridID, 0);
+            ylast  = gridInqYval(gridID, (lcurvi ? nlon*nlat : nlat) - 1);
+	    yinc   = fabs(gridInqYinc(gridID));
 	  }
 
 	if ( gridtype != GRID_GAUSSIAN_REDUCED ) GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
@@ -50717,14 +50659,14 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees",   ylast), 0);
 
         {
-          long jscan = 0;
-          if ( yfirst < ylast ) jscan = 1;
+          long iscan = xfirst > xlast;
+          GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", iscan), 0);
+        }
+        {
+          long jscan = yfirst < ylast;
           GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jscan), 0);
         }
-	/*
-	if ( fabs(xinc*1000 - ISEC2_LonIncr) > FLT_EPSILON )
-	  ISEC2_LonIncr = 0;
-	*/
+
 	if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
           {
             int np = gridInqNP(gridID);
@@ -50733,140 +50675,124 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
           }
 	else
 	  {
-	    latIncr = yinc;
-	    if ( latIncr < 0 ) latIncr = -latIncr;
-	    GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", latIncr), 0);
-	    /*
-	    if ( fabs(yinc*1000 - ISEC2_LatIncr) > FLT_EPSILON )
-	      ISEC2_LatIncr = 0;
-	    */
+	    GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", yinc), 0);
 	  }
-	/*
-	if ( ISEC2_NumLon > 1 && ISEC2_NumLat == 1 )
-	  if ( ISEC2_LonIncr != 0 && ISEC2_LatIncr == 0 ) ISEC2_LatIncr = ISEC2_LonIncr;
-
-	if ( ISEC2_NumLon == 1 && ISEC2_NumLat > 1 )
-	  if ( ISEC2_LonIncr == 0 && ISEC2_LatIncr != 0 ) ISEC2_LonIncr = ISEC2_LatIncr;
 
-	if ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 )
-	  ISEC2_ResFlag = 0;
-	else
-	  ISEC2_ResFlag = 128;
-	*/
-	if ( gridIsRotated(gridID) )
+	if ( lrotated )
 	  {
-	    double xpole = gridInqXpole(gridID);
-	    double ypole = gridInqYpole(gridID);
-	    double angle = gridInqAngle(gridID);
-	    /* change from north to south pole */
-	    if ( fabs(ypole) > 0 ) ypole = -ypole;
-	    xpole =  xpole + 180;
-            if ( fabs(angle) > 0 ) angle = -angle;
-	    GRIB_CHECK(my_grib_set_double(gh, "latitudeOfSouthernPoleInDegrees",  ypole), 0);
-	    GRIB_CHECK(my_grib_set_double(gh, "longitudeOfSouthernPoleInDegrees", xpole), 0);
-	    GRIB_CHECK(my_grib_set_double(gh, "angleOfRotation", angle), 0);
-	  }
-
-	/* East -> West */
-	//if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
+            double xpole = 0, ypole = 0, angle = 0;
+            gridInqParamRLL(gridID, &xpole, &ypole, &angle);
 
-	/* South -> North */
-	//if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+            xpole += 180;
+            if ( fabs(ypole) > 0 ) ypole = -ypole; // change from north to south pole
+            if ( fabs(angle) > 0 ) angle = -angle;
+            GRIB_CHECK(my_grib_set_double(gh, "latitudeOfSouthernPoleInDegrees",  ypole), 0);
+            GRIB_CHECK(my_grib_set_double(gh, "longitudeOfSouthernPoleInDegrees", xpole), 0);
+            GRIB_CHECK(my_grib_set_double(gh, "angleOfRotation", angle), 0);
+          }
 
         if ( editionNumber != 2 ) { lieee = false; comptype = 0; }
 
-        {
-          const char *mesg;
-          size_t len;
-          if ( lieee )
-            {
-              static const char mesg_grid_ieee[] = "grid_ieee";
-              len = sizeof (mesg_grid_ieee) - 1;
-              mesg = mesg_grid_ieee;
-            }
-          else
-            {
-              struct gribApiMsg gaMsg
-                = getGribApiCompTypeMsg(gh, comptype, gridsize);
-              len = gaMsg.msgLen;
-              mesg = gaMsg.msg;
-            }
-          GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-          if ( lieee )
-            GRIB_CHECK(my_grib_set_long(gh, "precision",
-                                        datatype == DATATYPE_FLT64 ? 2 : 1), 0);
+        if ( lieee )
+          {
+            static const char mesg_grid_ieee[] = "grid_ieee";
+            len = sizeof (mesg_grid_ieee) - 1;
+            mesg = mesg_grid_ieee;
+          }
+        else
+          {
+            struct gribApiMsg gaMsg = getGribApiCompTypeMsg(comptype, gridsize);
+            len = gaMsg.msgLen;
+            mesg = gaMsg.msg;
+          }
+        GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
+        if ( lieee )
+          GRIB_CHECK(my_grib_set_long(gh, "precision", datatype == CDI_DATATYPE_FLT64 ? 2 : 1), 0);
 
-        }
+        long uvRelativeToGrid = gridInqUvRelativeToGrid(gridID);
+        if ( uvRelativeToGrid ) GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGrid), 0);
 
 	break;
       }
     case GRID_LCC:
       {
-	double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	int projflag, scanflag;
+	int xsize = (int) gridInqXsize(gridID);
+	int ysize = (int) gridInqYsize(gridID);
 
-	int xsize = gridInqXsize(gridID);
-	int ysize = gridInqYsize(gridID);
+        double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
+	gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
+	gridVerifyGribParamLCC(grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
+        if ( xval_0 < 0 ) xval_0 += 360;
+        bool lsouth = (lat_1 < 0);
+        if ( lsouth ) { lat_1 = -lat_2; lat_2 = -lat_2; }
+        int projflag = 0;
+        if ( lsouth ) gribbyte_set_bit(&projflag, 1);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+        double xinc = gridInqXinc(gridID);
+        double yinc = gridInqYinc(gridID);
 
         static const char mesg[] = "lambert";
-        size_t len = sizeof (mesg) -1;
+        size_t len = sizeof(mesg) -1;
         GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 
 	GRIB_CHECK(my_grib_set_long(gh, "Nx", xsize), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "Ny", ysize), 0);
-
-        /* FIXME: lround should probably be round here */
-	GRIB_CHECK(my_grib_set_double(gh, "DxInMetres", (double)lround(xincm)), 0);
-        /* FIXME: lround should probably be round here */
-	GRIB_CHECK(my_grib_set_double(gh, "DyInMetres", (double)lround(yincm)), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", originLon), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", originLat), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "LoVInDegrees", lonParY), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "Latin1InDegrees", lat1), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "Latin2InDegrees", lat2), 0);
-
+	GRIB_CHECK(my_grib_set_long(gh, "DxInMetres", lround(xinc)), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "DyInMetres", lround(yinc)), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xval_0), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", yval_0), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "LoVInDegrees", lon_0), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "Latin1InDegrees", lat_1), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "Latin2InDegrees", lat_2), 0);
+        GRIB_CHECK(my_grib_set_long(gh, "projectionCentreFlag", projflag), 0);
+
+        long uvRelativeToGrid = gridInqUvRelativeToGrid(gridID);
+        if ( uvRelativeToGrid ) GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGrid), 0);
+        long earthIsOblate = (IS_EQUAL(a, 6378160.) && IS_EQUAL(rf, 297.));
+        if ( earthIsOblate ) GRIB_CHECK(my_grib_set_long(gh, "earthIsOblate", earthIsOblate), 0);
+
+        int scanflag = 0;
+        gribbyte_set_bit(&scanflag, 2);
         if ( editionNumber <= 1 )
-          {
-            GRIB_CHECK(my_grib_set_long(gh, "projectionCenterFlag", projflag), 0);
-            GRIB_CHECK(my_grib_set_long(gh, "scanningMode", scanflag), 0);
-          }
+          GRIB_CHECK(my_grib_set_long(gh, "scanningMode", (long)scanflag), 0);
 
 	break;
       }
     case GRID_SPECTRAL:
       {
-        static const char mesg[] = "sh";
-        size_t len = sizeof (mesg) -1;
-	GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
-
-	int trunc = gridInqTrunc(gridID);
-	GRIB_CHECK(my_grib_set_long(gh, "J", trunc), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "K", trunc), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "M", trunc), 0);
-
-	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
+        {
+          static const char mesg[] = "sh";
+          size_t len = sizeof (mesg) -1;
+          GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
+        }
+	{
+          int trunc = gridInqTrunc(gridID);
+          enum { numTruncAtt = 3 };
+          static const char truncAttNames[numTruncAtt][2] = { "J", "K", "M" };
+          for (size_t i = 0; i < numTruncAtt; ++i)
+            GRIB_CHECK(my_grib_set_long(gh, truncAttNames[i], trunc), 0);
+        }
+	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", (long)gridsize), 0);
         /*
         if ( lieee )
           {
             printf("spectral_ieee\n");
-            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize, 0);
+            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", (long)gridsize, 0);
             static const char mesg[] = "spectral_ieee";
             size_t len = sizeof (mesg) -1;
             GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
           }
         else */ if ( gridInqComplexPacking(gridID) )
 	  {
-	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize), 0);
+	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", (long)gridsize), 0);
             static const char mesg[] = "spectral_complex";
             size_t len = sizeof (mesg) -1;
 	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
-
-	    GRIB_CHECK(my_grib_set_long(gh, "JS", 20), 0);
-	    GRIB_CHECK(my_grib_set_long(gh, "KS", 20), 0);
-	    GRIB_CHECK(my_grib_set_long(gh, "MS", 20), 0);
+            enum { numTruncAtt = 3 };
+            static const char truncAttNames[numTruncAtt][3]
+              = { "JS", "KS", "MS" };
+            for (size_t i = 0; i < numTruncAtt; ++i)
+              GRIB_CHECK(my_grib_set_long(gh, truncAttNames[i], 20), 0);
 	  }
 	else
 	  {
@@ -50881,17 +50807,19 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
       {
 	GRIB_CHECK(my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_GME), 0);
 
-	GRIB_CHECK(my_grib_set_long(gh, "nd", gridInqGMEnd(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "Ni", gridInqGMEni(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "n2", gridInqGMEni2(gridID)), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "n3", gridInqGMEni3(gridID)), 0);
+        int nd = 0, ni = 0, ni2 = 0, ni3 = 0;
+        gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+	GRIB_CHECK(my_grib_set_long(gh, "nd", nd), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "Ni", ni), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "n2", ni2), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "n3", ni3), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
 
-	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", (long)gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", (long)gridsize), 0);
 
-        if ( comptype == COMPRESS_SZIP )
+        if ( comptype == CDI_COMPRESS_SZIP )
           {
             static const char mesg[] = "grid_ccsds";
             size_t len = sizeof (mesg) -1;
@@ -50927,7 +50855,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	      Warning("Can't write UUID!");
 	  }
 
-        if ( comptype == COMPRESS_SZIP )
+        if ( comptype == CDI_COMPRESS_SZIP )
           {
             static const char mesg[] = "grid_ccsds";
             size_t len = sizeof (mesg) -1;
@@ -50948,16 +50876,14 @@ static
 void getLevelFactor(double level, long *factor, long *out_scaled_value)
 {
   double scaled_value  = level;
-  /* FIXME: lround might be better here */
-  long   iscaled_value = (long) round(scaled_value);
+  long   iscaled_value = lround(scaled_value);
   long   i;
 
   const double eps = 1.e-8;
   for ( i=0; (fabs(scaled_value - (double) iscaled_value) >= eps) && i < 7; i++ )
     {
       scaled_value *= 10.;
-      /* FIXME: lround might be better here */
-      iscaled_value = (long)round(scaled_value);
+      iscaled_value = lround(scaled_value);
     }
 
   (*factor)           = i;
@@ -50968,7 +50894,7 @@ static
 void gribapiDefLevelType(grib_handle *gh, int gcinit, const char *keyname, long leveltype)
 {
   bool lset = false;
-  if ( (leveltype == 99 || leveltype == 100) && gribEditionNumber(gh) == 1 )
+  if ( (leveltype == GRIB1_LTYPE_ISOBARIC_PA || leveltype == 99 || leveltype == 100) && gribEditionNumber(gh) == 1 )
     {
       if ( gribGetLong(gh, "indicatorOfTypeOfLevel") != leveltype ) lset = true;
     }
@@ -51013,34 +50939,17 @@ void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2
     }
 }
 
-
-/*
-void grib_verfiy_zaxis(int zaxisID, double sf)
-{
-  printf("grb_verfiy_vlist called\n");
-  int zaxisID = vlistZaxis(vlistID, index);
-  int nlevels = zaxisInqSize(zaxisID);
-  int zaxistype = zaxisInqType(zaxisID);
-  double *levels = (double *) Malloc(nlevels*sizeof(double));
-  int *ilevels = (int *) Malloc(nlevels*sizeof(int));
-  zaxisInqLevels(zaxisID, levels);
-  for ( int i = 0; i < nlevels; ++i )
-    printf("level %d %g\n", i+1, levels[i]);
-  Free(ilevels);
-  Free(levels);
-}
-*/
-
 static
-void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID, int levelID, int gcinit, int proddef_template_num)
+void gribapiDefLevel(int editionNumber, grib_handle *gh, int zaxisID, int levelID, int gcinit, int proddef_template_num)
 {
+  char units[CDI_MAX_NAME];
   bool lbounds = false;
   double dlevel1 = 0, dlevel2 = 0;
 
   int zaxistype = zaxisInqType(zaxisID);
   long ltype = zaxisInqLtype(zaxisID);
   long ltype2 = zaxisInqLtype2(zaxisID);
-  double level = zaxisInqLevel(zaxisID, levelID);
+  double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) : levelID+1;
 
   if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
     {
@@ -51081,7 +50990,6 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
         if ( zaxistype == ZAXIS_HEIGHT )
           {
             double sf = 1;
-            char units[128];
             zaxisInqUnits(zaxisID, units);
             if ( units[1] == 'm' && !units[2] )
               {
@@ -51129,13 +51037,9 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
     case ZAXIS_ATMOSPHERE:
       {
         if ( editionNumber <= 1 )
-          {
-            grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
-          }
+          grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
         else
-          {
-            grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
-          }
+          grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
 
         break;
       }
@@ -51168,7 +51072,6 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       {
 	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
 
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
 	if ( memcmp(units, "Pa", 2) != 0 )
           {
@@ -51181,7 +51084,7 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
           {
             double dum;
             if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-              grib_ltype = GRIB1_LTYPE_99;
+              grib_ltype = GRIB1_LTYPE_ISOBARIC_PA;
             else
               level /= 100;
 
@@ -51208,7 +51111,6 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       }
     case ZAXIS_DEPTH_BELOW_LAND:
       {
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
         double sf; //scalefactor
 
@@ -51286,11 +51188,430 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
     }
 }
 
+
+int gribapiGetScanningMode(grib_handle *gh)
+{
+  long iScansNegatively;
+  long jScansPositively;
+  long jPointsAreConsecutive;
+
+  GRIB_CHECK(grib_get_long(gh, "iScansNegatively", &iScansNegatively), 0);
+  GRIB_CHECK(grib_get_long(gh, "jScansPositively", &jScansPositively), 0);
+  GRIB_CHECK(grib_get_long(gh, "jPointsAreConsecutive", &jPointsAreConsecutive), 0);
+  int scanningMode
+    = 128*(bool)iScansNegatively
+    + 64 *(bool)jScansPositively
+    + 32 *(bool)jPointsAreConsecutive;
+  if (cdiDebugExt>=30)
+    printf("gribapiGetScanningMode(): Scanning mode = %02d (%1d%1d%1d)*32; \n",\
+            scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively);
+
+ return scanningMode;
+}
+
+
+void gribapiSetScanningMode(grib_handle *gh, int scanningMode)
+{
+   // 127: reserved for testing; generated test data will be in 64 scanning mode
+  //if (scanningMode== 127)  scanningMode = 64;
+
+  long iScansNegatively      = (scanningMode & 128)/128;
+  long jScansPositively      = (scanningMode & 64)/64;
+  long jPointsAreConsecutive = (scanningMode & 32)/32;
+
+  if (cdiDebugExt>=30)
+  {
+    long paramId, levelTypeId, levelId, uvRelativeToGrid;
+    GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &uvRelativeToGrid), 0);
+    GRIB_CHECK(grib_get_long(gh, "indicatorOfParameter", &paramId), 0);
+    GRIB_CHECK(grib_get_long(gh, "indicatorOfTypeOfLevel", &levelTypeId), 0);
+    GRIB_CHECK(grib_get_long(gh, "level", &levelId), 0);
+    printf("gribapiSetScanningMode(): (param,ltype,level) = (%3d,%3d,%4d); Scanning mode = %02d (%1d%1d%1d)*32;  uvRelativeToGrid = %02d\n",\
+            (int)paramId, (int)levelTypeId, (int)levelId,
+            scanningMode,(int)jPointsAreConsecutive,(int)jScansPositively,(int)iScansNegatively,
+            (int)uvRelativeToGrid);
+  }
+
+  GRIB_CHECK(my_grib_set_long(gh, "iScansNegatively", iScansNegatively), 0);
+  GRIB_CHECK(my_grib_set_long(gh, "jScansPositively", jScansPositively), 0);
+  GRIB_CHECK(my_grib_set_long(gh, "jPointsAreConsecutive", jPointsAreConsecutive), 0);
+}
+
+
+static void gribapiSetUvRelativeToGrid(grib_handle *gh, int mode)
+{
+  long uvRelativeToGridMode = mode;
+  long uvRelativeToGridModeOld;
+
+  GRIB_CHECK(grib_get_long(gh, "uvRelativeToGrid", &uvRelativeToGridModeOld), 0);
+
+  if (cdiDebugExt>=30)
+    printf("gribapiSetUvRelativeToGrid():  uvRelativeToGrid: %02d (old) => %02d (new); \n",(int)uvRelativeToGridModeOld,(int)uvRelativeToGridMode);
+
+  GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", uvRelativeToGridMode), 0);
+}
+
+
+  /*
+    TABLE 8. SCANNING MODE FLAG
+
+    (GDS Octet 28)
+    BIT     VALUE     MEANING
+    1       0       Points scan in +i direction
+            1       Points scan in -i direction
+    2       0       Points scan in -j direction
+            1       Points scan in +j direction
+    3       0       Adjacent points in i direction are consecutive
+                      (FORTRAN: (I,J))
+            1       Adjacent points in j direction are consecutive
+                    (FORTRAN: (J,I))
+
+    => Scanning Mode     0 0 0 0 0 0 0 0  (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & North->South)
+    => Scanning Mode     0 1 0 0 0 0 0 0  (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & South->North )
+    => Scanning Mode     1 1 0 0 0 0 0 0  (96 dec)  +i, +j; j direction consecutive (column-major order South->North & West->East )
+
+    NOTE:  South->North  - As if you would plot the data as image on the screen
+                           where [0,0] of the data is the top-left pixel.
+
+                           grib2ppm LAMH_D11_201302150000_00000_oro | display ppm:-
+                           ImageMagick (display): [0,0] of an image belongs to the top-left pixel
+    [DEFAULT] : 64 dec
+
+    iScansNegatively = 0;
+    jScansPositively = 1;
+    jPointsAreConsecutive = 0;    => Scanning Mode 64
+
+    cdo selindexbox,1,726,100,550 LAMH_D11_201302150000_00000_oro LAMH_D11_201302150000_00000_oro_cropped
+    grib2ppm LAMH_D11_201302150000_00000_oro_cropped | /usr/bin/display ppm:- &
+    # ^^^ this image will be missing the souther parts of data
+
+    grib2ppm LAMH_D11_201302150000_00000_oro | /usr/bin/display ppm:- &
+    # ^ full domain data
+  */
+
+#ifdef HIRLAM_EXTENSIONS
+static void
+verticallyFlipGridDefinitionWhenScanningModeChanged(grib_handle *gh, double yfirst, double ylast, double yinc )
+{
+  /*
+  Nj = 550;
+  latitudeOfFirstGridPointInDegrees = -30.8;
+  latitudeOfLastGridPointInDegrees = 24.1;
+  iScansNegatively = 0;
+  jScansPositively = 0;
+  jPointsAreConsecutive = 0;
+  jDirectionIncrementInDegrees = 0.1;
+
+  When switching from scanning mode 0 <=> 64
+  yfirst = -30.8 + (550-1)*0.1
+
+  yfirst = yfirst + (ysize-1) * yinc
+  yinc   = -1.0*yinc
+
+  */
+
+
+  //long jDim=0;
+  //GRIB_CHECK(grib_get_long(gh, "Nj", &jDim), 0);
+
+  double latitudeOfFirstGridPointInDegrees;
+  double latitudeOfLastGridPointInDegrees;
+  double jDirectionIncrementInDegrees;
+
+  //GRIB_CHECK(grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &latitudeOfFirstGridPointInDegrees), 0);  // yfirst
+  //GRIB_CHECK(grib_get_double(gh, "latitudeOfLastGridPointInDegrees", &latitudeOfLastGridPointInDegrees), 0);    // ylast
+  //GRIB_CHECK(grib_get_double(gh, "jDirectionIncrementInDegrees", &jDirectionIncrementInDegrees), 0);  // yinc
+
+  if (cdiDebugExt>=10)
+  {
+      Message(" BEFORE: yfirst = %f; ylast = %f; yinc = %f; ", yfirst,ylast, yinc);
+  }
+
+  GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees", ylast), 0);
+  GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees", yfirst), 0);
+  //yinc *= -1.0; // don't set yinc here ...
+  //GRIB_CHECK(my_grib_set_double(gh, "jDirectionIncrementInDegrees", yinc), 0);
+
+  if (cdiDebugExt>=10)
+  {
+    GRIB_CHECK(grib_get_double(gh, "latitudeOfFirstGridPointInDegrees", &latitudeOfFirstGridPointInDegrees), 0);  // yfirst
+    GRIB_CHECK(grib_get_double(gh, "latitudeOfLastGridPointInDegrees", &latitudeOfLastGridPointInDegrees), 0);    // ylast
+    GRIB_CHECK(grib_get_double(gh, "jDirectionIncrementInDegrees", &jDirectionIncrementInDegrees), 0);  // yinc
+    Message("CHANGED INTO:  yfirst = %f, ylast = %f, yinc = %f",latitudeOfFirstGridPointInDegrees,latitudeOfLastGridPointInDegrees, jDirectionIncrementInDegrees);
+  }
+}
+
+static void
+convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
+                        size_t gridsize, size_t iDim, size_t jDim)
+{
+  size_t i,j;
+  size_t idxIN, idxOUT;
+
+   // 127: reserved for testing; it will generate test data in 64 scanning mode
+  if (scanModeOUT== 127)  // fill with testdata ...
+  {
+      scanModeOUT = 64;
+      if (cdiDebugExt>=30) printf("convertDataScanningMode(): Generating test data in 64 scanning mode..\n");
+      for (j=0; j<jDim; j++)
+      {
+        size_t jXiDim = j*iDim;
+        for (i=0; i<iDim; i++)
+        {
+          idxIN = i + jXiDim;
+          data[idxIN] = (double) (100.0*j +i);
+        }
+      }
+  }
+
+  if ( (iDim*jDim)!= gridsize)
+  {
+    if (cdiDebugExt>=30) printf("convertDataScanningMode(): ERROR: (iDim*jDim)!= gridsize;  (%zu * %zu) != %zu\n", iDim,jDim, gridsize);
+    return;
+  }
+  if (cdiDebugExt>=30) printf("convertDataScanningMode(): scanModeIN=%02d => scanModeOUT=%02d ; where: (iDim * jDim == gridsize)  (%zu*%zu == %zu)\n",scanModeIN, scanModeOUT, iDim,jDim, gridsize);
+
+  if (cdiDebugExt>=100)
+  {
+      printf("convertDataScanningMode(): data IN:\n");
+      for (j=0; j<jDim; j++)
+      {
+        size_t jXiDim = j*iDim;
+        for (i=0; i<iDim; i++)
+        {
+          idxIN = i + jXiDim;
+          printf("%03.0f, ",data[idxIN]);
+        }
+        printf("\n");
+      }
+  }
+
+  if (scanModeIN==scanModeOUT)
+  {
+    if (cdiDebugExt>=30) printf("convertDataScanningMode(): INFO: Nothing to do;  scanModeIN==scanModeOUT..\n");
+    return;
+  }
+
+  if (0)
+  {
+      return;
+      if (scanModeOUT==00)
+      {
+          if (cdiDebugExt>0) printf("convertDataScanningMode(): Leave data unchaged BUT set scanModeOUT=00.\n");
+          // CHECK:  Looks like that GRIB-API provide (no matter what) data in the scannning mode 00, even it is store in the gribfile as 64 !!
+          return;
+      }
+  }
+  double *dataCopy = (double *) malloc(gridsize*sizeof(double));
+  memcpy((void*)dataCopy,(void*) data, gridsize*sizeof(double));
+
+  if (scanModeIN==64)           // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
+  {                             // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
+                                // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
+      if (scanModeOUT==00)
+      // CHECK:  Looks like that GRIB-API provide (no matter what) data in the scannning mode 00, even it is store in the gribfile as 64 !!
+#define VERTICAL_FLIP
+#ifdef VERTICAL_FLIP
+      { // flip the data vertically ..
+        idxIN= 0; idxOUT= (jDim-1)*iDim;
+        if (cdiDebugExt>=30) printf("convertDataScanningMode():  copying rows nr. (%04d : %04d)\n",0,jDim-1);
+        for (j=0; j<jDim; j++)
+        {
+          memcpy((void*)&data[idxOUT], (void*)&dataCopy[idxIN], iDim*sizeof(double));
+          idxIN  += iDim; idxOUT -= iDim;
+        }
+      } // end if (scanModeOUT==00)*/
+#endif
+#ifdef HORIZONTAL_FLIP
+      { // flip data horizontally ...
+        if (1)
+        {
+            if (cdiDebugExt>=30) printf("convertDataScanningMode():  copying columns nr. (%04d : %04d);\n", 0, iDim-1);
+            for (i=0; i<iDim; i++)
+            {
+              for (j=0; j<jDim; j++)
+              {
+                size_t jXiDim = j*iDim;
+                idxIN  = i           + jXiDim;
+                //data[idxIN] = (double) (100.0*j +i);  // just some testdata ..
+                idxOUT = iDim - i -1 + jXiDim;
+                //printf("[%03d=>%03d] = %f;",idxIN,idxOUT,dataCopy[idxIN]);
+                data[idxOUT] =  dataCopy[idxIN];
+              }
+            }
+        }
+      } // end if (scanModeOUT==00)
+#endif
+
+      if (scanModeOUT==96)
+      { // transpose the data
+        if (cdiDebugExt>=30) printf("convertDataScanningMode():  transpose data rows=>columns nr. (%04d : %04zu) => (%04d : %04zu);\n", 0, iDim-1, 0, jDim-1);
+        for (j=0; j<jDim; j++)
+        {
+          size_t jXiDim = j*iDim;
+          for (i=0; i<iDim; i++)
+          {
+            idxIN  = i + jXiDim;
+            idxOUT = j + i*jDim;
+            //printf("[%03d=>%03d] = %f;",idxIN,idxOUT,dataCopy[idxIN]);
+            data[idxOUT] =  dataCopy[idxIN];
+          }
+          //printf(".\n");
+        }
+      } // end if (scanModeOUT==96)
+  } // end if (scanModeIN==64)
+
+  if (scanModeIN==00)           // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
+  {                             // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
+                               // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
+    if (scanModeOUT==64)
+      { // flip the data vertically ..
+        idxIN= 0; idxOUT= (jDim-1)*iDim;
+        for (j=0; j<jDim; j++)
+        {
+          if (cdiDebugExt>=25) printf("convertDataScanningMode():  copying row nr. %04zu; [idxIN=%08zu] => [idxOUT=%08zu]\n",j, idxIN, idxOUT);
+          memcpy((void*)&data[idxOUT], (void*)&dataCopy[idxIN], iDim*sizeof(double));
+          idxIN  += iDim; idxOUT -= iDim;
+        }
+      } // end if (scanModeOUT==64)
+
+      if (scanModeOUT==96)
+      { // transpose the data
+        size_t jInv;
+        for (j=0; j<jDim; j++)
+        {
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
+          jInv = (jDim-1) -j;
+          for (i=0; i<iDim; i++)
+            data[j + i*jDim] =  dataCopy[i + jInv*iDim];  // source data has -j
+        }
+      } // end if (scanModeOUT==96)
+  } // end if (scanModeIN==00)
+
+  if (scanModeIN==96)           // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
+  {                             // Scanning Mode (64 dec)  +i, +j; i direction consecutive (row-major    order West->East   & North->South )
+                                // Scanning Mode (96 dec)  +i, +j; j direction consecutive (column-major order North->South & West->East )
+    if (scanModeOUT==64)
+      { // transpose the data
+        for (j=0; j<jDim; j++)
+        {
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
+          size_t jXiDim = j*iDim;
+          for (i=0; i<iDim; i++)
+            //data[j + i*jDim] =  dataCopy[i + j*iDim];
+            data[i + jXiDim] =  dataCopy[j + i*jDim];
+        }
+      } // end if (scanModeOUT==64)
+
+      if (scanModeOUT==00)
+      { // transpose the data
+        idxIN= 0; idxOUT= 0;
+        size_t jInv;
+        for (j=0; j<jDim; j++)
+        {
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
+          jInv = (jDim-1) -j;
+          size_t jXiDim = j*iDim;
+          for (i=0; i<iDim; i++)
+            //data[jInv + iXjDim] =  dataCopy[i + jXiDim];  // target data has -j
+            data[i + jXiDim] =  dataCopy[jInv + i*jDim];  // target data has -j
+        }
+      } // end if (scanModeOUT==00)
+  } // end if (scanModeIN==96)
+
+  if (cdiDebugExt>=100)
+  {
+      printf("convertDataScanningMode(): data OUT (new scanning mode):\n");
+      for (j=0; j<jDim; j++)
+      {
+        size_t jXiDim = j*iDim;
+        for (i=0; i<iDim; i++)
+        {
+          idxIN = i + jXiDim;
+          printf("%03.0f, ",data[idxIN]);
+        }
+        printf("\n");
+      }
+  }
+
+  free(dataCopy); return;
+}
+#endif //HIRLAM_EXTENSIONS
+
+static
+void gribapiSetExtMode(grib_handle *gh, int gridID, size_t datasize, const double *data)
+{
+  /*
+  Nj = 550;
+  latitudeOfFirstGridPointInDegrees = -30.8;
+  latitudeOfLastGridPointInDegrees = 24.1;
+  iScansNegatively = 0;
+  jScansPositively = 0;
+  jPointsAreConsecutive = 0;
+  jDirectionIncrementInDegrees = 0.1; */
+#ifndef HIRLAM_EXTENSIONS
+  (void)data;
+  (void)datasize;
+#endif
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_GENERIC || gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN ||
+       gridtype == GRID_GAUSSIAN_REDUCED || gridtype == GRID_PROJECTION )
+    {
+#ifdef HIRLAM_EXTENSIONS
+      int scanModeIN = gridInqScanningMode(gridID);
+
+      if (cdiDebugExt>=100)
+        {
+          size_t gridsize = gridInqSize(gridID);
+          Message("(scanModeIN=%d; gridsize=%zu", scanModeIN, gridsize);
+        }
+
+      if ( cdiGribDataScanningMode.active )   // allowed modes: <0, 64, 96>; Default is 64
+        {
+          size_t iDim = gridInqXsize(gridID);
+          size_t jDim = gridInqYsize(gridID);
+
+          double yfirst = gridInqYval(gridID,      0);
+          double ylast  = gridInqYval(gridID, jDim-1);
+          double yinc   = gridInqYinc(gridID);
+
+          int scanModeOUT = cdiGribDataScanningMode.value;
+          convertDataScanningMode(scanModeIN, scanModeOUT, (double*)data, datasize, iDim, jDim);
+          // This will overrule the old scanning mode of the given grid
+          if (cdiDebugExt>=10) Message("Set GribDataScanningMode (%d) => (%d)", scanModeIN, cdiGribDataScanningMode.value);
+          gribapiSetScanningMode(gh, cdiGribDataScanningMode.value);
+
+          if (((scanModeIN==00) && (cdiGribDataScanningMode.value==64)) ||
+              ((scanModeIN==64) && (cdiGribDataScanningMode.value==00)) )
+            verticallyFlipGridDefinitionWhenScanningModeChanged(gh, yfirst, ylast, yinc);
+        }
+      else
+        {
+          if (cdiDebugExt>=100) Message("Set GribDataScanningMode => (%d) based on used grid", scanModeIN);
+          gribapiSetScanningMode(gh, scanModeIN);
+        }
+#endif
+
+      if ( cdiGribChangeModeUvRelativeToGrid.active )
+        {
+          // this will overrule/change the UvRelativeToGrid flag;
+          // typically when the wind is rotated with respect to north pole
+          if (cdiDebugExt>=100) Message("Set ModeUvRelativeToGrid =>%d ( note grid has: %d)", cdiGribChangeModeUvRelativeToGrid.mode, gridInqUvRelativeToGrid(gridID));
+          GRIB_CHECK(my_grib_set_long(gh, "uvRelativeToGrid", (long) cdiGribChangeModeUvRelativeToGrid.mode), 0);
+        }
+      else
+        {
+          if (cdiDebugExt>=100) Message("Set ModeUvRelativeToGrid =>%d based on used grid", gridInqUvRelativeToGrid(gridID));
+          gribapiSetUvRelativeToGrid(gh, gridInqUvRelativeToGrid(gridID));
+        }
+    }
+}
+
 /* #define GRIBAPIENCODETEST 1 */
 
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int comptype, void *gribContainer)
 {
   size_t recsize = 0;
@@ -51303,8 +51624,9 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
   long editionNumber = 2;
   char name[256];
   char stdname[256];
-  gribContainer_t *gc = (gribContainer_t *) gribContainer;
+
   // extern unsigned char _grib_template_GRIB2[];
+  cdi_check_gridsize_int_limit("GRIB", datasize);
 
   int param    = vlistInqVarParam(vlistID, varID);
   int datatype = vlistInqVarDatatype(vlistID, varID);
@@ -51317,8 +51639,11 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 #if defined(GRIBAPIENCODETEST)
   grib_handle *gh = (grib_handle *) gribHandleNew(editionNumber);
 #else
+  gribContainer_t *gc = (gribContainer_t *) gribContainer;
+  assert(gc != NULL);
   grib_handle *gh = (struct grib_handle *)gc->gribHandle;
 #endif
+
   GRIB_CHECK(grib_get_long(gh, "editionNumber", &editionNumber), 0);
 
   if ( editionNumber == 2 )
@@ -51336,14 +51661,15 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
     }
   */
 
-  gribapiDefTime((int)editionNumber, productDefinitionTemplate, typeOfGeneratingProcess, gh, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID), gc->init);
+  gribapiDefTime((int)editionNumber, productDefinitionTemplate, typeOfGeneratingProcess,
+                 gh, vdate, vtime, tsteptype, numavg, vlistInqTaxis(vlistID), gc->init);
 
   if ( ! gc->init ) gribapiDefInstitut(gh, vlistID, varID);
   if ( ! gc->init ) gribapiDefModel(gh, vlistID, varID);
 
   if ( ! gc->init ) gribapiDefParam((int)editionNumber, gh, param, name, stdname);
 
-  if ( editionNumber == 2 && (datatype == DATATYPE_FLT32 || datatype == DATATYPE_FLT64) ) lieee = true;
+  if ( editionNumber == 2 && (datatype == CDI_DATATYPE_FLT32 || datatype == CDI_DATATYPE_FLT64) ) lieee = true;
 
   /* bitsPerValue have to be defined before call to DefGrid (complex packing) */
   //  if ( lieee == false )
@@ -51354,7 +51680,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 
   gribapiDefGrid((int)editionNumber, gh, gridID, comptype, lieee, datatype, nmiss, gc->init);
 
-  gribapiDefLevel((int)editionNumber, gh, param, zaxisID, levelID, gc->init, productDefinitionTemplate);
+  gribapiDefLevel((int)editionNumber, gh, zaxisID, levelID, gc->init, productDefinitionTemplate);
 
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
   //if (!gc->init)
@@ -51370,7 +51696,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
           {
             //DR: Fix for multi-level fields (otherwise only the 1st level is correct)
             if ( zaxisInqSize(zaxisID)==(levelID+1) )
-              vlistptr->vars[varID].opt_grib_kvpair[i].update = FALSE;
+              vlistptr->vars[varID].opt_grib_kvpair[i].update = false;
 
             if (vlistptr->vars[varID].opt_grib_kvpair[i].data_type == t_double)
               {
@@ -51402,7 +51728,9 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
       GRIB_CHECK(my_grib_set_double(gh, "missingValue", vlistInqVarMissval(vlistID, varID)), 0);
     }
 
-  GRIB_CHECK(grib_set_double_array(gh, "values", data, (size_t)datasize), 0);
+  gribapiSetExtMode(gh, gridID, datasize, data);
+
+  GRIB_CHECK(grib_set_double_array(gh, "values", data, datasize), 0);
 
   /* get the size of coded message  */
   GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
@@ -51417,10 +51745,24 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
   gribHandleDelete(gh);
 #endif
 
-  gc->init = TRUE;
+  gc->init = true;
 
   return recsize;
 }
+
+
+void gribapiChangeParameterIdentification(grib_handle *gh, int code, int ltype, int lev)
+{
+  long  indicatorOfParameter,  indicatorOfTypeOfLevel,  level; //  timeRangeIndicator: could be included later
+  indicatorOfParameter = code;
+  indicatorOfTypeOfLevel = ltype;
+  level = lev;
+
+  if (indicatorOfParameter!=-1) GRIB_CHECK(my_grib_set_long(gh, "indicatorOfParameter", indicatorOfParameter), 0);
+  if (indicatorOfTypeOfLevel!=-1) GRIB_CHECK(my_grib_set_long(gh, "indicatorOfTypeOfLevel", indicatorOfTypeOfLevel), 0);
+  if (level!=-1) GRIB_CHECK(my_grib_set_long(gh, "level", level), 0);
+}
+
 #endif
 
 /*
@@ -51432,20 +51774,28 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
  * require-trailing-newline: t
  * End:
  */
-#if defined (HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #endif
 
 
+#ifdef HAVE_LIBNETCDF
+static inline bool
+filetypeIsNetCDF(int filetype)
+{
+  return filetype == CDI_FILETYPE_NC
+    ||   filetype == CDI_FILETYPE_NC2
+    ||   filetype == CDI_FILETYPE_NC5
+    ||   filetype == CDI_FILETYPE_NC4
+    ||   filetype == CDI_FILETYPE_NC4C;
+}
+#endif
 
 void streamDefHistory(int streamID, int length, const char *history)
 {
 #ifdef HAVE_LIBNETCDF
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  if ( filetypeIsNetCDF(streamptr->filetype) )
     {
       char *histstring;
       size_t len;
@@ -51474,10 +51824,7 @@ int streamInqHistorySize(int streamID)
 #ifdef HAVE_LIBNETCDF
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  if ( filetypeIsNetCDF(streamptr->filetype) )
     {
       size = cdfInqHistorySize(streamptr);
     }
@@ -51493,10 +51840,7 @@ void streamInqHistoryString(int streamID, char *history)
 #ifdef HAVE_LIBNETCDF
   stream_t *streamptr = stream_to_pointer(streamID);
 
-  if ( streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C )
+  if ( filetypeIsNetCDF(streamptr->filetype) )
     {
       cdfInqHistoryString(streamptr, history);
     }
@@ -51516,57 +51860,35 @@ void streamInqHistoryString(int streamID, char *history)
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <float.h>
-#include <math.h>
-
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBIEG)
 
-
 typedef struct {
   int param;
   int level;
-} IEGCOMPVAR;
+} iegcompvar_t;
 
 
-static int iegInqDatatype(int prec)
+static
+int iegInqDatatype(int prec)
 {
-  int datatype;
-
-  if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-  else                            datatype = DATATYPE_FLT32;
-
-  return (datatype);
+  return (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
 }
 
-
-static int iegDefDatatype(int datatype)
+static
+int iegDefDatatype(int datatype)
 {
-  int prec;
-
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+  if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
     Error("CDI/IEG library does not support complex numbers!");
 
-  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
-    datatype = DATATYPE_FLT32;
+  if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 )
+    datatype = CDI_DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
-
-  return (prec);
+  return (datatype == CDI_DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -51586,7 +51908,7 @@ int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
   *levelID = -1;
 
   status = iegRead(fileID, iegp);
-  if ( status != 0 ) return (0);
+  if ( status != 0 ) return 0;
 
   icode  = IEG_P_Parameter(iegp->ipdb);
   if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
@@ -51596,51 +51918,43 @@ int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
 
   *varID = vlistInqVarID(vlistID, icode);
 
-  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
+  if ( *varID == CDI_UNDEFID ) Error("Code %d undefined", icode);
 
   zaxisID = vlistInqVarZaxis(vlistID, *varID);
 
   *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
 
-  return (1);
+  return 1;
 }
 */
 
-void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
-  int vlistID, fileID;
-  int status;
-  int recID, vrecID, tsID;
-  off_t recpos;
-  int varID, gridID;
-  int i, size;
-  double missval;
-  void *iegp = streamptr->record->exsep;
-
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
-  tsID    = streamptr->curTsID;
-  vrecID  = streamptr->tsteps[tsID].curRecID;
-  recID   = streamptr->tsteps[tsID].recIDs[vrecID];
-  recpos  = streamptr->tsteps[tsID].records[recID].position;
-  varID   = streamptr->tsteps[tsID].records[recID].varID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+  int tsID    = streamptr->curTsID;
+  int vrecID  = streamptr->tsteps[tsID].curRecID;
+  int recID   = streamptr->tsteps[tsID].recIDs[vrecID];
+  int varID   = streamptr->tsteps[tsID].records[recID].varID;
+  off_t recpos = streamptr->tsteps[tsID].records[recID].position;
 
   fileSetPos(fileID, recpos, SEEK_SET);
 
-  status = iegRead(fileID, iegp);
+  void *iegp = streamptr->record->exsep;
+  int status = iegRead(fileID, iegp);
   if ( status != 0 )
     Error("Could not read IEG record!");
 
   iegInqDataDP(iegp, data);
 
-  missval = vlistInqVarMissval(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  size    = gridInqSize(gridID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( size_t i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -51700,19 +52014,18 @@ int iegGetZaxisType(int iegleveltype)
       }
     }
 
-  return (leveltype);
+  return leveltype;
 }
 
 
 static void iegDefTime(int *pdb, int date, int time, int taxisID)
 {
-  int year, month, day, hour, minute, second;
   int timetype = -1;
-
   if ( taxisID != -1 ) timetype = taxisInqType(taxisID);
 
   if ( timetype == TAXIS_ABSOLUTE || timetype == TAXIS_RELATIVE )
     {
+      int year, month, day, hour, minute, second;
       cdiDecodeDate(date, &year, &month, &day);
       cdiDecodeTime(time, &hour, &minute, &second);
 
@@ -51763,21 +52076,27 @@ calc_resfac(double xfirst, double xlast, double xinc, double yfirst, double ylas
         }
     }
 
-  return (resfac);
+  return resfac;
 }
 
 static
 void iegDefGrid(int *gdb, int gridID)
 {
+  int projID = gridInqProj(gridID);
+  if ( projID != CDI_UNDEFID && gridInqProjType(projID) == CDI_PROJ_RLL ) gridID = projID;
+
   int gridtype = gridInqType(gridID);
 
-  if ( gridtype == GRID_GENERIC )
-    {
-      int xsize, ysize;
+  int projtype = CDI_UNDEFID;
+  if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL ) projtype = CDI_PROJ_RLL;
 
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
 
+  cdi_check_gridsize_int_limit("IEG", xsize*ysize);
+
+  if ( gridtype == GRID_GENERIC )
+    {
       if ( (ysize == 32  || ysize == 48 || ysize == 64 ||
 	    ysize == 96  || ysize == 160) &&
 	   (xsize == 2*ysize || xsize == 1) )
@@ -51801,39 +52120,32 @@ void iegDefGrid(int *gdb, int gridID)
       gridtype = GRID_LONLAT;
     }
 
-  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
+  bool lrotated = (projtype == CDI_PROJ_RLL);
+
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
     {
       double xfirst = 0, xlast = 0, xinc = 0;
       double yfirst = 0, ylast = 0, yinc = 0;
 
-      int nlon = gridInqXsize(gridID),
-        nlat = gridInqYsize(gridID);
-
-      if ( nlon == 0 )
-	{
-	  nlon = 1;
-	}
+      if ( xsize == 0 ) xsize = 1;
       else
 	{
-	  xfirst = gridInqXval(gridID,      0);
-	  xlast  = gridInqXval(gridID, nlon-1);
+	  xfirst = gridInqXval(gridID,       0);
+	  xlast  = gridInqXval(gridID, xsize-1);
 	  xinc   = gridInqXinc(gridID);
 	}
 
-      if ( nlat == 0 )
-	{
-	  nlat = 1;
-	}
+      if ( ysize == 0 ) ysize = 1;
       else
 	{
-	  yfirst = gridInqYval(gridID,      0);
-	  ylast  = gridInqYval(gridID, nlat-1);
+	  yfirst = gridInqYval(gridID,       0);
+	  ylast  = gridInqYval(gridID, ysize-1);
 	  yinc   = gridInqYinc(gridID);
 	}
 
       if ( gridtype == GRID_GAUSSIAN )
 	IEG_G_GridType(gdb) = 4;
-      else if ( gridtype == GRID_LONLAT && gridIsRotated(gridID) )
+      else if ( lrotated )
 	IEG_G_GridType(gdb) = 10;
       else
 	IEG_G_GridType(gdb) = 0;
@@ -51844,8 +52156,8 @@ void iegDefGrid(int *gdb, int gridID)
 
       IEG_G_ResFac(gdb)   = iresfac;
 
-      IEG_G_NumLon(gdb)   = nlon;
-      IEG_G_NumLat(gdb)   = nlat;
+      IEG_G_NumLon(gdb)   = (int)xsize;
+      IEG_G_NumLat(gdb)   = (int)ysize;
       IEG_G_FirstLat(gdb) = (int)lround(yfirst*resfac);
       IEG_G_LastLat(gdb)  = (int)lround(ylast*resfac);
       IEG_G_FirstLon(gdb) = (int)lround(xfirst*resfac);
@@ -51855,7 +52167,7 @@ void iegDefGrid(int *gdb, int gridID)
 	IEG_G_LonIncr(gdb) = 0;
 
       if ( gridtype == GRID_GAUSSIAN )
-	IEG_G_LatIncr(gdb) = nlat/2;
+	IEG_G_LatIncr(gdb) = (int)ysize/2;
       else
 	{
 	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
@@ -51871,15 +52183,15 @@ void iegDefGrid(int *gdb, int gridID)
       if ( IEG_G_NumLon(gdb) == 1 && IEG_G_NumLat(gdb) > 1 )
 	if ( IEG_G_LonIncr(gdb) == 0 && IEG_G_LatIncr(gdb) != 0 ) IEG_G_LonIncr(gdb) = IEG_G_LatIncr(gdb);
 
-      if ( IEG_G_LatIncr(gdb) == 0 || IEG_G_LonIncr(gdb) == 0 )
-	IEG_G_ResFlag(gdb) = 0;
-      else
-	IEG_G_ResFlag(gdb) = 128;
+      IEG_G_ResFlag(gdb) = (IEG_G_LatIncr(gdb) == 0 || IEG_G_LonIncr(gdb) == 0) ? 0 : 128;
 
-      if ( gridIsRotated(gridID) )
+      if ( lrotated )
 	{
-	  IEG_G_LatSP(gdb) = - (int)lround(gridInqYpole(gridID) * resfac);
-	  IEG_G_LonSP(gdb) =   (int)lround((gridInqXpole(gridID) + 180) * resfac);
+          double xpole = 0, ypole = 0, angle = 0;
+          gridInqParamRLL(gridID, &xpole, &ypole, &angle);
+
+	  IEG_G_LatSP(gdb) = - (int)lround(ypole * resfac);
+	  IEG_G_LonSP(gdb) =   (int)lround((xpole + 180) * resfac);
 	  IEG_G_Size(gdb)  = 42;
 	}
       else
@@ -51896,19 +52208,25 @@ void iegDefGrid(int *gdb, int gridID)
 }
 
 static
+void pdbDefLevel(int *pdb, int leveltype, int level1, int level2)
+{
+  IEG_P_LevelType(pdb) = leveltype;
+  IEG_P_Level1(pdb)    = level1;
+  IEG_P_Level2(pdb)    = level2;
+}
+
+static
 void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
 {
   double level;
-  int ilevel, leveltype;
-  static int vct_warning = 1;
+  int ilevel;
 
-  leveltype = zaxisInqType(zaxisID);
+  int leveltype = zaxisInqType(zaxisID);
 
   if ( leveltype == ZAXIS_GENERIC )
     {
       Message("Changed zaxis type from %s to %s",
-	      zaxisNamePtr(leveltype),
-	      zaxisNamePtr(ZAXIS_PRESSURE));
+	      zaxisNamePtr(leveltype), zaxisNamePtr(ZAXIS_PRESSURE));
       leveltype = ZAXIS_PRESSURE;
       zaxisChangeType(zaxisID, leveltype);
       zaxisDefUnits(zaxisID, "Pa");
@@ -51920,36 +52238,26 @@ void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
     {
     case ZAXIS_SURFACE:
       {
-	IEG_P_LevelType(pdb) = IEG_LTYPE_SURFACE;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
+        pdbDefLevel(pdb, IEG_LTYPE_SURFACE, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
 	break;
       }
     case ZAXIS_HYBRID:
       {
-	int vctsize;
-
 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID_LAYER;
-	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
+          pdbDefLevel(pdb, IEG_LTYPE_HYBRID_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)),
+                      (int)(zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_HYBRID;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqLevel(zaxisID, levelID));
-	  }
+          pdbDefLevel(pdb, IEG_LTYPE_HYBRID, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
 
-	vctsize = zaxisInqVctSize(zaxisID);
+	int vctsize = zaxisInqVctSize(zaxisID);
 	if ( vctsize > 100 )
 	  {
+            static bool vct_warning = true;
 	    /*	    IEG_G_NumVCP(gdb) = 0; */
 	    if ( vct_warning )
 	      {
 		Warning("VCT size of %d is too large (maximum is 100). Set to 0!", vctsize);
-		vct_warning = 0;
+		vct_warning = false;
 	      }
 	  }
 	else
@@ -51963,11 +52271,10 @@ void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
     case ZAXIS_PRESSURE:
       {
 	double dum;
-	char units[128];
+	char units[CDI_MAX_NAME];
 
 	level = zaxisInqLevel(zaxisID, levelID);
-	if ( level < 0 )
-	  Warning("pressure level of %f Pa is below 0.", level);
+	if ( level < 0 ) Warning("pressure level of %f Pa is below 0.", level);
 
 	zaxisInqUnits(zaxisID, units);
 	if ( memcmp(units, "hPa", 3) == 0 || memcmp(units, "mb",2 ) == 0 )
@@ -51975,81 +52282,43 @@ void iegDefLevel(int *pdb, int *gdb, double *vct, int zaxisID, int levelID)
 
 	ilevel = (int) level;
 	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_99;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel;
-	  }
+          pdbDefLevel(pdb, IEG_LTYPE_99, 0, ilevel);
 	else
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_ISOBARIC;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel/100;
-	  }
-	break;
+          pdbDefLevel(pdb, IEG_LTYPE_ISOBARIC, 0, ilevel/100);
+
+        break;
       }
     case ZAXIS_HEIGHT:
       {
 	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_HEIGHT;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
-
+        pdbDefLevel(pdb, IEG_LTYPE_HEIGHT, 0, (int)level);
 	break;
       }
     case ZAXIS_ALTITUDE:
       {
 	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_ALTITUDE;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
-
+        pdbDefLevel(pdb, IEG_LTYPE_ALTITUDE, 0, (int)level);
 	break;
       }
     case ZAXIS_DEPTH_BELOW_LAND:
       {
 	if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
-	  {
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH_LAYER;
-	    IEG_P_Level1(pdb)    = (int)(zaxisInqLbound(zaxisID, levelID));
-	    IEG_P_Level2(pdb)    = (int)(zaxisInqUbound(zaxisID, levelID));
-	  }
+          pdbDefLevel(pdb, IEG_LTYPE_LANDDEPTH_LAYER, (int)(zaxisInqLbound(zaxisID, levelID)), (int)(zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-	    level = zaxisInqLevel(zaxisID, levelID);
-
-	    ilevel = (int) level;
-	    IEG_P_LevelType(pdb) = IEG_LTYPE_LANDDEPTH;
-	    IEG_P_Level1(pdb)    = 0;
-	    IEG_P_Level2(pdb)    = ilevel;
-	  }
+          pdbDefLevel(pdb, IEG_LTYPE_LANDDEPTH, 0, (int)(zaxisInqLevel(zaxisID, levelID)));
 
 	break;
       }
     case ZAXIS_DEPTH_BELOW_SEA:
       {
 	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = IEG_LTYPE_SEADEPTH;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
-
+        pdbDefLevel(pdb, IEG_LTYPE_SEADEPTH, 0, (int)level);
 	break;
       }
     case ZAXIS_ISENTROPIC:
       {
 	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	IEG_P_LevelType(pdb) = 113;
-	IEG_P_Level1(pdb)    = 0;
-	IEG_P_Level2(pdb)    = ilevel;
-
+        pdbDefLevel(pdb, 113, 0, (int)level);
 	break;
       }
     default:
@@ -52069,68 +52338,55 @@ void iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 
 void iegDefRecord(stream_t *streamptr)
 {
-  int vlistID;
-  int gridID;
-  int date, time;
-  int datatype;
-  int i;
-  int param, pdis, pcat, pnum;
-  int varID, levelID, tsID, zaxisID;
-  int byteorder;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  Record *record = streamptr->record;
+  iegrec_t *iegp = (iegrec_t*) record->exsep;
 
-  vlistID = streamptr->vlistID;
-  byteorder = streamptr->byteorder;
+  int vlistID = streamptr->vlistID;
+  int byteorder = streamptr->byteorder;
 
-  varID   = streamptr->record->varID;
-  levelID = streamptr->record->levelID;
-  tsID    = streamptr->curTsID;
+  int varID   = record->varID;
+  int levelID = record->levelID;
+  int tsID    = streamptr->curTsID;
 
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  zaxisID = vlistInqVarZaxis(vlistID, varID);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
 
   iegInitMem(iegp);
-  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
+  for ( int i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
 
   iegp->byteswap = getByteswap(byteorder);
 
-  param =  vlistInqVarParam(vlistID, varID);
+  int param = vlistInqVarParam(vlistID, varID);
+  int pdis, pcat, pnum;
   cdiDecodeParam(param, &pnum, &pcat, &pdis);
   IEG_P_Parameter(iegp->ipdb) = pnum;
   if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
-  date     = streamptr->tsteps[tsID].taxis.vdate;
-  time     = streamptr->tsteps[tsID].taxis.vtime;
 
+  int date = streamptr->tsteps[tsID].taxis.vdate;
+  int time = streamptr->tsteps[tsID].taxis.vtime;
   iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
   iegDefGrid(iegp->igdb, gridID);
   iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levelID);
 
-  datatype = streamptr->record->prec;
-
-  iegp->dprec = iegDefDatatype(datatype);
+  iegp->dprec = iegDefDatatype(record->prec);
 }
 
 
 void iegWriteRecord(stream_t *streamptr, const double *data)
 {
-  int fileID;
-  int i, gridsize, gridID;
-  double refval;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  Record *record = streamptr->record;
+  iegrec_t *iegp = (iegrec_t*) record->exsep;
 
-  fileID = streamptr->fileID;
-  gridID = streamptr->record->gridID;
-
-  gridsize = gridInqSize(gridID);
+  int fileID = streamptr->fileID;
+  size_t gridsize = gridInqSize(record->gridID);
 
-  refval = data[0];
-  for ( i = 1; i < gridsize; i++ )
+  double refval = data[0];
+  for ( size_t i = 1; i < gridsize; i++ )
     if ( data[i] < refval ) refval = data[i];
 
   iegp->refval = refval;
 
   iegDefDataDP(iegp, data);
-
   iegWrite(fileID, iegp);
 }
 
@@ -52138,7 +52394,6 @@ static
 void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vct,
 		  size_t recsize, off_t position, int prec)
 {
-  int levelID = 0;
   int vlistID = streamptr->vlistID;
   int tsID    = streamptr->curTsID;
   int recID   = recordNewEntry(streamptr, tsID);
@@ -52164,18 +52419,20 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
   record->ilevel2  = level2;
   record->ltype    = IEG_P_LevelType(pdb);
 
-  int gridtype =
-   ( IEG_G_GridType(gdb) == 0 || IEG_G_GridType(gdb) == 10 ) ? GRID_LONLAT :
-    ( IEG_G_GridType(gdb) == 4 ) ? GRID_GAUSSIAN : GRID_GENERIC;
+  int gridtype = (IEG_G_GridType(gdb) == 0) ? GRID_LONLAT :
+                 (IEG_G_GridType(gdb) == 10) ? GRID_PROJECTION :
+                 (IEG_G_GridType(gdb) == 4) ? GRID_GAUSSIAN : GRID_GENERIC;
 
   grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
   grid_init(grid);
   cdiGridTypeInit(grid, gridtype, IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb));
-  grid->xsize = IEG_G_NumLon(gdb);
-  grid->ysize = IEG_G_NumLat(gdb);
-  grid->xinc  = 0;
-  grid->yinc  = 0;
-  grid->xdef  = 0;
+  size_t xsize = (size_t)IEG_G_NumLon(gdb);
+  size_t ysize = (size_t)IEG_G_NumLat(gdb);
+  grid->x.size = xsize;
+  grid->y.size = ysize;
+  grid->x.inc  = 0;
+  grid->y.inc  = 0;
+  grid->x.flag = 0;
 
   int iresfac = IEG_G_ResFac(gdb);
   if ( iresfac == 0 ) iresfac = 1000;
@@ -52183,78 +52440,65 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
 
   /* if ( IEG_G_FirstLon != 0 || IEG_G_LastLon != 0 ) */
   {
-    if ( grid->xsize > 1 )
+    if ( xsize > 1 )
       {
 	if ( IEG_G_ResFlag(gdb) && IEG_G_LonIncr(gdb) > 0 )
-	  grid->xinc = IEG_G_LonIncr(gdb) * resfac;
+	  grid->x.inc = IEG_G_LonIncr(gdb) * resfac;
 	else
-	  grid->xinc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (grid->xsize - 1);
+	  grid->x.inc = (IEG_G_LastLon(gdb) - IEG_G_FirstLon(gdb)) * resfac / (xsize - 1);
 
 	/* correct xinc if necessary */
 	if ( IEG_G_FirstLon(gdb) == 0 && IEG_G_LastLon(gdb) > 354000 )
 	  {
-	    double xinc = 360. / grid->xsize;
-            /* FIXME: why not use grid->xinc != xinc as condition? */
-	    if ( fabs(grid->xinc-xinc) > 0.0 )
+	    double xinc = 360. / xsize;
+            /* FIXME: why not use grid->x.inc != xinc as condition? */
+	    if ( fabs(grid->x.inc-xinc) > 0.0 )
 	      {
-		grid->xinc = xinc;
-		if ( CDI_Debug ) Message("set xinc to %g", grid->xinc);
+		grid->x.inc = xinc;
+		if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
 	      }
 	  }
       }
-    grid->xfirst = IEG_G_FirstLon(gdb) * resfac;
-    grid->xlast  = IEG_G_LastLon(gdb)  * resfac;
-    grid->xdef   = 2;
+    grid->x.first = IEG_G_FirstLon(gdb) * resfac;
+    grid->x.last  = IEG_G_LastLon(gdb)  * resfac;
+    grid->x.flag  = 2;
   }
-  grid->ydef  = 0;
+  grid->y.flag = 0;
   /* if ( IEG_G_FirstLat != 0 || IEG_G_LastLat != 0 ) */
   {
-    if ( grid->ysize > 1 )
+    if ( ysize > 1 )
       {
 	if ( IEG_G_ResFlag(gdb) && IEG_G_LatIncr(gdb) > 0 )
-	  grid->yinc = IEG_G_LatIncr(gdb) * resfac;
+	  grid->y.inc = IEG_G_LatIncr(gdb) * resfac;
 	else
-	  grid->yinc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (grid->ysize - 1);
+	  grid->y.inc = (IEG_G_LastLat(gdb) - IEG_G_FirstLat(gdb)) * resfac / (ysize - 1);
       }
-    grid->yfirst = IEG_G_FirstLat(gdb) * resfac;
-    grid->ylast  = IEG_G_LastLat(gdb)  * resfac;
-    grid->ydef   = 2;
+    grid->y.first = IEG_G_FirstLat(gdb) * resfac;
+    grid->y.last  = IEG_G_LastLat(gdb)  * resfac;
+    grid->y.flag  = 2;
   }
-  /*
-  grid->xfirst= IEG_G_FirstLon(gdb) * resfac;
-  grid->xlast = IEG_G_LastLon(gdb) * resfac;
-  grid->xinc  = IEG_G_LonIncr(gdb) * resfac;
-  grid->xdef  = 2;
-  grid->yfirst= IEG_G_FirstLat(gdb) * resfac;
-  grid->ylast = IEG_G_LastLat(gdb) * resfac;
-  grid->yinc  = IEG_G_LatIncr(gdb) * resfac;
-  grid->ydef  = 2;
-  */
-  grid->xvals = NULL;
-  grid->yvals = NULL;
 
-  grid->isRotated = FALSE;
+  double xpole = 0, ypole = 0;
   if ( IEG_G_GridType(gdb) == 10 )
     {
-      grid->isRotated = TRUE;
-      grid->ypole     = - IEG_G_LatSP(gdb) * resfac;
-      grid->xpole     =   IEG_G_LonSP(gdb) * resfac - 180;
-      grid->angle     = 0;
+      xpole =   IEG_G_LonSP(gdb) * resfac - 180;
+      ypole = - IEG_G_LatSP(gdb) * resfac;
+      grid->projtype = CDI_PROJ_RLL;
     }
 
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
   int gridID = gridAdded.Id;
-  if (!gridAdded.isNew) Free(grid);
+  if ( !gridAdded.isNew ) Free(grid);
+  else if ( gridtype == GRID_PROJECTION ) gridDefParamRLL(gridID, xpole, ypole, 0);
 
   int leveltype = iegGetZaxisType(IEG_P_LevelType(pdb));
-
   if ( leveltype == ZAXIS_HYBRID )
     {
       double tmpvct[100];
       size_t vctsize = (size_t)IEG_G_NumVCP(gdb);
 
-      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i] = vct[i];
-      for (size_t i = 0; i < vctsize/2; i++ ) tmpvct[i+vctsize/2] = vct[i+50];
+      for ( size_t i = 0; i < vctsize/2; i++ ) tmpvct[i] = vct[i];
+      for ( size_t i = 0; i < vctsize/2; i++ ) tmpvct[i+vctsize/2] = vct[i+50];
 
       varDefVCT(vctsize, tmpvct);
     }
@@ -52264,6 +52508,7 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
   int datatype = iegInqDatatype(prec);
 
   int varID;
+  int levelID = 0;
   varAddRecord(recID, param, gridID, leveltype, lbounds, level1, level2, 0, 0,
 	       datatype, &varID, &levelID, TSTEP_INSTANT, 0, 0, -1,
                NULL, NULL, NULL, NULL, NULL, NULL);
@@ -52275,20 +52520,18 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
   streamptr->nrecs++;
 
   if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
+    Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
 }
 
 #if 0
 static
 void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int param,
-		  int level, int xsize, int ysize)
+		  int level, size_t xsize, size_t ysize)
 {
   int varID = 0;
   int levelID = 0;
-  record_t *record;
 
-  record  = &streamptr->tsteps[tsID].records[recID];
+  record_t *record  = &streamptr->tsteps[tsID].records[recID];
 
   if ( param != (*record).param || level != (*record).ilevel )
     Error("inconsistent timestep");
@@ -52308,17 +52551,15 @@ void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int
 }
 #endif
 
-static void iegDateTime(int *pdb, int *date, int *time)
+static
+void iegDateTime(int *pdb, int *date, int *time)
 {
-  int ryear, rmonth, rday, rhour, rminute;
-
-  ryear   = IEG_P_Year(pdb);
+  int ryear   = IEG_P_Year(pdb);
+  int rmonth  = IEG_P_Month(pdb);
+  int rday    = IEG_P_Day(pdb);
 
-  rmonth  = IEG_P_Month(pdb);
-  rday    = IEG_P_Day(pdb);
-
-  rhour   = IEG_P_Hour(pdb);
-  rminute = IEG_P_Minute(pdb);
+  int rhour   = IEG_P_Hour(pdb);
+  int rminute = IEG_P_Minute(pdb);
 
   if ( rminute == -1 ) rminute = 0;
 
@@ -52329,51 +52570,39 @@ static void iegDateTime(int *pdb, int *date, int *time)
 static
 void iegScanTimestep1(stream_t *streamptr)
 {
-  int prec = 0;
-  int status;
-  int fileID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
   DateTime datetime0 = { LONG_MIN, LONG_MIN };
-  int tsID;
-  int varID;
-  size_t recsize;
   off_t recpos;
-  int nrecords, nrecs, recID;
-  int taxisID = -1;
-  taxis_t *taxis;
-  int vlistID;
-  IEGCOMPVAR compVar, compVar0;
+  iegcompvar_t compVar, compVar0;
   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
   streamptr->curTsID = 0;
 
-  tsID  = tstepsNewEntry(streamptr);
-  taxis = &streamptr->tsteps[tsID].taxis;
+  int tsID = tstepsNewEntry(streamptr);
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   if ( tsID != 0 )
     Error("Internal problem! tstepsNewEntry returns %d", tsID);
 
-  fileID = streamptr->fileID;
+  int fileID = streamptr->fileID;
 
-  nrecs = 0;
-  while ( TRUE )
+  int nrecs = 0;
+  while ( true )
     {
       recpos = fileGetPos(fileID);
-      status = iegRead(fileID, iegp);
+      int status = iegRead(fileID, iegp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 1;
 	  break;
 	}
-      recsize = (size_t)(fileGetPos(fileID) - recpos);
+      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-      prec   = iegp->dprec;
-      rcode  = IEG_P_Parameter(iegp->ipdb);
-      tabnum = IEG_P_CodeTable(iegp->ipdb);
-      param  = cdiEncodeParam(rcode, tabnum, 255);
+      int prec   = iegp->dprec;
+      int rcode  = IEG_P_Parameter(iegp->ipdb);
+      int tabnum = IEG_P_CodeTable(iegp->ipdb);
+      int param  = cdiEncodeParam(rcode, tabnum, 255);
 
+      int rlevel = 0;
       if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
 	rlevel = IEG_P_Level1(iegp->ipdb);
       else
@@ -52381,6 +52610,7 @@ void iegScanTimestep1(stream_t *streamptr)
 
       if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
+      int vdate = 0, vtime = 0;
       iegDateTime(iegp->ipdb, &vdate, &vtime);
 
       if ( nrecs == 0 )
@@ -52392,12 +52622,13 @@ void iegScanTimestep1(stream_t *streamptr)
 	{
 	  compVar.param = param;
           compVar.level = rlevel;
+          int recID = 0;
 	  for ( recID = 0; recID < nrecs; recID++ )
 	    {
 	      compVar0.param = streamptr->tsteps[0].records[recID].param;
 	      compVar0.level = streamptr->tsteps[0].records[recID].ilevel;
 
-	      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 ) break;
+	      if ( memcmp(&compVar0, &compVar, sizeof(iegcompvar_t)) == 0 ) break;
 	    }
 	  if ( recID < nrecs ) break;
 	  DateTime datetime = { .date = vdate, .time = vtime};
@@ -52417,17 +52648,17 @@ void iegScanTimestep1(stream_t *streamptr)
 
   cdi_generate_vars(streamptr);
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
   taxis->type  = TAXIS_ABSOLUTE;
   taxis->vdate = (int)datetime0.date;
   taxis->vtime = (int)datetime0.time;
 
-  vlistID = streamptr->vlistID;
+  int vlistID = streamptr->vlistID;
   vlistDefTaxis(vlistID, taxisID);
 
   vlist_check_contents(vlistID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   if ( nrecords < streamptr->tsteps[0].recordSize )
     {
       streamptr->tsteps[0].recordSize = nrecords;
@@ -52438,7 +52669,7 @@ void iegScanTimestep1(stream_t *streamptr)
 
   streamptr->tsteps[0].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
   streamptr->tsteps[0].nrecs = nrecords;
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[0].recIDs[recID] = recID;
 
   if ( streamptr->ntsteps == -1 )
@@ -52447,7 +52678,7 @@ void iegScanTimestep1(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
@@ -52456,10 +52687,8 @@ void iegScanTimestep1(stream_t *streamptr)
       if ( taxis->vdate == 0 && taxis->vtime == 0 )
 	{
 	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
-	    {
-	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
-	    }
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
+            vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
     }
 }
@@ -52467,67 +52696,55 @@ void iegScanTimestep1(stream_t *streamptr)
 static
 int iegScanTimestep2(stream_t *streamptr)
 {
-  int status;
-  int fileID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
-  int varID;
-  size_t recsize;
   off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
-  IEGCOMPVAR compVar, compVar0;
+  iegcompvar_t compVar, compVar0;
   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
   streamptr->curTsID = 1;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  tsID = streamptr->rtsteps;
+  int tsID = streamptr->rtsteps;
   if ( tsID != 1 )
     Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
   cdi_create_records(streamptr, tsID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof(int));
   streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[1].recIDs[recID] = -1;
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
-      varID = streamptr->tsteps[0].records[recID].varID;
       streamptr->tsteps[tsID].records[recID].position =
 	streamptr->tsteps[0].records[recID].position;
       streamptr->tsteps[tsID].records[recID].size     =
 	streamptr->tsteps[0].records[recID].size;
     }
 
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
+  for ( int rindex = 0; rindex <= nrecords; rindex++ )
     {
       recpos = fileGetPos(fileID);
-      status = iegRead(fileID, iegp);
+      int status = iegRead(fileID, iegp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 2;
 	  break;
 	}
-      recsize = (size_t)(fileGetPos(fileID) - recpos);
+      size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-      rcode  = IEG_P_Parameter(iegp->ipdb);
-      tabnum = IEG_P_CodeTable(iegp->ipdb);
-      param  = cdiEncodeParam(rcode, tabnum, 255);
+      int rcode  = IEG_P_Parameter(iegp->ipdb);
+      int tabnum = IEG_P_CodeTable(iegp->ipdb);
+      int param  = cdiEncodeParam(rcode, tabnum, 255);
 
+      int rlevel = 0;
       if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
 	rlevel = IEG_P_Level1(iegp->ipdb);
       else
@@ -52535,6 +52752,7 @@ int iegScanTimestep2(stream_t *streamptr)
 
       if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
+      int vdate = 0, vtime = 0;
       iegDateTime(iegp->ipdb, &vdate, &vtime);
 
       if ( rindex == 0 )
@@ -52546,21 +52764,22 @@ int iegScanTimestep2(stream_t *streamptr)
 
       compVar.param = param;
       compVar.level = rlevel;
-      nextstep = FALSE;
+      bool nextstep = false;
+      int recID = 0;
       for ( recID = 0; recID < nrecords; recID++ )
 	{
 	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
 	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) == 0 )
+	  if ( memcmp(&compVar0, &compVar, sizeof(iegcompvar_t)) == 0 )
 	    {
 	      if ( streamptr->tsteps[tsID].records[recID].used )
 		{
-		  nextstep = TRUE;
+		  nextstep = true;
 		}
 	      else
 		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].records[recID].used = true;
 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
 		}
 	      break;
@@ -52571,7 +52790,7 @@ int iegScanTimestep2(stream_t *streamptr)
 	  char paramstr[32];
 	  cdiParamToString(param, paramstr, sizeof(paramstr));
 	  Warning("param %s level %d not defined at timestep 1", paramstr, rlevel);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       if ( nextstep ) break;
@@ -52584,25 +52803,25 @@ int iegScanTimestep2(stream_t *streamptr)
       compVar0.param = streamptr->tsteps[tsID].records[recID].param;
       compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-      if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
+      if ( memcmp(&compVar0, &compVar, sizeof(iegcompvar_t)) != 0 )
 	{
 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
 		  tsID, recID,
 		  streamptr->tsteps[tsID].records[recID].param, param,
 		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       streamptr->tsteps[1].records[recID].position = recpos;
     }
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  int nrecs = 0;
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
-	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
+          vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
       else
 	{
@@ -52619,47 +52838,35 @@ int iegScanTimestep2(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
-  return (0);
+  return 0;
 }
 
 
 int iegInqContents(stream_t *streamptr)
 {
-  int fileID;
-  int status = 0;
-
-  fileID = streamptr->fileID;
+  int fileID = streamptr->fileID;
 
   streamptr->curTsID = 0;
 
   iegScanTimestep1(streamptr);
 
+  int status = 0;
   if ( streamptr->ntsteps == -1 ) status = iegScanTimestep2(streamptr);
 
   fileSetPos(fileID, 0, SEEK_SET);
 
-  return (status);
+  return status;
 }
 
 static
 long iegScanTimestep(stream_t *streamptr)
 {
-  int status;
-  int fileID;
-  int tsID;
-  int tabnum;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  size_t recsize = 0;
   off_t recpos = 0;
-  int recID;
-  taxis_t *taxis;
-  int rindex, nrecs = 0;
-  IEGCOMPVAR compVar, compVar0;
+  iegcompvar_t compVar, compVar0;
   iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 
   if ( CDI_Debug )
@@ -52673,9 +52880,10 @@ long iegScanTimestep(stream_t *streamptr)
   if ( streamptr->rtsteps == 0 )
     Error("Internal problem! Missing contents.");
 
-  tsID  = streamptr->rtsteps;
-  taxis = &streamptr->tsteps[tsID].taxis;
+  int tsID = streamptr->rtsteps;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
+  int nrecs = 0;
   if ( streamptr->tsteps[tsID].recordSize == 0 )
     {
       cdi_create_records(streamptr, tsID);
@@ -52685,28 +52893,29 @@ long iegScanTimestep(stream_t *streamptr)
       streamptr->tsteps[tsID].nrecs = nrecs;
       streamptr->tsteps[tsID].recIDs
         = (int *) Malloc((size_t)nrecs * sizeof (int));
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-      fileID = streamptr->fileID;
+      int fileID = streamptr->fileID;
 
       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
+      for ( int rindex = 0; rindex <= nrecs; rindex++ )
 	{
 	  recpos = fileGetPos(fileID);
-	  status = iegRead(fileID, iegp);
+	  int status = iegRead(fileID, iegp);
 	  if ( status != 0 )
 	    {
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
 	      break;
 	    }
-	  recsize = (size_t)(fileGetPos(fileID) - recpos);
+	  size_t recsize = (size_t)(fileGetPos(fileID) - recpos);
 
-	  rcode  = IEG_P_Parameter(iegp->ipdb);
-	  tabnum = IEG_P_CodeTable(iegp->ipdb);
-	  param  = cdiEncodeParam(rcode, tabnum, 255);
+	  int rcode  = IEG_P_Parameter(iegp->ipdb);
+	  int tabnum = IEG_P_CodeTable(iegp->ipdb);
+	  int param  = cdiEncodeParam(rcode, tabnum, 255);
 
+          int rlevel = 0;
 	  if ( IEG_P_LevelType(iegp->ipdb) == IEG_LTYPE_HYBRID_LAYER )
 	    rlevel = IEG_P_Level1(iegp->ipdb);
 	  else
@@ -52714,11 +52923,12 @@ long iegScanTimestep(stream_t *streamptr)
 
 	  if ( IEG_P_LevelType(iegp->ipdb) == 100 ) rlevel *= 100;
 
+          int vdate = 0, vtime = 0;
 	  iegDateTime(iegp->ipdb, &vdate, &vtime);
 
 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
 	  if ( rindex == nrecs ) continue;
-	  recID = streamptr->tsteps[tsID].recIDs[rindex];
+	  int recID = streamptr->tsteps[tsID].recIDs[rindex];
 
 	  if ( rindex == 0 )
 	    {
@@ -52732,7 +52942,7 @@ long iegScanTimestep(stream_t *streamptr)
 	  compVar0.param = streamptr->tsteps[tsID].records[recID].param;
 	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(IEGCOMPVAR)) != 0 )
+	  if ( memcmp(&compVar0, &compVar, sizeof(iegcompvar_t)) != 0 )
 	    {
 	      Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
 		      tsID, recID,
@@ -52756,7 +52966,7 @@ long iegScanTimestep(stream_t *streamptr)
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID-1].next   = true;
 	  streamptr->tsteps[tsID].position = recpos;
 	}
 
@@ -52770,113 +52980,51 @@ long iegScanTimestep(stream_t *streamptr)
       streamptr->ntsteps = tsID;
     }
 
-  return (streamptr->ntsteps);
+  return streamptr->ntsteps;
 }
 
 
 int iegInqTimestep(stream_t *streamptr, int tsID)
 {
-  int nrecs;
-
   if ( tsID == 0 && streamptr->rtsteps == 0 )
     Error("Call to cdiInqContents missing!");
 
   if ( CDI_Debug )
     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
 
-  long ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+  long ntsteps = CDI_UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
     ntsteps = iegScanTimestep(streamptr);
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
+  int nrecs = 0;
+  if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
     {
       streamptr->curTsID = tsID;
       nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  return (nrecs);
+  return nrecs;
 }
 
 
-void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *iegp = streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
-
-  for (levID = 0; levID < nlevs; levID++)
-    {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      iegRead(fileID, iegp);
-      iegInqDataDP(iegp, &data[levID*gridsize]);
-    }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-
-  *nmiss = 0;
-  for ( i = 0; i < nlevs*gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
-}
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
-
-void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int tsid;
-  int recID;
-  int i;
-  double missval;
   void *iegp = streamptr->record->exsep;
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  int tsid     = streamptr->curTsID;
 
-  currentfilepos = fileGetPos(fileID);
+  off_t currentfilepos = fileGetPos(fileID);
 
   /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
+  int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  off_t recpos = streamptr->tsteps[tsid].records[recID].position;
   fileSetPos(fileID, recpos, SEEK_SET);
   iegRead(fileID, iegp);
   iegInqDataDP(iegp, data);
@@ -52884,7 +53032,7 @@ void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 
   *nmiss = 0;
-  for ( i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -52893,101 +53041,70 @@ void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
+void iegReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int i;
-  int date, time;
-  int param, pdis, pcat, pnum;
-  double refval;
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamptr->self, varID);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
-  iegInitMem(iegp);
-  for ( i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
+  for ( size_t levID = 0; levID < nlevs; levID++)
+    iegReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
+}
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
+  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+  iegInitMem(iegp);
+  for ( int i = 0; i < 37; i++ ) iegp->ipdb[i] = -1;
+
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(vlistID, varID);
 
-  param    = vlistInqVarParam(vlistID, varID);
+  int param    = vlistInqVarParam(vlistID, varID);
+  int pdis, pcat, pnum;
   cdiDecodeParam(param, &pnum, &pcat, &pdis);
   IEG_P_Parameter(iegp->ipdb) = pnum;
   if ( pdis == 255 ) IEG_P_CodeTable(iegp->ipdb) = pcat;
-  date     = streamptr->tsteps[tsID].taxis.vdate;
-  time     = streamptr->tsteps[tsID].taxis.vtime;
 
+  int date     = streamptr->tsteps[tsID].taxis.vdate;
+  int time     = streamptr->tsteps[tsID].taxis.vtime;
   iegDefTime(iegp->ipdb, date, time, vlistInqTaxis(vlistID));
   iegDefGrid(iegp->igdb, gridID);
+  iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  iegp->dprec = iegDefDatatype(vlistInqVarDatatype(vlistID, varID));
 
-  iegp->dprec = iegDefDatatype(datatype);
-
-  for ( levID = 0;  levID < nlevs; levID++ )
-    {
-      iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
+  size_t gridsize = gridInqSize(gridID);
 
-      refval = data[0];
-      for ( i = 1; i < gridsize; i++ )
-	if ( data[levID*gridsize+i] < refval ) refval = data[levID*gridsize+i];
+  double refval = data[0];
+  for ( size_t i = 1; i < gridsize; i++ )
+    if ( data[i] < refval ) refval = data[i];
 
-      iegp->refval = refval;
+  iegp->refval = refval;
 
-      iegDefDataDP(iegp, &data[levID*gridsize]);
-      iegWrite(fileID, iegp);
-    }
+  iegDefDataDP(iegp, data);
+  iegWrite(fileID, iegp);
 }
 
 
-void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
+void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
 {
-  int fileID;
-  int gridID;
-  int zaxisID;
-  /* double level; */
-  int datatype;
-  /* int tsID; */
-  int vlistID;
-  /* int param, date, time, datasize; */
-  iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* tsID     = streamptr->curTsID; */
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  (void)levID;
-  /* level    = zaxisInqLevel(zaxisID, levID); */
-
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
-
-  /* param = vlistInqVarParam(vlistID, varID); */
-  /* date = streamptr->tsteps[tsID].taxis.vdate; */
-  /* time = streamptr->tsteps[tsID].taxis.vtime; */
-  /* datasize = gridInqSize(gridID); */
-
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  iegp->dprec = iegDefDatatype(datatype);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
 
-  iegDefDataDP(iegp, data);
-  iegWrite(fileID, iegp);
+  for ( size_t levID = 0;  levID < nlevs; levID++ )
+    iegWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
 }
 
 #endif /* HAVE_LIBIEG */
@@ -53000,7 +53117,7 @@ void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
  * require-trailing-newline: t
  * End:
  */
-#if defined (HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #endif
 
 #include <limits.h>
@@ -53016,7 +53133,7 @@ void recordInitEntry(record_t *record)
   record->size     = 0;
   record->param    = 0;
   record->ilevel   = CDI_UNDEFID;
-  record->used     = FALSE;
+  record->used     = false;
   record->varID    = CDI_UNDEFID;
   record->levelID  = CDI_UNDEFID;
   memset(record->varname, 0, sizeof(record->varname));
@@ -53078,18 +53195,19 @@ int recordNewEntry(stream_t *streamptr, int tsID)
 static
 void cdiInitRecord(stream_t *streamptr)
 {
-  streamptr->record = (Record *) Malloc(sizeof(Record));
+  Record *record = (Record *) Malloc(sizeof(Record));
+  streamptr->record = record;
 
-  streamptr->record->param      = 0;
-  streamptr->record->level      = 0;
-  streamptr->record->date       = 0;
-  streamptr->record->time       = 0;
-  streamptr->record->gridID     = 0;
-  streamptr->record->buffer     = NULL;
-  streamptr->record->buffersize = 0;
-  streamptr->record->position   = 0;
-  streamptr->record->varID      = 0;
-  streamptr->record->levelID    = CDI_UNDEFID;
+  record->param      = 0;
+  record->level      = 0;
+  record->date       = 0;
+  record->time       = 0;
+  record->gridID     = 0;
+  record->buffer     = NULL;
+  record->buffersize = 0;
+  record->position   = 0;
+  record->varID      = 0;
+  record->levelID    = CDI_UNDEFID;
 }
 
 
@@ -53122,7 +53240,7 @@ void streamInqRecord(int streamID, int *varID, int *levelID)
   *levelID = streamptr->vars[*varID].recordTable[isub].lindex[lindex];
 
   if ( CDI_Debug )
-    Message("tsID = %d, recID = %d, varID = %d, levelID = %d\n", tsID, recID, *varID, *levelID);
+    Message("tsID = %d, recID = %d, varID = %d, levelID = %d", tsID, recID, *varID, *levelID);
 
   streamptr->curTsID = tsID;
   streamptr->tsteps[tsID].curRecID = rindex;
@@ -53162,43 +53280,45 @@ void streamDefRecord(int streamID, int varID, int levelID)
   int param   = vlistInqVarParam(vlistID, varID);
   int level   = (int)(zaxisInqLevel(zaxisID, levelID));
 
-  streamptr->record->varID    = varID;
-  streamptr->record->levelID  = levelID;
-  streamptr->record->param    = param;
-  streamptr->record->level    = level;
-  streamptr->record->date     = streamptr->tsteps[tsID].taxis.vdate;
-  streamptr->record->time     = streamptr->tsteps[tsID].taxis.vtime;
-  streamptr->record->gridID   = gridID;
-  streamptr->record->prec     = vlistInqVarDatatype(vlistID, varID);
+  Record *record = streamptr->record;
+  record->varID    = varID;
+  record->levelID  = levelID;
+  record->param    = param;
+  record->level    = level;
+  record->date     = streamptr->tsteps[tsID].taxis.vdate;
+  record->time     = streamptr->tsteps[tsID].taxis.vtime;
+  record->gridID   = gridID;
+  record->prec     = vlistInqVarDatatype(vlistID, varID);
 
   switch (streamptr->filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       grbDefRecord(streamptr);
       break;
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       srvDefRecord(streamptr);
       break;
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       extDefRecord(streamptr);
       break;
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       iegDefRecord(streamptr);
       break;
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
       if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
       cdfDefRecord(streamptr);
       break;
@@ -53216,24 +53336,26 @@ void streamCopyRecord(int streamID2, int streamID1)
     *streamptr2 = stream_to_pointer(streamID2);
   int filetype1 = streamptr1->filetype,
     filetype2 = streamptr2->filetype,
-    filetype  = FILETYPE_UNDEF;
+    filetype  = CDI_FILETYPE_UNDEF;
 
   if ( filetype1 == filetype2 ) filetype = filetype2;
   else
     {
       switch (filetype1)
         {
-        case FILETYPE_NC:
-        case FILETYPE_NC2:
-        case FILETYPE_NC4:
-        case FILETYPE_NC4C:
+        case CDI_FILETYPE_NC:
+        case CDI_FILETYPE_NC2:
+        case CDI_FILETYPE_NC4:
+        case CDI_FILETYPE_NC4C:
+        case CDI_FILETYPE_NC5:
           switch (filetype2)
             {
-            case FILETYPE_NC:
-            case FILETYPE_NC2:
-            case FILETYPE_NC4:
-            case FILETYPE_NC4C:
-              Warning("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
+            case CDI_FILETYPE_NC:
+            case CDI_FILETYPE_NC2:
+            case CDI_FILETYPE_NC4:
+            case CDI_FILETYPE_NC4C:
+            case CDI_FILETYPE_NC5:
+              // Warning("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
               filetype = filetype2;
               break;
             }
@@ -53241,37 +53363,38 @@ void streamCopyRecord(int streamID2, int streamID1)
         }
     }
 
-  if ( filetype == FILETYPE_UNDEF )
+  if ( filetype == CDI_FILETYPE_UNDEF )
     Error("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
 
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       grbCopyRecord(streamptr2, streamptr1);
       break;
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       srvCopyRecord(streamptr2, streamptr1);
       break;
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       extCopyRecord(streamptr2, streamptr1);
       break;
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       iegCopyRecord(streamptr2, streamptr1);
       break;
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
+    case CDI_FILETYPE_NC5:
       cdfCopyRecord(streamptr2, streamptr1);
       break;
 #endif
@@ -53287,7 +53410,6 @@ void streamCopyRecord(int streamID2, int streamID1)
 void cdi_create_records(stream_t *streamptr, int tsID)
 {
   unsigned nrecords, maxrecords;
-  record_t *records;
 
   tsteps_t *sourceTstep = streamptr->tsteps;
   tsteps_t *destTstep = sourceTstep + tsID;
@@ -53321,7 +53443,7 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 	{
 	  int varID = sourceTstep->records[recID].varID;
 	  nrecords += (varID == CDI_UNDEFID /* varID = CDI_UNDEFID for write mode !!! */
-                       || vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT);
+                       || vlistInqVarTimetype(vlistID, varID) != TIME_CONSTANT);
           //    printf("varID nrecords %d %d %d \n", varID, nrecords, vlistInqVarTsteptype(vlistID, varID));
 	}
     }
@@ -53331,10 +53453,8 @@ void cdi_create_records(stream_t *streamptr, int tsID)
     }
   //  printf("tsID, nrecords %d %d\n", tsID, nrecords);
 
-  if ( maxrecords > 0 )
-    records = (record_t *) Malloc(maxrecords*sizeof(record_t));
-  else
-    records = NULL;
+  record_t *records = NULL;
+  if ( maxrecords > 0 ) records = (record_t *) Malloc(maxrecords*sizeof(record_t));
 
   destTstep->records    = records;
   destTstep->recordSize = (int)maxrecords;
@@ -53355,16 +53475,42 @@ void cdi_create_records(stream_t *streamptr, int tsID)
           destTstep->records[recID].used = curRecord->used;
           if ( curRecord->used != CDI_UNDEFID && curRecord->varID != -1 ) /* curRecord->varID = -1 for write mode !!! */
             {
-              if ( vlistInqVarTsteptype(vlistID, curRecord->varID) != TSTEP_CONSTANT )
+              if ( vlistInqVarTimetype(vlistID, curRecord->varID) != TIME_CONSTANT )
                 {
                   destTstep->records[recID].position = CDI_UNDEFID;
                   destTstep->records[recID].size     = 0;
-                  destTstep->records[recID].used     = FALSE;
+                  destTstep->records[recID].used     = false;
                 }
             }
 	}
     }
 }
+
+
+void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1, const char *container_name)
+{
+  int fileID1 = streamptr1->fileID;
+  int fileID2 = streamptr2->fileID;
+
+  int tsID    = streamptr1->curTsID;
+  int vrecID  = streamptr1->tsteps[tsID].curRecID;
+  int recID   = streamptr1->tsteps[tsID].recIDs[vrecID];
+  off_t recpos  = streamptr1->tsteps[tsID].records[recID].position;
+  size_t recsize = streamptr1->tsteps[tsID].records[recID].size;
+
+  if (fileSetPos(fileID1, recpos, SEEK_SET) != 0)
+    Error("Cannot seek input file for %s record copy!", container_name);
+
+  char *buffer = (char *) Malloc(recsize);
+
+  if (fileRead(fileID1, buffer, recsize) != recsize)
+    Error("Failed to read record from %s file for copying!", container_name);
+
+  if (fileWrite(fileID2, buffer, recsize) != recsize)
+    Error("Failed to write record to %s file when copying!", container_name);
+
+  Free(buffer);
+}
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -53377,54 +53523,33 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
 
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBSERVICE)
 
-
 typedef struct {
   int param;
   int level;
-} SRVCOMPVAR;
+} srvcompvar_t;
 
 
-static int srvInqDatatype(int prec)
+static
+int srvInqDatatype(int prec)
 {
-  int datatype;
-
-  if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-  else                            datatype = DATATYPE_FLT32;
-
-  return (datatype);
+  return (prec == EXSE_DOUBLE_PRECISION) ? CDI_DATATYPE_FLT64 : CDI_DATATYPE_FLT32;
 }
 
-
-static int srvDefDatatype(int datatype)
+static
+int srvDefDatatype(int datatype)
 {
-  int prec;
-
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+  if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
     Error("CDI/SERVICE library does not support complex numbers!");
 
-  if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
-    datatype = DATATYPE_FLT32;
+  if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 )
+    datatype = CDI_DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
-
-  return (prec);
+  return (datatype == CDI_DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -53454,25 +53579,18 @@ int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
 
   *varID = vlistInqVarID(vlistID, icode);
 
-  if ( *varID == UNDEFID ) Error("Code %d undefined", icode);
+  if ( *varID == CDI_UNDEFID ) Error("Code %d undefined", icode);
 
   zaxisID = vlistInqVarZaxis(vlistID, *varID);
 
   *levelID = zaxisInqLevelID(zaxisID, (double) ilevel);
 
-  return (1);
+  return 1;
 }
 */
 
-void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
-  int status;
-  int header[8];
-  int gridID;
-  int i, size;
-  double missval;
-  void *srvp = streamptr->record->exsep;
-
   int vlistID  = streamptr->vlistID;
   int fileID   = streamptr->fileID;
   int tsID     = streamptr->curTsID;
@@ -53483,21 +53601,23 @@ void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
 
   fileSetPos(fileID, recpos, SEEK_SET);
 
-  status = srvRead(fileID, srvp);
+  void *srvp = streamptr->record->exsep;
+  int status = srvRead(fileID, srvp);
   if ( status != 0 )
     Error("Failed to read record from SRV file");
 
+  int header[8];
   srvInqHeader(srvp, header);
   srvInqDataDP(srvp, data);
 
-  missval = vlistInqVarMissval(vlistID, varID);
-  gridID  = vlistInqVarGrid(vlistID, varID);
-  size    = gridInqSize(gridID);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  int gridID  = vlistInqVarGrid(vlistID, varID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( size_t i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -53514,20 +53634,21 @@ void srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 
 void srvDefRecord(stream_t *streamptr)
 {
-  int header[8];
-  Record *restrict record = streamptr->record;
-  srvrec_t *restrict srvp = (srvrec_t*) record->exsep;
-  int gridID = record->gridID;
+  Record *record = streamptr->record;
+  srvrec_t *srvp = (srvrec_t*) record->exsep;
 
   int pdis, pcat, pnum;
   cdiDecodeParam(record->param, &pnum, &pcat, &pdis);
+
+  int header[8];
   header[0] = pnum;
   header[1] = record->level;
   header[2] = record->date;
   header[3] = record->time;
 
-  int xsize = gridInqXsize(gridID),
-    ysize = gridInqYsize(gridID);
+  int gridID = record->gridID;
+  size_t xsize = gridInqXsize(gridID),
+         ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -53537,13 +53658,14 @@ void srvDefRecord(stream_t *streamptr)
   if ( gridInqSize(gridID) != xsize*ysize )
     Error("Internal problem with gridsize!");
 
-  header[4] = xsize;
-  header[5] = ysize;
+  cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
+
+  header[4] = (int)xsize;
+  header[5] = (int)ysize;
   header[6] = 0;
   header[7] = 0;
 
   int datatype = record->prec;
-
   srvp->dprec = srvDefDatatype(datatype);
 
   srvDefHeader(srvp, header);
@@ -53560,7 +53682,7 @@ void srvWriteRecord(stream_t *streamptr, const double *data)
 }
 
 static
-void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ysize,
+void srv_add_record(stream_t *streamptr, int param, int level, size_t xsize, size_t ysize,
                     size_t recsize, off_t position, int prec)
 {
   int vlistID = streamptr->vlistID;
@@ -53573,14 +53695,12 @@ void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ys
   record->param    = param;
   record->ilevel   = level;
 
-  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
+  grid_t *grid = (grid_t*) Malloc(sizeof(*grid));
   grid_init(grid);
   cdiGridTypeInit(grid, GRID_GENERIC, xsize*ysize);
-  grid->xsize = xsize;
-  grid->ysize = ysize;
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  grid->x.size = xsize;
+  grid->y.size = ysize;
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
   int gridID = gridAdded.Id;
   if (!gridAdded.isNew) Free(grid);
   /*
@@ -53605,8 +53725,7 @@ void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ys
   streamptr->nrecs++;
 
   if ( CDI_Debug )
-    Message("varID = %d gridID = %d levelID = %d",
-	    varID, gridID, levelID);
+    Message("varID = %d gridID = %d levelID = %d", varID, gridID, levelID);
 }
 
 static
@@ -53626,11 +53745,10 @@ void srvScanTimestep1(stream_t *streamptr)
     taxis = &streamptr->tsteps[tsID].taxis;
   }
 
-
   int fileID = streamptr->fileID;
 
   int nrecs = 0;
-  while ( TRUE )
+  while ( true )
     {
       int header[8];
       recpos = fileGetPos(fileID);
@@ -53713,7 +53831,7 @@ void srvScanTimestep1(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
@@ -53723,7 +53841,7 @@ void srvScanTimestep1(stream_t *streamptr)
 	{
 	  streamptr->ntsteps = 0;
 	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
-            vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+            vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
     }
 }
@@ -53732,54 +53850,43 @@ static
 int srvScanTimestep2(stream_t *streamptr)
 {
   int header[8];
-  int status;
-  int fileID;
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
-  int tsID;
-  int varID;
   off_t recpos = 0;
-  int nrecords, nrecs, recID, rindex;
-  int nextstep;
-  taxis_t *taxis;
-  int vlistID;
-  SRVCOMPVAR compVar, compVar0;
+  srvcompvar_t compVar, compVar0;
   void *srvp = streamptr->record->exsep;
 
   streamptr->curTsID = 1;
 
-  vlistID = streamptr->vlistID;
-  fileID  = streamptr->fileID;
+  int vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
 
-  tsID = streamptr->rtsteps;
+  int tsID = streamptr->rtsteps;
   if ( tsID != 1 )
     Error("Internal problem! unexpected timestep %d", tsID+1);
 
-  taxis = &streamptr->tsteps[tsID].taxis;
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
 
   fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
   cdi_create_records(streamptr, tsID);
 
-  nrecords = streamptr->tsteps[0].nallrecs;
+  int nrecords = streamptr->tsteps[0].nallrecs;
   streamptr->tsteps[1].recIDs = (int *) Malloc((size_t)nrecords * sizeof (int));
   streamptr->tsteps[1].nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     streamptr->tsteps[1].recIDs[recID] = -1;
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
-      varID = streamptr->tsteps[0].records[recID].varID;
       streamptr->tsteps[tsID].records[recID].position =
 	streamptr->tsteps[0].records[recID].position;
       streamptr->tsteps[tsID].records[recID].size     =
 	streamptr->tsteps[0].records[recID].size;
     }
 
-  for ( rindex = 0; rindex <= nrecords; rindex++ )
+  for ( int rindex = 0; rindex <= nrecords; rindex++ )
     {
       recpos = fileGetPos(fileID);
-      status = srvRead(fileID, srvp);
+      int status = srvRead(fileID, srvp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 2;
@@ -53789,12 +53896,12 @@ int srvScanTimestep2(stream_t *streamptr)
 
       srvInqHeader(srvp, header);
 
-      rcode  = header[0];
-      rlevel = header[1];
-      vdate  = header[2];
-      vtime  = header[3];
+      int rcode  = header[0];
+      int rlevel = header[1];
+      int vdate  = header[2];
+      int vtime  = header[3];
 
-      param = cdiEncodeParam(rcode, 255, 255);
+      int param = cdiEncodeParam(rcode, 255, 255);
 
       if ( rindex == 0 )
 	{
@@ -53805,21 +53912,22 @@ int srvScanTimestep2(stream_t *streamptr)
 
       compVar.param = param;
       compVar.level = rlevel;
-      nextstep = FALSE;
+      bool nextstep = false;
+      int recID;
       for ( recID = 0; recID < nrecords; recID++ )
 	{
 	  compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
 	  compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-	  if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) == 0 )
+	  if ( memcmp(&compVar0, &compVar, sizeof(srvcompvar_t)) == 0 )
 	    {
 	      if ( streamptr->tsteps[tsID].records[recID].used )
 		{
-		  nextstep = TRUE;
+		  nextstep = true;
 		}
 	      else
 		{
-		  streamptr->tsteps[tsID].records[recID].used = TRUE;
+		  streamptr->tsteps[tsID].records[recID].used = true;
 		  streamptr->tsteps[tsID].recIDs[rindex] = recID;
 		}
 	      break;
@@ -53828,7 +53936,7 @@ int srvScanTimestep2(stream_t *streamptr)
       if ( recID == nrecords )
 	{
 	  Warning("Code %d level %d not found at timestep %d", rcode, rlevel, tsID+1);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       if ( nextstep ) break;
@@ -53841,25 +53949,25 @@ int srvScanTimestep2(stream_t *streamptr)
       compVar0.param  = streamptr->tsteps[tsID].records[recID].param;
       compVar0.level = streamptr->tsteps[tsID].records[recID].ilevel;
 
-      if ( memcmp(&compVar0, &compVar, sizeof(SRVCOMPVAR)) != 0 )
+      if ( memcmp(&compVar0, &compVar, sizeof(srvcompvar_t)) != 0 )
 	{
 	  Message("tsID = %d recID = %d param = %3d new %3d  level = %3d new %3d",
 		  tsID, recID,
 		  streamptr->tsteps[tsID].records[recID].param, param,
 		  streamptr->tsteps[tsID].records[recID].ilevel, rlevel);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       streamptr->tsteps[1].records[recID].position = recpos;
     }
 
-  nrecs = 0;
-  for ( recID = 0; recID < nrecords; recID++ )
+  int nrecs = 0;
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       if ( ! streamptr->tsteps[tsID].records[recID].used )
 	{
-	  varID = streamptr->tsteps[tsID].records[recID].varID;
-          vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
+          vlistDefVarTimetype(vlistID, varID, TIME_CONSTANT);
 	}
       else
 	{
@@ -53876,44 +53984,37 @@ int srvScanTimestep2(stream_t *streamptr)
       if ( tsID != streamptr->rtsteps )
 	Error("Internal error. tsID = %d", tsID);
 
-      streamptr->tsteps[tsID-1].next   = TRUE;
+      streamptr->tsteps[tsID-1].next   = true;
       streamptr->tsteps[tsID].position = recpos;
     }
 
-  return (0);
+  return 0;
 }
 
 
 int srvInqContents(stream_t *streamptr)
 {
-  int fileID;
-  int status = 0;
-
-  fileID = streamptr->fileID;
-
   streamptr->curTsID = 0;
 
   srvScanTimestep1(streamptr);
 
+  int status = 0;
   if ( streamptr->ntsteps == -1 ) status = srvScanTimestep2(streamptr);
 
+  int fileID = streamptr->fileID;
   fileSetPos(fileID, 0, SEEK_SET);
 
-  return (status);
+  return status;
 }
 
 static
 long srvScanTimestep(stream_t *streamptr)
 {
   int header[8];
-  int status;
-  int fileID;
   /* int rxsize = 0, rysize = 0; */
-  int param = 0;
-  int rcode = 0, rlevel = 0, vdate = 0, vtime = 0;
   off_t recpos = 0;
   int recID;
-  int rindex, nrecs = 0;
+  int nrecs = 0;
   void *srvp = streamptr->record->exsep;
   /*
   if ( CDI_Debug )
@@ -53939,14 +54040,14 @@ long srvScanTimestep(stream_t *streamptr)
       for ( recID = 0; recID < nrecs; recID++ )
 	streamptr->tsteps[tsID].recIDs[recID] = streamptr->tsteps[1].recIDs[recID];
 
-      fileID = streamptr->fileID;
+      int fileID = streamptr->fileID;
 
       fileSetPos(fileID, streamptr->tsteps[tsID].position, SEEK_SET);
 
-      for ( rindex = 0; rindex <= nrecs; rindex++ )
+      for ( int rindex = 0; rindex <= nrecs; rindex++ )
 	{
 	  recpos = fileGetPos(fileID);
-	  status = srvRead(fileID, srvp);
+	  int status = srvRead(fileID, srvp);
 	  if ( status != 0 )
 	    {
 	      streamptr->ntsteps = streamptr->rtsteps + 1;
@@ -53956,14 +54057,14 @@ long srvScanTimestep(stream_t *streamptr)
 
 	  srvInqHeader(srvp, header);
 
-	  rcode  = header[0];
-	  rlevel = header[1];
-	  vdate  = header[2];
-	  vtime  = header[3];
+	  int rcode  = header[0];
+	  int rlevel = header[1];
+	  int vdate  = header[2];
+	  int vtime  = header[3];
           /* rxsize = header[4]; */
           /* rysize = header[5]; */
 
-	  param = cdiEncodeParam(rcode, 255, 255);
+	  int param = cdiEncodeParam(rcode, 255, 255);
 
 	  // if ( rindex == nrecs ) break; gcc-4.5 internal compiler error
 	  if ( rindex == nrecs ) continue;
@@ -54001,7 +54102,7 @@ long srvScanTimestep(stream_t *streamptr)
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
-	  streamptr->tsteps[tsID-1].next   = 1;
+	  streamptr->tsteps[tsID-1].next   = true;
 	  streamptr->tsteps[tsID].position = recpos;
 	}
 
@@ -54015,128 +54116,61 @@ long srvScanTimestep(stream_t *streamptr)
       streamptr->ntsteps = tsID;
     }
 
-  return (streamptr->ntsteps);
+  return streamptr->ntsteps;
 }
 
 
 int srvInqTimestep(stream_t *streamptr, int tsID)
 {
-  long ntsteps;
-  int nrecs;
-
   if ( tsID == 0 && streamptr->rtsteps == 0 )
     Error("Call to cdiInqContents missing!");
 
   if ( CDI_Debug )
     Message("tsID = %d rtsteps = %d", tsID, streamptr->rtsteps);
 
-  ntsteps = UNDEFID;
-  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == UNDEFID )
+  long ntsteps = CDI_UNDEFID;
+  while ( ( tsID + 1 ) > streamptr->rtsteps && ntsteps == CDI_UNDEFID )
     ntsteps = srvScanTimestep(streamptr);
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != UNDEFID )
-    {
-      nrecs = 0;
-    }
-  else
+  int nrecs = 0;
+  if ( !(tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID) )
     {
       streamptr->curTsID = tsID;
       nrecs = streamptr->tsteps[tsID].nrecs;
     }
 
-  return (nrecs);
+  return nrecs;
 }
 
 
-void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
-  int vlistID, fileID;
-  int levID, nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[8];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
-  void *srvp = streamptr->record->exsep;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  currentfilepos = fileGetPos(fileID);
-
-  for (levID = 0; levID < nlevs; levID++)
-    {
-      /* NOTE: tiles are not supported here! */
-      recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-      recpos = streamptr->tsteps[tsid].records[recID].position;
-      fileSetPos(fileID, recpos, SEEK_SET);
-      if (srvRead(fileID, srvp) < 0)
-        abort();
-      srvInqHeader(srvp, header);
-      srvInqDataDP(srvp, &data[levID*gridsize]);
-    }
-  fileSetPos(fileID, currentfilepos, SEEK_SET);
-
-  *nmiss = 0;
-  for ( i = 0; i < nlevs*gridsize; i++ )
-    if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
-      {
-	data[i] = missval;
-	(*nmiss)++;
-      }
-}
-
-
-void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
-{
-  int vlistID, fileID;
-  int nlevs, gridID, gridsize;
-  off_t recpos, currentfilepos;
-  int header[8];
-  int tsid;
-  int recID;
-  int i;
-  double missval;
   void *srvp = streamptr->record->exsep;
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
-  nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
-  missval  = vlistInqVarMissval(vlistID, varID);
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  tsid     = streamptr->curTsID;
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
+  double missval = vlistInqVarMissval(vlistID, varID);
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  int tsid     = streamptr->curTsID;
 
-  currentfilepos = fileGetPos(fileID);
+  off_t currentfilepos = fileGetPos(fileID);
 
   /* NOTE: tiles are not supported here! */
-  recID = streamptr->vars[varID].recordTable[0].recordID[levID];
-  recpos = streamptr->tsteps[tsid].records[recID].position;
+  int recID = streamptr->vars[varID].recordTable[0].recordID[levID];
+  off_t recpos = streamptr->tsteps[tsid].records[recID].position;
   fileSetPos(fileID, recpos, SEEK_SET);
-  if (srvRead(fileID, srvp) < 0)
-    abort();
+  if ( srvRead(fileID, srvp) < 0 ) abort();
+  int header[8];
   srvInqHeader(srvp, header);
   srvInqDataDP(srvp, data);
 
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 
   *nmiss = 0;
-  for ( i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -54145,105 +54179,39 @@ void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
+void srvReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
-  int fileID;
-  int levID, nlevs, gridID, gridsize;
-  int zaxisID;
-  double level;
-  int header[8];
-  int xsize, ysize;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
-
-  if ( CDI_Debug )
-    Message("streamID = %d  varID = %d", streamptr->self, varID);
-
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  gridsize = gridInqSize(gridID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  nlevs    = zaxisInqSize(zaxisID);
-
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
-
-  cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
-
-  header[0] = pnum;
-  header[2] = streamptr->tsteps[tsID].taxis.vdate;
-  header[3] = streamptr->tsteps[tsID].taxis.vtime;
-
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
-  if ( xsize == 0 || ysize == 0 )
-    {
-      xsize = gridInqSize(gridID);
-      ysize = 1;
-    }
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED ) ysize = 1;
-  if ( gridInqSize(gridID) != xsize*ysize )
-    Error("Internal problem with gridsize!");
-
-  header[4] = xsize;
-  header[5] = ysize;
-  header[6] = 0;
-  header[7] = 0;
-
-  datatype = vlistInqVarDatatype(vlistID, varID);
-
-  srvp->dprec = srvDefDatatype(datatype);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  for ( levID = 0; levID < nlevs; levID++ )
-    {
-      level = zaxisInqLevel(zaxisID, levID);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
-      header[1] = (int) level;
-      srvDefHeader(srvp, header);
-      srvDefDataDP(srvp, &data[levID*gridsize]);
-      srvWrite(fileID, srvp);
-    }
+  for ( size_t levID = 0; levID < nlevs; levID++)
+    srvReadVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize], nmiss);
 }
 
 
 void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double *data)
 {
-  int fileID;
-  int gridID;
-  int zaxisID;
-  double level;
-  int header[8];
-  int xsize, ysize;
-  int datatype;
-  int tsID;
-  int vlistID;
-  int pdis, pcat, pnum;
-  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
-  vlistID  = streamptr->vlistID;
-  fileID   = streamptr->fileID;
-  tsID     = streamptr->curTsID;
-  gridID   = vlistInqVarGrid(vlistID, varID);
-  zaxisID  = vlistInqVarZaxis(vlistID, varID);
-  level    = zaxisInqLevel(zaxisID, levID);
-
-  if ( CDI_Debug )
-    Message("gridID = %d zaxisID = %d", gridID, zaxisID);
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
 
+  int pdis, pcat, pnum;
   cdiDecodeParam(vlistInqVarParam(vlistID, varID), &pnum, &pcat, &pdis);
 
+  int header[8];
   header[0] = pnum;
-  header[1] = (int) level;
+  header[1] = (int)(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
   header[2] = streamptr->tsteps[tsID].taxis.vdate;
   header[3] = streamptr->tsteps[tsID].taxis.vtime;
 
-  xsize = gridInqXsize(gridID);
-  ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -54253,13 +54221,16 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   if ( gridInqSize(gridID) != xsize*ysize )
     Error("Internal problem with gridsize!");
 
+  cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
+
   header[4] = xsize;
   header[5] = ysize;
   header[6] = 0;
   header[7] = 0;
 
-  datatype = vlistInqVarDatatype(vlistID, varID);
+  int datatype = vlistInqVarDatatype(vlistID, varID);
 
+  srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
   srvp->dprec = srvDefDatatype(datatype);
 
   srvDefHeader(srvp, header);
@@ -54267,7 +54238,21 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   srvWrite(fileID, srvp);
 }
 
+
+void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
+{
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
+
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
+
+  for ( size_t levID = 0; levID < nlevs; levID++ )
+    srvWriteVarSliceDP(streamptr, varID, (int)levID, &data[levID*gridsize]);
+}
+
 #endif /* HAVE_LIBSERVICE */
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -54280,8 +54265,6 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <string.h>
-
 
 
 
@@ -54297,7 +54280,7 @@ static
 void streamvar_init_entry(stream_t *streamptr, int varID)
 {
   streamptr->vars[varID].ncvarid      = CDI_UNDEFID;
-  streamptr->vars[varID].defmiss      = 0;
+  streamptr->vars[varID].defmiss      = false;
 
   streamptr->vars[varID].subtypeSize  = 0;
   streamptr->vars[varID].recordTable  = NULL;
@@ -54312,30 +54295,24 @@ static
 int streamvar_new_entry(stream_t *streamptr)
 {
   int varID = 0;
-  int streamvarSize;
-  svarinfo_t *streamvar;
-
-  streamvarSize = streamptr->varsAllocated;
-  streamvar     = streamptr->vars;
+  int streamvarSize = streamptr->varsAllocated;
+  svarinfo_t *streamvar = streamptr->vars;
   /*
     Look for a free slot in streamvar.
     (Create the table the first time through).
   */
   if ( ! streamvarSize )
     {
-      int i;
-
       streamvarSize = 2;
-      streamvar
-        = (svarinfo_t *) Malloc((size_t)streamvarSize * sizeof(svarinfo_t));
+      streamvar = (svarinfo_t *) Malloc((size_t)streamvarSize * sizeof(svarinfo_t));
       if ( streamvar == NULL )
 	{
           Message("streamvarSize = %d", streamvarSize);
 	  SysError("Allocation of svarinfo_t failed");
 	}
 
-      for ( i = 0; i < streamvarSize; i++ )
-	streamvar[i].isUsed = FALSE;
+      for ( int i = 0; i < streamvarSize; i++ )
+	streamvar[i].isUsed = false;
     }
   else
     {
@@ -54350,11 +54327,8 @@ int streamvar_new_entry(stream_t *streamptr)
   */
   if ( varID == streamvarSize )
     {
-      int i;
-
       streamvarSize = 2*streamvarSize;
-      streamvar
-        = (svarinfo_t *) Realloc(streamvar,
+      streamvar = (svarinfo_t *) Realloc(streamvar,
                                  (size_t)streamvarSize * sizeof (svarinfo_t));
       if ( streamvar == NULL )
 	{
@@ -54363,8 +54337,8 @@ int streamvar_new_entry(stream_t *streamptr)
 	}
       varID = streamvarSize/2;
 
-      for ( i = varID; i < streamvarSize; i++ )
-	streamvar[i].isUsed = FALSE;
+      for ( int i = varID; i < streamvarSize; i++ )
+	streamvar[i].isUsed = false;
     }
 
   streamptr->varsAllocated = streamvarSize;
@@ -54372,8 +54346,9 @@ int streamvar_new_entry(stream_t *streamptr)
 
   streamvar_init_entry(streamptr, varID);
 
-  streamptr->vars[varID].isUsed = TRUE;
-  return (varID);
+  streamptr->vars[varID].isUsed = true;
+
+  return varID;
 }
 
 
@@ -54383,7 +54358,7 @@ allocate_record_table_entry(stream_t *streamptr, int varID, int subID, int nlevs
   int *level    = (int *) Malloc((size_t)nlevs * sizeof (int));
   int *lindex   = (int *) Malloc((size_t)nlevs * sizeof (int));
 
-  for (int levID = 0; levID < nlevs; levID++ )
+  for ( int levID = 0; levID < nlevs; levID++ )
     {
       level[levID]    = CDI_UNDEFID;
       lindex[levID]   = levID;
@@ -54428,7 +54403,7 @@ int stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
 
   streamptr->vars[varID].subtypeID = tilesetID;
 
-  return (varID);
+  return varID;
 }
 /*
  * Local Variables:
@@ -54449,20 +54424,20 @@ int stream_new_var(stream_t *streamptr, int gridID, int zaxisID, int tilesetID)
 static
 size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		 int date, int time, int tsteptype, int numavg,
-		 size_t datasize, const void *data, int nmiss, void **gribbuffer,
+		 size_t datasize, const void *data, size_t nmiss, void **gribbuffer,
 		 int comptype, void *gribContainer)
 {
   size_t nbytes = 0;
 
 #ifdef HAVE_LIBCGRIBEX
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       size_t gribbuffersize = datasize*4+3000;
       *gribbuffer = Malloc(gribbuffersize);
 
       nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
 			     date, time, tsteptype, numavg,
-			     (long) datasize, data, nmiss, *gribbuffer, gribbuffersize);
+			     datasize, data, nmiss, *gribbuffer, gribbuffersize);
     }
   else
 #endif
@@ -54483,7 +54458,7 @@ size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID,
 			     (long) datasize, datap, nmiss, gribbuffer, &gribbuffersize,
 			     comptype, gribContainer);
       
-      if ( memtype == MEMTYPE_FLOAT ) free((void*)datap);
+      if ( memtype == MEMTYPE_FLOAT ) Free((void*)datap);
     }
 #else
     {
@@ -54505,7 +54480,7 @@ size_t grbSzip(int filetype, void *gribbuffer, size_t gribbuffersize)
   /*  memcpy(buffer, gribbuffer, gribbuffersize); */
 
   size_t nbytes = 0;
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       nbytes = (size_t)gribZip((unsigned char *)gribbuffer, (long) gribbuffersize, (unsigned char *)buffer, (long) buffersize);
     }
@@ -54546,12 +54521,91 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
 
   size_t nbytes = recsize;
 
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
-      long unzipsize;
-      int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
+      if ( cdiGribChangeParameterID.active )
+        {
+          // Even if you are stream-copy records you might need to change a bit of grib-header !
+#if defined HAVE_LIBCGRIBEX
+          void *gh = cgribex_handle_new_from_meassage((void*) gribbuffer, recsize);
+          cgribexChangeParameterIdentification(gh, cdiGribChangeParameterID.code, cdiGribChangeParameterID.ltype, cdiGribChangeParameterID.lev);
+          cgribex_handle_delete(gh);
+#elif defined HAVE_LIBGRIB_API
+          void *gh = (void*)grib_handle_new_from_message(NULL, (void*) gribbuffer, recsize);
+          gribapiChangeParameterIdentification(gh, cdiGribChangeParameterID.code, cdiGribChangeParameterID.ltype, cdiGribChangeParameterID.lev);
+          grib_handle_delete(gh);
+#endif
+          cdiGribChangeParameterID.active = false; // after grib attributes have been changed turn it off again
+        }
+    }
+
+#ifdef HIRLAM_EXTENSIONS
+  // Even if you are stream-copy records you might need to change a bit of grib-header !
+
+  if ( cdiGribDataScanningMode.active )
+    // allowed modes: <0, 64, 96>; Default is 64
+    // This will overrule the old scanning mode of the given grid
+  {
+    grib_handle *gh = NULL;
+    gh = grib_handle_new_from_message(NULL, (void *) gribbuffer, recsize);
+
+    int scanModeIN = gribapiGetScanningMode(gh);
+
+    grib_handle_delete(gh);
+
+    if (cdiDebugExt>=20) Message("Change GribDataScanningMode => %d (scanModeIN = %d)", cdiGribDataScanningMode.value, scanModeIN);
+
+    if (scanModeIN != cdiGribDataScanningMode.value)
+    {
+        //int zip;
+        size_t nmiss = 0;
+
+        int vlistID = streamptr1->vlistID;
+        int varID   = streamptr1->tsteps[tsID].records[recID].varID;
+        int levelID = streamptr1->tsteps[tsID].records[recID].levelID;
+        //gribbuffer = (unsigned char *) streamptr->record->buffer;
+        // allocate above ..
+        int gridID   = vlistInqVarGrid(vlistID, varID);
+
+        size_t gridsize = vlistGridsizeMax(vlistID);
+        if ( vlistNumber(vlistID) != CDI_REAL ) gridsize *= 2;
+        double *data = (double *) malloc(gridsize*sizeof(double));
+        //int missval = vlistInqVarMissval(vlistID, varID);
+
+        //streamptr->numvals += gridsize;
+
+        // memtype: MEMTYPE_FLOAT or MEMTYPE_DOUBLE
+        //int statusDC = grbDecode(filetype, MEMTYPE_DOUBLE, gribbuffer, recsize, data, gridsize, streamptr1->unreduced, &nmiss, missval, vlistID, varID);
+        //int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
+        //              int unreduced, size_t *nmiss, double missval, int vlistID, int varID);
+
+        //streamptr1->tsteps[tsID].records[recID].zip = zip;
+        //gribapiSetScanningMode(gh, cdoGribDataScanningMode);  // T.B.D. this will be done by grbDecode..
+
+        //varID   = streamptr1->record->varID;
+        //levelID = streamptr1->record->levelID;
+
+        if (cdiDebugExt>=20) Message(" processing varID %d; levelID %d",varID,levelID);
+
+        grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+        //grb_write_var_slice(streamptr, varID, levelID, memtype, ((double*)data)+levelID*gridsize, nmiss);
 
-      if ( izip == 0 && streamptr2->comptype == COMPRESS_SZIP )
+        //grb_write_var(streamptr2, varID, MEMTYPE_DOUBLE, data, nmiss);
+        //grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
+        //grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+
+        free(data);
+        free(gribbuffer);
+    }
+  }
+#endif // HIRLAM_EXTENSIONS
+
+  if ( filetype == CDI_FILETYPE_GRB )
+    {
+      size_t unzipsize;
+      int izip = gribGetZip(recsize, gribbuffer, &unzipsize);
+
+      if ( izip == 0 && streamptr2->comptype == CDI_COMPRESS_SZIP )
           nbytes = grbSzip(filetype, gribbuffer, nbytes);
     }
 
@@ -54568,7 +54622,7 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
 }
 
 
-void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
   void *gribbuffer = NULL;
   void *gc = NULL;
@@ -54583,17 +54637,15 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   int tsID      = streamptr->curTsID;
   int date      = streamptr->tsteps[tsID].taxis.vdate;
   int time      = streamptr->tsteps[tsID].taxis.vtime;
-  int numavg    = 0;
-  if ( vlistInqVarTimave(vlistID, varID) )
-    numavg = streamptr->tsteps[tsID].taxis.numavg;
+  int numavg    = (tsteptype == TSTEP_AVG) ? streamptr->tsteps[tsID].taxis.numavg : 0;
 
   if ( CDI_Debug )
     Message("gridID = %d zaxisID = %d", gridID, zaxisID);
 
-  size_t datasize = (size_t)gridInqSize(gridID);
+  size_t datasize = gridInqSize(gridID);
 
 #ifdef HAVE_LIBCGRIBEX
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
     }
   else
@@ -54608,9 +54660,9 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 #endif
     }
 
-  if ( comptype != COMPRESS_JPEG && comptype != COMPRESS_SZIP ) comptype = COMPRESS_NONE;
+  if ( comptype != CDI_COMPRESS_JPEG && comptype != CDI_COMPRESS_SZIP ) comptype = CDI_COMPRESS_NONE;
 
-  if ( filetype == FILETYPE_GRB && comptype == COMPRESS_JPEG )
+  if ( filetype == CDI_FILETYPE_GRB && comptype == CDI_COMPRESS_JPEG )
     {
       static int ljpeg_warn = 1;
       if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
@@ -54620,11 +54672,10 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   size_t nbytes = grbEncode(filetype, memtype, varID, levelID, vlistID, gridID, zaxisID, date, time, tsteptype, numavg,
                             datasize, data, nmiss, &gribbuffer, comptype, gc);
 
-  if ( filetype == FILETYPE_GRB && streamptr->comptype == COMPRESS_SZIP )
+  if ( filetype == CDI_FILETYPE_GRB && streamptr->comptype == CDI_COMPRESS_SZIP )
     nbytes = grbSzip(filetype, gribbuffer, nbytes);
 
-  size_t (*myFileWrite)(int fileID, const void *restrict buffer,
-                        size_t len, int tsID)
+  size_t (*myFileWrite)(int fileID, const void *restrict buffer, size_t len, int tsID)
     = (size_t (*)(int, const void *restrict, size_t, int))
     namespaceSwitchGet(NSSWITCH_FILE_WRITE).func;
   size_t nwrite = myFileWrite(fileID, gribbuffer, nbytes, tsID);
@@ -54639,22 +54690,22 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 }
 
 
-void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
 {
   int vlistID  = streamptr->vlistID,
     gridID   = vlistInqVarGrid(vlistID, varID),
-    gridsize = gridInqSize(gridID),
     zaxisID  = vlistInqVarZaxis(vlistID, varID),
     nlevs    = zaxisInqSize(zaxisID);
+  size_t gridsize = gridInqSize(gridID);
   double missval = vlistInqVarMissval(vlistID, varID);
 
-  size_t chunkLen = (size_t)gridsize;
+  size_t chunkLen = gridsize;
   if ( memtype == MEMTYPE_FLOAT )
     for ( int levelID = 0; levelID < nlevs; levelID++ )
       {
         const float *restrict fdata = ((const float *)data)+levelID*gridsize;
         
-        int nmiss_slice = 0;
+        size_t nmiss_slice = 0;
         if ( nmiss )
           for ( size_t i = 0; i < chunkLen; ++i )
             nmiss_slice += DBL_IS_EQUAL(fdata[i], missval);
@@ -54666,7 +54717,7 @@ void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data
       {
         const double *restrict ddata = ((const double *)data)+levelID*gridsize;
         
-        int nmiss_slice = 0;
+        size_t nmiss_slice = 0;
         if ( nmiss )
           for ( size_t i = 0; i < chunkLen; ++i )
             nmiss_slice += DBL_IS_EQUAL(ddata[i], missval);
@@ -54676,7 +54727,7 @@ void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data
 }
 
 
-void grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+void grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
 {
   int varID   = streamptr->record->varID;
   int levelID = streamptr->record->levelID;
@@ -54694,20 +54745,20 @@ void grb_write_record(stream_t *streamptr, int memtype, const void *data, int nm
 
 
 static
-int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
-	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
+int grbDecode(int filetype, int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+	      int unreduced, size_t *nmiss, double missval, int vlistID, int varID)
 {
   int status = 0;
 
 #if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
 #if  defined  (HAVE_LIBGRIB_API)
       extern int cdiNAdditionalGRIBKeys;
       if ( cdiNAdditionalGRIBKeys > 0 )
 	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
 #endif
-      status = cgribexDecode(memtype, gribbuffer, gribsize, data, (long) datasize, unreduced, nmiss, missval);
+      status = cgribexDecode(memtype, gribbuffer, gribsize, data, datasize, unreduced, nmiss, missval);
     }
   else
 #endif
@@ -54717,14 +54768,14 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
       if ( memtype == MEMTYPE_FLOAT )
         datap = Malloc(datasize*sizeof(double));
 
-      status = gribapiDecode(gribbuffer, gribsize, datap, (long) datasize, unreduced, nmiss, missval, vlistID, varID);
+      status = gribapiDecode(gribbuffer, gribsize, datap, datasize, unreduced, nmiss, missval, vlistID, varID);
 
       if ( memtype == MEMTYPE_FLOAT )
         {
           float *dataf = (float*) data;
           double *datad = (double*) datap;
           for ( size_t i = 0; i < datasize; ++i ) dataf[i] = (float) datad[i];
-          free((void*)datap);
+          Free((void*)datap);
         }
     }
 #else
@@ -54742,12 +54793,12 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 {
   int zip = 0;
   int izip;
-  long unzipsize;
+  size_t unzipsize;
 
   size_t igribsize = *gribsize;
   size_t ogribsize = *gribsize;
 
-  if ( (izip = gribGetZip((long)igribsize, (unsigned char *)gribbuffer, &unzipsize)) > 0 )
+  if ( (izip = gribGetZip(igribsize, (unsigned char *)gribbuffer, &unzipsize)) > 0 )
     {
       zip = izip;
       if ( izip == 128 ) /* szip */
@@ -54755,10 +54806,10 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 	  unsigned char *itmpbuffer = NULL;
 	  size_t itmpbuffersize = 0;
 
-	  if ( unzipsize < (long) igribsize )
+	  if ( unzipsize < igribsize )
 	    {
-	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
-	      return (0);
+	      fprintf(stderr, "Decompressed size smaller than compressed size (in %zu; out %zu)!\n", igribsize, unzipsize);
+	      return 0;
 	    }
 
 	  if ( itmpbuffersize < igribsize )
@@ -54771,7 +54822,7 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 
 	  unzipsize += 100; /* need 0 to 1 bytes for rounding of bds */
 
-	  ogribsize = (size_t)gribUnzip((unsigned char *)gribbuffer, unzipsize, itmpbuffer, (long)igribsize);
+	  ogribsize = (size_t)gribUnzip((unsigned char *)gribbuffer, (long)unzipsize, itmpbuffer, (long)igribsize);
 
 	  Free(itmpbuffer);
 
@@ -54789,7 +54840,7 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 }
 
 
-void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
+void grb_read_record(stream_t * streamptr, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -54805,7 +54856,7 @@ void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
   int varID   = streamptr->tsteps[tsID].records[recID].varID;
 
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   streamptr->numvals += gridsize;
 
@@ -54818,11 +54869,11 @@ void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
 
   streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
-  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 }
 
 
-void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int *nmiss)
+void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -54833,14 +54884,14 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
   int tsID    = streamptr->curTsID;
 
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   off_t currentfilepos = fileGetPos(fileID);
 
   int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
   int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
   if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+    Message("nlevs = %d gridID = %d gridsize = %zu", nlevs, gridID, gridsize);
   *nmiss = 0;
   for (int levelID = 0; levelID < nlevs; levelID++ )
     {
@@ -54854,7 +54905,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
 
       double missval = vlistInqVarMissval(vlistID, varID);
 
-      int imiss;
+      size_t imiss;
 
       streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
@@ -54864,7 +54915,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
       else
         datap = (double*)data + levelID*gridsize;
 
-      grbDecode(filetype, memtype, gribbuffer, (int)recsize, datap, (size_t)gridsize,
+      grbDecode(filetype, memtype, gribbuffer, recsize, datap, gridsize,
                 streamptr->unreduced, &imiss, missval, vlistID, varID);
 
       *nmiss += imiss;
@@ -54874,7 +54925,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
 }
 
 
-void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -54882,11 +54933,11 @@ void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
 
   int vlistID = streamptr->vlistID;
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
   int tsID = streamptr->curTsID;
 
   if ( CDI_Debug )
-    Message("gridID = %d gridsize = %d", gridID, gridsize);
+    Message("gridID = %d gridsize = %zu", gridID, gridsize);
 
   int fileID = streamptr->fileID;
 
@@ -54908,26 +54959,54 @@ void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
   streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
   double missval = vlistInqVarMissval(vlistID, varID);
-  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 }
 
 #endif
+#ifndef VLIST_VAR_H
+#define VLIST_VAR_H
+
 #ifdef HAVE_CONFIG_H
 #endif
 
-#ifdef HAVE_LIBNETCDF
+#ifndef _VLIST_H
+#endif
+
+int  vlistVarGetPackSize(vlist_t *p, int varID, void *context);
+void vlistVarPack(vlist_t *p, int varID,
+                  char * buffer, int bufferSize, int * pos, void *context);
+void vlistVarUnpack(int vlistID,
+                    char * buf, int size, int *position, int, void *context);
+int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB);
+void vlistDefVarIOrank    ( int, int, int );
+int  vlistInqVarIOrank    ( int, int );
+
+void cdiVlistCreateVarLevInfo(vlist_t *vlistptr, int varID);
 
+const char *vlistInqVarNamePtr(int vlistID, int varID);
 
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+#ifdef HAVE_CONFIG_H
+#endif
+
+#ifdef HAVE_LIBNETCDF
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
 
 
 void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
 {
-#if  defined  (HAVE_NETCDF4)
+#if  defined(HAVE_NETCDF4)
   int retval;
   /* Set chunking, shuffle, and deflate. */
   int shuffle = 1;
@@ -54935,56 +55014,55 @@ void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level)
 
   if ( deflate_level < 1 || deflate_level > 9 ) deflate_level = 1;
 
-  if ((retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)))
+  if ( (retval = nc_def_var_deflate(ncid, ncvarid, shuffle, deflate, deflate_level)) )
     {
       Error("nc_def_var_deflate failed, status = %d", retval);
     }
 #else
-  
-  static int lwarn = TRUE;
+  static bool lwarn = true;
   if ( lwarn )
     {
-      lwarn = FALSE;
+      lwarn = false;
       Warning("Deflate compression failed, NetCDF4 not available!");
     }
 #endif
 }
 
-static
+
 int cdfDefDatatype(int datatype, int filetype)
 {
   int xtype = NC_FLOAT;
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+  if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
     Error("CDI/NetCDF library does not support complex numbers!");
 
-  if ( filetype == FILETYPE_NC4 )
+  if ( filetype == CDI_FILETYPE_NC4 )
     {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
+      if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
 #if  defined  (HAVE_NETCDF4)
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_UBYTE;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_USHORT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_UINT;
+      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_UBYTE;
+      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_USHORT;
+      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_UINT;
 #else
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
+      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
 #endif
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
+      else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                        xtype = NC_FLOAT;
     }
   else
     {
-      if      ( datatype == DATATYPE_INT8   ) xtype = NC_BYTE;
-      else if ( datatype == DATATYPE_INT16  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_INT32  ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT8  ) xtype = NC_SHORT;
-      else if ( datatype == DATATYPE_UINT16 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_UINT32 ) xtype = NC_INT;
-      else if ( datatype == DATATYPE_FLT64  ) xtype = NC_DOUBLE;
-      else                                    xtype = NC_FLOAT;
+      if      ( datatype == CDI_DATATYPE_INT8   ) xtype = NC_BYTE;
+      else if ( datatype == CDI_DATATYPE_INT16  ) xtype = NC_SHORT;
+      else if ( datatype == CDI_DATATYPE_INT32  ) xtype = NC_INT;
+      else if ( datatype == CDI_DATATYPE_UINT8  ) xtype = NC_SHORT;
+      else if ( datatype == CDI_DATATYPE_UINT16 ) xtype = NC_INT;
+      else if ( datatype == CDI_DATATYPE_UINT32 ) xtype = NC_INT;
+      else if ( datatype == CDI_DATATYPE_FLT64  ) xtype = NC_DOUBLE;
+      else                                        xtype = NC_FLOAT;
     }
 
   return xtype;
@@ -54993,7 +55071,7 @@ int cdfDefDatatype(int datatype, int filetype)
 static
 void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
 {
-  if ( streamptr->vars[varID].defmiss == FALSE )
+  if ( streamptr->vars[varID].defmiss == false )
     {
       int vlistID = streamptr->vlistID;
       int fileID  = streamptr->fileID;
@@ -55006,12 +55084,18 @@ void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
 
       if ( xtype == NC_BYTE && missval > 127 && missval < 256 ) xtype = NC_INT;
 
-      cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
+      if ( lcheck == 0 ||
+           streamptr->ncmode != 2 ||
+           streamptr->filetype == CDI_FILETYPE_NC ||
+           streamptr->filetype == CDI_FILETYPE_NC2||
+           streamptr->filetype == CDI_FILETYPE_NC5 )
+        cdf_put_att_double(fileID, ncvarid, "_FillValue", (nc_type) xtype, 1, &missval);
+
       cdf_put_att_double(fileID, ncvarid, "missing_value", (nc_type) xtype, 1, &missval);
 
       if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
 
-      streamptr->vars[varID].defmiss = TRUE;
+      streamptr->vars[varID].defmiss = true;
     }
 }
 
@@ -55022,7 +55106,7 @@ void cdfDefInstitut(stream_t *streamptr)
   int fileID  = streamptr->fileID;
   int instID  = vlistInqInstitut(vlistID);
 
-  if ( instID != UNDEFID )
+  if ( instID != CDI_UNDEFID )
     {
       const char *longname = institutInqLongnamePtr(instID);
       if ( longname )
@@ -55045,7 +55129,7 @@ void cdfDefSource(stream_t *streamptr)
   int fileID  = streamptr->fileID;
   int modelID = vlistInqModel(vlistID);
 
-  if ( modelID != UNDEFID )
+  if ( modelID != CDI_UNDEFID )
     {
       const char *longname = modelInqNamePtr(modelID);
       if ( longname )
@@ -55064,7 +55148,7 @@ void cdfDefSource(stream_t *streamptr)
 static inline
 void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
 {
-  if (reqSize > *bufSize)
+  if ( reqSize > *bufSize )
     {
       *buf = Realloc(*buf, reqSize);
       *bufSize = reqSize;
@@ -55072,8 +55156,8 @@ void *resizeBuf(void **buf, size_t *bufSize, size_t reqSize)
   return *buf;
 }
 
-static
-void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
+
+void cdfDefineAttributes(int cdiID, int varID, int fileID, int ncvarID)
 {
   int atttype, attlen;
   size_t len;
@@ -55082,37 +55166,47 @@ void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
   size_t attBufSize = 0;
 
   int natts;
-  vlistInqNatts(vlistID, varID, &natts);
+  cdiInqNatts(cdiID, varID, &natts);
 
-  for ( int iatt = 0; iatt < natts; iatt++ )
+  for ( int iatt = 0; iatt < natts; ++iatt )
     {
-      vlistInqAtt(vlistID, varID, iatt, attname, &atttype, &attlen);
+      cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
 
       if ( attlen == 0 ) continue;
 
-      if ( atttype == DATATYPE_TXT )
+      if ( atttype == CDI_DATATYPE_TXT )
         {
           size_t attSize = (size_t)attlen*sizeof(char);
           char *atttxt = (char *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttTxt(vlistID, varID, attname, attlen, atttxt);
+          cdiInqAttTxt(cdiID, varID, attname, attlen, atttxt);
           len = (size_t)attlen;
           cdf_put_att_text(fileID, ncvarID, attname, len, atttxt);
         }
-      else if ( atttype == DATATYPE_INT16 || atttype == DATATYPE_INT32 )
+      else if ( atttype == CDI_DATATYPE_INT8  || atttype == CDI_DATATYPE_UINT8  ||
+                atttype == CDI_DATATYPE_INT16 || atttype == CDI_DATATYPE_UINT16 ||
+                atttype == CDI_DATATYPE_INT32 || atttype == CDI_DATATYPE_UINT32 )
         {
           size_t attSize = (size_t)attlen*sizeof(int);
           int *attint = (int *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttInt(vlistID, varID, attname, attlen, &attint[0]);
+          cdiInqAttInt(cdiID, varID, attname, attlen, &attint[0]);
           len = (size_t)attlen;
-          cdf_put_att_int(fileID, ncvarID, attname, atttype == DATATYPE_INT16 ? NC_SHORT : NC_INT, len, attint);
+          nc_type xtype = (atttype == CDI_DATATYPE_INT8)  ? NC_BYTE :
+                          (atttype == CDI_DATATYPE_INT16) ? NC_SHORT :
+#if  defined  (HAVE_NETCDF4)
+                          (atttype == CDI_DATATYPE_UINT8)  ? NC_UBYTE :
+                          (atttype == CDI_DATATYPE_UINT16) ? NC_USHORT :
+                          (atttype == CDI_DATATYPE_UINT32) ? NC_UINT :
+#endif
+                          NC_INT;
+          cdf_put_att_int(fileID, ncvarID, attname, xtype, len, attint);
         }
-      else if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
+      else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
         {
           size_t attSize = (size_t)attlen * sizeof(double);
           double *attflt = (double *)resizeBuf(&attBuf, &attBufSize, attSize);
-          vlistInqAttFlt(vlistID, varID, attname, attlen, attflt);
+          cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
           len = (size_t)attlen;
-          if ( atttype == DATATYPE_FLT32 )
+          if ( atttype == CDI_DATATYPE_FLT32 )
             {
               float attflt_sp[len];
               for ( size_t i = 0; i < len; ++i ) attflt_sp[i] = (float)attflt[i];
@@ -55122,7 +55216,7 @@ void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
             cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
         }
     }
-  
+
   Free(attBuf);
 }
 
@@ -55138,7 +55232,7 @@ void cdfDefGlobalAtts(stream_t *streamptr)
   cdfDefInstitut(streamptr);
 
   int natts;
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+  cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
 
   if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
 
@@ -55156,7 +55250,7 @@ void cdfDefLocalAtts(stream_t *streamptr)
   int fileID  = streamptr->fileID;
 
   if ( streamptr->localatts ) return;
-  if ( vlistInqInstitut(vlistID) != UNDEFID ) return;
+  if ( vlistInqInstitut(vlistID) != CDI_UNDEFID ) return;
 
   streamptr->localatts = 1;
 
@@ -55165,7 +55259,7 @@ void cdfDefLocalAtts(stream_t *streamptr)
   for ( int varID = 0; varID < streamptr->nvars; varID++ )
     {
       int instID = vlistInqVarInstitut(vlistID, varID);
-      if ( instID != UNDEFID )
+      if ( instID != CDI_UNDEFID )
 	{
           int ncvarid = streamptr->vars[varID].ncvarid;
   	  const char *name = institutInqNamePtr(instID);
@@ -55181,14 +55275,47 @@ void cdfDefLocalAtts(stream_t *streamptr)
 }
 
 static
+void cdf_get_gmapvarname(int gridID, char *gmapvarname)
+{
+  int pgridID = gridID;
+  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+  cdiGridInqKeyStr(pgridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+
+  if ( !mapping[0] )
+    {
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID )
+        {
+          pgridID = projID;
+          cdiGridInqKeyStr(pgridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+        }
+    }
+
+  if ( mapping[0] )
+    cdiGridInqKeyStr(pgridID, CDI_KEY_MAPPING, CDI_MAX_NAME, gmapvarname);
+}
+
+static
+int nc_grid_index(stream_t *streamptr, int gridID)
+{
+  int index = 0;
+  int vlistID = streamptr->vlistID;
+  int ngrids = vlistNgrids(vlistID);
+  for ( index = 0; index < ngrids; ++index )
+    if ( streamptr->ncgrid[index].gridID == gridID ) break;
+
+  assert(index < ngrids);
+
+  return index;
+}
+
+static
 int cdfDefVar(stream_t *streamptr, int varID)
 {
   int ncvarid = -1;
-  int xid = UNDEFID, yid = UNDEFID;
+  int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
   size_t xsize = 0, ysize = 0;
-  char varname[CDI_MAX_NAME];
   int dims[4];
-  int lchunk = FALSE;
   size_t chunks[4] = {0,0,0,0};
   int ndims = 0;
   int tablenum;
@@ -55196,22 +55323,21 @@ int cdfDefVar(stream_t *streamptr, int varID)
   size_t iax = 0;
   char axis[5];
   int ensID, ensCount, forecast_type;
-  int retval;
 
   int fileID  = streamptr->fileID;
 
   if ( CDI_Debug )
     Message("streamID = %d, fileID = %d, varID = %d", streamptr->self, fileID, varID);
 
-  if ( streamptr->vars[varID].ncvarid != UNDEFID )
+  if ( streamptr->vars[varID].ncvarid != CDI_UNDEFID )
     return streamptr->vars[varID].ncvarid;
 
-  int vlistID   = streamptr->vlistID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
-  int code      = vlistInqVarCode(vlistID, varID);
-  int param     = vlistInqVarParam(vlistID, varID);
+  int vlistID  = streamptr->vlistID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  int timetype = vlistInqVarTimetype(vlistID, varID);
+  int code     = vlistInqVarCode(vlistID, varID);
+  int param    = vlistInqVarParam(vlistID, varID);
   int pnum, pcat, pdis;
   cdiDecodeParam(param, &pnum, &pcat, &pdis);
 
@@ -55219,26 +55345,26 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
   vlistInqVarDimorder(vlistID, varID, &dimorder);
 
-  int gridsize  = gridInqSize(gridID);
-  if ( gridsize > 1 ) lchunk = TRUE;
+  size_t gridsize = gridInqSize(gridID);
+  bool lchunk = (gridsize >= 16);
   int gridtype  = gridInqType(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
+  int gridindex = nc_grid_index(streamptr, gridID);
   if ( gridtype != GRID_TRAJECTORY )
     {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
-      if ( xid != UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
-      if ( yid != UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
+      xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
+      if ( xid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, xid, &xsize);
+      if ( yid != CDI_UNDEFID ) cdf_inq_dimlen(fileID, yid, &ysize);
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
-  int zaxis_is_scalar = FALSE;
-  if ( zid == UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID);
+  bool zaxis_is_scalar = false;
+  if ( zid == CDI_UNDEFID ) zaxis_is_scalar = zaxisInqScalar(zaxisID) > 0;
 
-  if ( dimorder[0] != 3 ) lchunk = FALSE; /* ZYX and ZXY */
+  if ( dimorder[0] != 3 ) lchunk = false; /* ZYX and ZXY */
 
-  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=UNDEFID)+(yid!=UNDEFID)+(zid!=UNDEFID)) )
+  if ( ((dimorder[0]>0)+(dimorder[1]>0)+(dimorder[2]>0)) < ((xid!=CDI_UNDEFID)+(yid!=CDI_UNDEFID)+(zid!=CDI_UNDEFID)) )
     {
       printf("zid=%d  yid=%d  xid=%d\n", zid, yid, xid);
       Error("Internal problem, dimension order missing!");
@@ -55246,45 +55372,49 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
   int tid = streamptr->basetime.ncdimid;
 
-  if ( tsteptype != TSTEP_CONSTANT )
+  if ( vlistHasTime(vlistID) && timetype != TIME_CONSTANT )
     {
-      if ( tid == UNDEFID ) Error("Internal problem, time undefined!");
+      if ( tid == CDI_UNDEFID ) Error("Internal problem, time undefined!");
       chunks[ndims] = 1;
       dims[ndims++] = tid;
       axis[iax++] = 'T';
     }
   /*
-  if ( zid != UNDEFID ) axis[iax++] = 'Z';
-  if ( zid != UNDEFID ) chunks[ndims] = 1;
-  if ( zid != UNDEFID ) dims[ndims++] = zid;
+  if ( zid != CDI_UNDEFID ) axis[iax++] = 'Z';
+  if ( zid != CDI_UNDEFID ) chunks[ndims] = 1;
+  if ( zid != CDI_UNDEFID ) dims[ndims++] = zid;
 
-  if ( yid != UNDEFID ) chunks[ndims] = ysize;
-  if ( yid != UNDEFID ) dims[ndims++] = yid;
+  if ( yid != CDI_UNDEFID ) chunks[ndims] = ysize;
+  if ( yid != CDI_UNDEFID ) dims[ndims++] = yid;
 
-  if ( xid != UNDEFID ) chunks[ndims] = xsize;
-  if ( xid != UNDEFID ) dims[ndims++] = xid;
+  if ( xid != CDI_UNDEFID ) chunks[ndims] = xsize;
+  if ( xid != CDI_UNDEFID ) dims[ndims++] = xid;
   */
+  size_t chunk_size_max = 65536;
   for ( int id = 0; id < 3; ++id )
     {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
+      if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
         {
           axis[iax++] = 'Z';
           chunks[ndims] = 1;
           dims[ndims] = zid;
           ndims++;
         }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
+      else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
         {
-          if ( chunktype == CHUNK_LINES )
-            chunks[ndims] = 1;
+          if ( chunktype == CDI_CHUNK_AUTO )
+            chunks[ndims] = (chunk_size_max > gridsize) ? ysize : chunk_size_max/xsize;
           else
-            chunks[ndims] = ysize;
+            chunks[ndims] = (chunktype == CDI_CHUNK_LINES) ? 1 : ysize;
           dims[ndims] = yid;
           ndims++;
         }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
         {
-          chunks[ndims] = xsize;
+          if ( chunktype == CDI_CHUNK_AUTO && yid == CDI_UNDEFID )
+            chunks[ndims] = (chunk_size_max > xsize) ? xsize : chunk_size_max;
+          else
+            chunks[ndims] = xsize;
           dims[ndims] = xid;
           ndims++;
         }
@@ -55293,36 +55423,31 @@ int cdfDefVar(stream_t *streamptr, int varID)
   if ( CDI_Debug )
     fprintf(stderr, "chunktype %d  chunks %d %d %d %d\n", chunktype, (int)chunks[0], (int)chunks[1], (int)chunks[2], (int)chunks[3]);
 
-  int tableID  = vlistInqVarTable(vlistID, varID);
-
-  const char *name     = vlistInqVarNamePtr(vlistID, varID);
-  const char *longname = vlistInqVarLongnamePtr(vlistID, varID);
-  const char *stdname  = vlistInqVarStdnamePtr(vlistID, varID);
-  const char *units    = vlistInqVarUnitsPtr(vlistID, varID);
+  char varname[CDI_MAX_NAME];
+  char name[CDI_MAX_NAME]; name[0] = 0;
+  char longname[CDI_MAX_NAME]; longname[0] = 0;
+  char stdname[CDI_MAX_NAME]; stdname[0] = 0;
+  char units[CDI_MAX_NAME]; units[0] = 0;
+  if ( vlistInqVarNamePtr(vlistID, varID) ) vlistInqVarName(vlistID, varID, name);
+  vlistInqVarLongname(vlistID, varID, longname);
+  vlistInqVarStdname(vlistID, varID, stdname);
+  vlistInqVarUnits(vlistID, varID, units);
 
-  if ( name     == NULL )     name = tableInqParNamePtr(tableID, code);
-  if ( longname == NULL ) longname = tableInqParLongnamePtr(tableID, code);
-  if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
-  if ( name )
+  int tableID  = vlistInqVarTable(vlistID, varID);
+  if ( !name[0] ) tableInqEntry(tableID, code, -1, name, longname, units);
+  if ( name[0] )
     {
-      int checkname;
-      int iz;
-      int status;
-
       sprintf(varname, "%s", name);
 
-      checkname = TRUE;
-      iz = 0;
+      bool checkname = true;
+      int iz = 0;
 
       while ( checkname )
         {
           if ( iz ) sprintf(varname, "%s_%d", name, iz+1);
 
-          status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR )
-            {
-              checkname = FALSE;
-            }
+          int status = nc_inq_varid(fileID, varname, &ncvarid);
+          if ( status != NC_NOERR ) checkname = false;
 
           if ( checkname ) iz++;
 
@@ -55337,7 +55462,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
             Warning("Changed multiple entry of variable name '%s' to '%s'!", name, varname);
         }
 
-      name = varname;
+      strcpy(name, varname);
     }
   else
     {
@@ -55351,7 +55476,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
       char *varname2 = varname+strlen(varname);
 
-      int checkname = TRUE;
+      bool checkname = true;
       int iz = 0;
 
       while ( checkname )
@@ -55359,14 +55484,14 @@ int cdfDefVar(stream_t *streamptr, int varID)
           if ( iz ) sprintf(varname2, "_%d", iz+1);
 
           int status = nc_inq_varid(fileID, varname, &ncvarid);
-          if ( status != NC_NOERR ) checkname = FALSE;
+          if ( status != NC_NOERR ) checkname = false;
 
           if ( checkname ) iz++;
 
           if ( iz >= CDI_MAX_NAME ) break;
         }
 
-      name = varname;
+      strcpy(name, varname);
       code = 0;
       pdis = 255;
     }
@@ -55379,20 +55504,13 @@ int cdfDefVar(stream_t *streamptr, int varID)
   cdf_def_var(fileID, name, (nc_type) xtype, ndims, dims, &ncvarid);
 
 #if  defined  (HAVE_NETCDF4)
-  if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-    {
-      if ( chunktype == CHUNK_AUTO )
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
-      else
-        retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
-
-      if ( retval ) Error("nc_def_var_chunking failed, status = %d", retval);
-    }
+  if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
+    cdf_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
 #endif
 
-  if ( streamptr->comptype == COMPRESS_ZIP )
+  if ( streamptr->comptype == CDI_COMPRESS_ZIP )
     {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
+      if ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
         {
           cdfDefVarDeflate(fileID, ncvarid, streamptr->complevel);
         }
@@ -55400,53 +55518,19 @@ int cdfDefVar(stream_t *streamptr, int varID)
         {
           if ( lchunk )
             {
-              static int lwarn = TRUE;
-
+              static bool lwarn = true;
               if ( lwarn )
                 {
-                  lwarn = FALSE;
+                  lwarn = false;
                   Warning("Deflate compression is only available for NetCDF4!");
                 }
             }
         }
     }
 
-  if ( streamptr->comptype == COMPRESS_SZIP )
-    {
-      if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
-        {
-#if defined (NC_SZIP_NN_OPTION_MASK)
-          cdfDefVarSzip(fileID, ncvarid);
-#else
-          static int lwarn = TRUE;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("NetCDF4/SZIP compression not available!");
-            }
-#endif
-        }
-      else
-        {
-          static int lwarn = TRUE;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("SZIP compression is only available for NetCDF4!");
-            }
-        }
-    }
-
-  if ( stdname && *stdname )
-    cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
-
-  if ( longname && *longname )
-    cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
-
-  if ( units && *units )
-    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
+  if ( *stdname )  cdf_put_att_text(fileID, ncvarid, "standard_name", strlen(stdname), stdname);
+  if ( *longname ) cdf_put_att_text(fileID, ncvarid, "long_name", strlen(longname), longname);
+  if ( *units )    cdf_put_att_text(fileID, ncvarid, "units", strlen(units), units);
 
   if ( code > 0 && pdis == 255 )
     cdf_put_att_int(fileID, ncvarid, "code", NC_INT, 1, &code);
@@ -55458,17 +55542,16 @@ int cdfDefVar(stream_t *streamptr, int varID)
       cdf_put_att_text(fileID, ncvarid, "param", strlen(paramstr), paramstr);
     }
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       tablenum = tableInqNum(tableID);
       if ( tablenum > 0 )
         cdf_put_att_int(fileID, ncvarid, "table", NC_INT, 1, &tablenum);
     }
 
-  char coordinates[CDI_MAX_NAME];
-  coordinates[0] = 0;
+  char coordinates[CDI_MAX_NAME]; coordinates[0] = 0;
 
-  if ( zaxis_is_scalar )
+  if ( zaxis_is_scalar || zaxisInqType(zaxisID) == ZAXIS_CHAR )
     {
       int nczvarID = streamptr->nczvarID[zaxisindex];
       if ( nczvarID != CDI_UNDEFID )
@@ -55479,42 +55562,28 @@ int cdfDefVar(stream_t *streamptr, int varID)
         }
     }
 
-  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
+  if ( gridtype != GRID_GENERIC && gridtype != GRID_LONLAT && gridtype != GRID_GAUSSIAN &&
+       gridtype != GRID_PROJECTION && gridtype != GRID_CURVILINEAR && gridtype != GRID_CHARXY )
     {
       size_t len = strlen(gridNamePtr(gridtype));
       if ( len > 0 )
-        cdf_put_att_text(fileID, ncvarid, "grid_type", len, gridNamePtr(gridtype));
+        cdf_put_att_text(fileID, ncvarid, "CDI_grid_type", len, gridNamePtr(gridtype));
     }
 
-  if ( gridIsRotated(gridID) )
-    {
-      char mapping[] = "rotated_pole";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
+  char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
 
-  if ( gridtype == GRID_SINUSOIDAL )
-    {
-      char mapping[] = "sinusoidal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_LAEA )
-    {
-      char mapping[] = "laea";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_LCC2 )
-    {
-      char mapping[] = "Lambert_Conformal";
-      cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(mapping), mapping);
-    }
-  else if ( gridtype == GRID_TRAJECTORY )
+  cdf_get_gmapvarname(gridID, gmapvarname);
+
+  if ( gmapvarname[0] ) cdf_put_att_text(fileID, ncvarid, "grid_mapping", strlen(gmapvarname), gmapvarname);
+
+  if ( gridtype == GRID_TRAJECTORY )
     {
-      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "tlon tlat" );
+      cdf_put_att_text(fileID, ncvarid, "coordinates", 9, "lon lat" );
     }
-  else if ( gridtype == GRID_LONLAT && xid == UNDEFID && yid == UNDEFID && gridsize == 1 )
+  else if ( gridtype == GRID_LONLAT && xid == CDI_UNDEFID && yid == CDI_UNDEFID && gridsize == 1 )
     {
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
+      int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
+      int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
       if ( ncyvarID != CDI_UNDEFID )
         {
           size_t len = strlen(coordinates);
@@ -55531,20 +55600,39 @@ int cdfDefVar(stream_t *streamptr, int varID)
   else if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
     {
       char cellarea[CDI_MAX_NAME] = "area: ";
-      int ncxvarID = streamptr->ncxvarID[gridindex];
-      int ncyvarID = streamptr->ncyvarID[gridindex];
-      int ncavarID = streamptr->ncavarID[gridindex];
-      if ( ncyvarID != CDI_UNDEFID )
+      int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
+      int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
+      int ncavarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_A];
+      // CMOR order: coordinates = "lat lon"
+      if ( cdiCoordinatesLonLat )
         {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+          if ( ncxvarID != CDI_UNDEFID )
+            {
+              size_t len = strlen(coordinates);
+              if ( len ) coordinates[len++] = ' ';
+              cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+            }
+          if ( ncyvarID != CDI_UNDEFID )
+            {
+              size_t len = strlen(coordinates);
+              if ( len ) coordinates[len++] = ' ';
+              cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+            }
         }
-      if ( ncxvarID != CDI_UNDEFID )
+      else
         {
-          size_t len = strlen(coordinates);
-          if ( len ) coordinates[len++] = ' ';
-          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+          if ( ncyvarID != CDI_UNDEFID )
+            {
+              size_t len = strlen(coordinates);
+              if ( len ) coordinates[len++] = ' ';
+              cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+            }
+          if ( ncxvarID != CDI_UNDEFID )
+            {
+              size_t len = strlen(coordinates);
+              if ( len ) coordinates[len++] = ' ';
+              cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+            }
         }
 
       if ( ncavarID != CDI_UNDEFID )
@@ -55570,20 +55658,35 @@ int cdfDefVar(stream_t *streamptr, int varID)
       cdf_put_att_text(fileID, ncvarid, "axis", iax, axis);
       cdf_put_att_int(fileID, ncvarid, "truncation", NC_INT, 1, &gridTruncation);
     }
+  else if ( gridtype == GRID_CHARXY )
+    {
+      if ( gridInqXIsc(gridID) )
+        {
+          int ncxvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncxvarID, coordinates+len);
+        }
+      else if ( gridInqYIsc(gridID) )
+        {
+          int ncyvarID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
+          size_t len = strlen(coordinates);
+          if ( len ) coordinates[len++] = ' ';
+          cdf_inq_varname(fileID, ncyvarID, coordinates+len);
+        }
+    }
 
   size_t len = strlen(coordinates);
   if ( len ) cdf_put_att_text(fileID, ncvarid, "coordinates", len, coordinates);
 
   /*  if ( xtype == NC_BYTE || xtype == NC_SHORT || xtype == NC_INT ) */
     {
-      int laddoffset, lscalefactor;
-      double addoffset, scalefactor;
       int astype = NC_DOUBLE;
 
-      addoffset    = vlistInqVarAddoffset(vlistID, varID);
-      scalefactor  = vlistInqVarScalefactor(vlistID, varID);
-      laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-      lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+      double addoffset   = vlistInqVarAddoffset(vlistID, varID);
+      double scalefactor = vlistInqVarScalefactor(vlistID, varID);
+      bool laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+      bool lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
 
       if ( laddoffset || lscalefactor )
         {
@@ -55600,7 +55703,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
         }
     }
 
-  if ( dtype == DATATYPE_UINT8 && xtype == NC_BYTE )
+  if ( dtype == CDI_DATATYPE_UINT8 && xtype == NC_BYTE )
     {
       int validrange[2] = {0, 255};
       cdf_put_att_int(fileID, ncvarid, "valid_range", NC_SHORT, 2, validrange);
@@ -55639,14 +55742,6 @@ int cdfDefVar(stream_t *streamptr, int varID)
 	cdf_put_att_int(fileID, ncvarid, "realization", NC_INT, 1, &ensID);
 	cdf_put_att_int(fileID, ncvarid, "ensemble_members", NC_INT, 1, &ensCount);
 	cdf_put_att_int(fileID, ncvarid, "forecast_init_type", NC_INT, 1, &forecast_type);
-
-#ifdef DBG
-	if( DBG )
-	  {
-	    fprintf( stderr, "cdfDefVar :\n EnsID  %d\n Enscount %d\n Forecast init type %d\n",  ensID,
-		     ensCount,  forecast_type );
-	  }
-#endif
     }
 
   /* Attributes */
@@ -55687,25 +55782,23 @@ void cdfEndDef(stream_t *streamptr)
 static
 void cdfWriteGridTraj(stream_t *streamptr, int gridID)
 {
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex];
-  int latID = streamptr->ydimID[gridindex];
+  int gridindex = nc_grid_index(streamptr, gridID);
+  int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+  int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
 
   double xlon = gridInqXval(gridID, 0);
   double xlat = gridInqYval(gridID, 0);
   int tsID = streamptr->curTsID;
   size_t index = (size_t)tsID;
 
+  int fileID = streamptr->fileID;
   cdf_put_var1_double(fileID, lonID, &index, &xlon);
   cdf_put_var1_double(fileID, latID, &index, &xlat);
 }
 
 static
 void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dtype, size_t nvals, size_t xsize, size_t ysize,
-                        int swapxy, size_t *start, size_t *count, int memtype, const void *data, int nmiss)
+                        bool swapxy, size_t *start, size_t *count, int memtype, const void *data, size_t nmiss)
 {
   const double *pdata_dp = (const double *) data;
   double *mdata_dp = NULL;
@@ -55714,7 +55807,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
   float *mdata_sp = NULL;
   float *sdata_sp = NULL;
 
-  /*  if ( dtype == DATATYPE_INT8 || dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 ) */
+  /*  if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 ) */
     {
       double missval      = vlistInqVarMissval(vlistID, varID);
       double addoffset    = vlistInqVarAddoffset(vlistID, varID);
@@ -55782,8 +55875,8 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
             }
         }
 
-      if ( dtype == DATATYPE_UINT8 || dtype == DATATYPE_INT8 ||
-           dtype == DATATYPE_INT16 || dtype == DATATYPE_INT32 )
+      if ( dtype == CDI_DATATYPE_UINT8 || dtype == CDI_DATATYPE_INT8 ||
+           dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
         {
           if ( memtype == MEMTYPE_FLOAT )
             {
@@ -55796,7 +55889,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
 
               for ( size_t i = 0; i < nvals; i++ ) mdata_sp[i] = roundf(mdata_sp[i]);
 
-              if ( dtype == DATATYPE_UINT8 )
+              if ( dtype == CDI_DATATYPE_UINT8 )
                 {
                   nc_type xtype;
                   cdf_inq_vartype(fileID, ncvarid, &xtype);
@@ -55818,7 +55911,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
 
               for ( size_t i = 0; i < nvals; i++ ) mdata_dp[i] = round(mdata_dp[i]);
 
-              if ( dtype == DATATYPE_UINT8 )
+              if ( dtype == CDI_DATATYPE_UINT8 )
                 {
                   nc_type xtype;
                   cdf_inq_vartype(fileID, ncvarid, &xtype);
@@ -55833,9 +55926,8 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
 
       if ( CDF_Debug && memtype != MEMTYPE_FLOAT )
         {
-          double fmin, fmax;
-          fmin =  1.0e200;
-          fmax = -1.0e200;
+          double fmin =  1.0e200;
+          double fmax = -1.0e200;
           for ( size_t i = 0; i < nvals; ++i )
             {
               if ( !DBL_IS_EQUAL(pdata_dp[i], missval) )
@@ -55849,7 +55941,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
         }
     }
 
-  if ( swapxy ) // implemented only for cdf_write_var_slice() 
+  if ( swapxy ) // implemented only for cdf_write_var_slice()
     {
       size_t gridsize = xsize*ysize;
       if ( memtype == MEMTYPE_FLOAT )
@@ -55882,7 +55974,7 @@ void cdf_write_var_data(int fileID, int vlistID, int varID, int ncvarid, int dty
 }
 
 
-void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
@@ -55890,9 +55982,8 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
   size_t size;
   size_t start[5];
   size_t count[5];
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
+  bool swapxy = false;
+  size_t ndims = 0;
 
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -55902,44 +55993,42 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
   long ntsteps = streamptr->ntsteps;
   if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
 
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
   int ncvarid = cdfDefVar(streamptr, varID);
 
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  int timetype = vlistInqVarTimetype(vlistID, varID);
 
-  int xid = UNDEFID, yid = UNDEFID;
+  int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
   if ( gridInqType(gridID) == GRID_TRAJECTORY )
     {
       cdfWriteGridTraj(streamptr, gridID);
     }
   else
     {
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
+      int gridindex = nc_grid_index(streamptr, gridID);
+      xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
 
-  if ( tsteptype != TSTEP_CONSTANT )
+  if ( timetype != TIME_CONSTANT )
     {
       start[ndims] = (size_t)ntsteps - 1;
       count[ndims] = 1;
       ndims++;
     }
 
-  if ( zid != UNDEFID )
+  if ( zid != CDI_UNDEFID )
     {
       start[ndims] = 0;
       count[ndims] = (size_t)zaxisInqSize(zaxisID);
       ndims++;
     }
 
-  if ( yid != UNDEFID )
+  if ( yid != CDI_UNDEFID )
     {
       start[ndims] = 0;
       cdf_inq_dimlen(fileID, yid, &size);
@@ -55948,7 +56037,7 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
       ndims++;
     }
 
-  if ( xid != UNDEFID )
+  if ( xid != CDI_UNDEFID )
     {
       start[ndims] = 0;
       cdf_inq_dimlen(fileID, xid, &size);
@@ -55958,7 +56047,7 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
     }
 
   if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
+    for (size_t idim = 0; idim < ndims; idim++)
       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
 
   if ( streamptr->ncmode == 1 )
@@ -55971,24 +56060,23 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+  size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
 void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                         const int rect[][2], const void *data, int nmiss)
+                         const int rect[][2], const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
-  int xid = UNDEFID, yid = UNDEFID;
+  int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
   size_t xsize = 0, ysize = 0;
   size_t start[5];
   size_t count[5];
-  int swapxy = FALSE;
-  int ndims = 0;
-  int idim;
+  bool swapxy = false;
+  size_t ndims = 0;
   int streamID = streamptr->self;
 
   if ( CDI_Debug )
@@ -55998,16 +56086,13 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
   int fileID  = streamInqFileID(streamID);
 
   long ntsteps = streamptr->ntsteps;
-  if ( CDI_Debug )
-    Message("ntsteps = %ld", ntsteps);
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+  if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
 
   int ncvarid = cdfDefVar(streamptr, varID);
 
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  int timetype = vlistInqVarTimetype(vlistID, varID);
 
   if ( gridInqType(gridID) == GRID_TRAJECTORY )
     {
@@ -56015,21 +56100,21 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
     }
   else
     {
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
+      int gridindex = nc_grid_index(streamptr, gridID);
+      xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
 
-  if ( tsteptype != TSTEP_CONSTANT )
+  if ( timetype != TIME_CONSTANT )
     {
       start[ndims] = (size_t)ntsteps - 1;
       count[ndims] = 1;
       ndims++;
     }
-  if ( zid != UNDEFID )
+  if ( zid != CDI_UNDEFID )
     {
       int size = zaxisInqSize(zaxisID);
       xassert(rect[2][0] >= 0 && rect[2][0] <= rect[2][1]
@@ -56038,7 +56123,7 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
       count[ndims] = (size_t)rect[2][1] - (size_t)rect[2][0] + 1;
       ndims++;
     }
-  if ( yid != UNDEFID )
+  if ( yid != CDI_UNDEFID )
     {
       size_t size;
       cdf_inq_dimlen(fileID, yid, &size);
@@ -56048,7 +56133,7 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
       count[ndims] = (size_t)rect[1][1] - (size_t)rect[1][0] + 1;
       ndims++;
     }
-  if ( xid != UNDEFID )
+  if ( xid != CDI_UNDEFID )
     {
       size_t size;
       cdf_inq_dimlen(fileID, xid, &size);
@@ -56060,7 +56145,7 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
     }
 
   if ( CDI_Debug )
-    for (idim = 0; idim < ndims; idim++)
+    for (size_t idim = 0; idim < ndims; idim++)
       Message("dim = %d  start = %d  count = %d", idim, start[idim], count[idim]);
 
   if ( streamptr->ncmode == 1 )
@@ -56073,14 +56158,14 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID)) * (size_t)(zaxisInqSize(zaxisID));
+  size_t nvals = gridInqSize(gridID) * (size_t)(zaxisInqSize(zaxisID));
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals,
                      xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
-void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
   if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
 
@@ -56088,7 +56173,7 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   size_t start[5];
   size_t count[5];
   int dimorder[3];
-  int xid = UNDEFID, yid = UNDEFID;
+  int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
 
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -56098,13 +56183,11 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   long ntsteps = streamptr->ntsteps;
   if ( CDI_Debug ) Message("ntsteps = %ld", ntsteps);
 
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
   int ncvarid = cdfDefVar(streamptr, varID);
 
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+  int timetype = vlistInqVarTimetype(vlistID, varID);
   vlistInqVarDimorder(vlistID, varID, &dimorder);
 
   if ( gridInqType(gridID) == GRID_TRAJECTORY )
@@ -56113,18 +56196,18 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
     }
   else
     {
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
+      int gridindex = nc_grid_index(streamptr, gridID);
+      xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
 
-  int swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != UNDEFID && yid != UNDEFID;
+  bool swapxy = (dimorder[2] == 2 || dimorder[0] == 1) && xid != CDI_UNDEFID && yid != CDI_UNDEFID;
 
   size_t ndims = 0;
-  if ( tsteptype != TSTEP_CONSTANT )
+  if ( timetype != TIME_CONSTANT )
     {
       start[ndims] = (size_t)ntsteps - 1;
       count[ndims] = 1;
@@ -56133,20 +56216,20 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 
   for ( int id = 0; id < 3; ++id )
     {
-      if ( dimorder[id] == 3 && zid != UNDEFID )
+      if ( dimorder[id] == 3 && zid != CDI_UNDEFID )
         {
           start[ndims] = (size_t)levelID;
           count[ndims] = 1;
           ndims++;
         }
-      else if ( dimorder[id] == 2 && yid != UNDEFID )
+      else if ( dimorder[id] == 2 && yid != CDI_UNDEFID )
         {
           start[ndims] = 0;
           cdf_inq_dimlen(fileID, yid, &ysize);
           count[ndims] = ysize;
           ndims++;
         }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
         {
           start[ndims] = 0;
           cdf_inq_dimlen(fileID, xid, &xsize);
@@ -56163,13 +56246,13 @@ void cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 
   if ( nmiss > 0 ) cdfDefVarMissval(streamptr, varID, dtype, 1);
 
-  size_t nvals = (size_t)(gridInqSize(gridID));
+  size_t nvals = gridInqSize(gridID);
 
   cdf_write_var_data(fileID, vlistID, varID, ncvarid, dtype, nvals, xsize, ysize, swapxy, start, count, memtype, data, nmiss);
 }
 
 
-void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+void cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
 {
   int varID   = streamptr->record->varID;
   int levelID = streamptr->record->levelID;
@@ -56178,6 +56261,16 @@ void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nm
 }
 
 #endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
 #ifdef HAVE_CONFIG_H
 #endif
 
@@ -56188,10 +56281,6 @@ void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nm
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-
 static
 void cdfReadGridTraj(stream_t *streamptr, int gridID)
 {
@@ -56199,8 +56288,8 @@ void cdfReadGridTraj(stream_t *streamptr, int gridID)
   int fileID  = streamptr->fileID;
 
   int gridindex = vlistGridIndex(vlistID, gridID);
-  int lonID = streamptr->xdimID[gridindex];
-  int latID = streamptr->ydimID[gridindex];
+  int lonID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_X];
+  int latID = streamptr->ncgrid[gridindex].ncIDs[CDF_VARID_Y];
 
   int tsID = streamptr->curTsID;
   size_t index = (size_t)tsID;
@@ -56218,22 +56307,22 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
 {
   int vlistID = streamptr->vlistID;
   int tsID = streamptr->curTsID;
-  int gridID    = vlistInqVarGrid(vlistID, varID);
-  int zaxisID   = vlistInqVarZaxis(vlistID, varID);
-  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
+  int gridID = vlistInqVarGrid(vlistID, varID);
+  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+  int timetype = vlistInqVarTimetype(vlistID, varID);
   int gridindex = vlistGridIndex(vlistID, gridID);
 
   if ( CDI_Debug ) Message("tsID = %d", tsID);
 
-  int xid = UNDEFID, yid = UNDEFID;
+  int xid = CDI_UNDEFID, yid = CDI_UNDEFID;
   if ( gridInqType(gridID) == GRID_TRAJECTORY )
     {
       cdfReadGridTraj(streamptr, gridID);
     }
   else
     {
-      xid = streamptr->xdimID[gridindex];
-      yid = streamptr->ydimID[gridindex];
+      xid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+      yid = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
     }
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
@@ -56245,10 +56334,10 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
       (*count)[ndims] = length; \
       ndims++; \
     } while(0)
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
-  if ( zid != UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
-  if ( yid != UNDEFID ) addDimension(0, (size_t)gridInqYsize(gridID));
-  if ( xid != UNDEFID ) addDimension(0, (size_t)gridInqXsize(gridID));
+  if ( timetype != TIME_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( zid != CDI_UNDEFID ) addDimension(0, (size_t)zaxisInqSize(zaxisID));
+  if ( yid != CDI_UNDEFID ) addDimension(0, gridInqYsize(gridID));
+  if ( xid != CDI_UNDEFID ) addDimension(0, gridInqXsize(gridID));
 #undef addDimension
 
   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
@@ -56486,18 +56575,12 @@ void transpose2dArrayDP(size_t inWidth, size_t inHeight, double *data)
   */
 
   for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
-    {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
-            {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
-                {
-                  out[x][y] = temp[y][x];
-                }
-            }
-        }
-    }
+    for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+      for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+        for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+          {
+            out[x][y] = temp[y][x];
+          }
 
   Free(temp[0]);
 }
@@ -56527,18 +56610,12 @@ void transpose2dArraySP(size_t inWidth, size_t inHeight, float *data)
   */
 
   for ( size_t yBlock = 0; yBlock < inHeight; yBlock += cacheBlockSize )
-    {
-      for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
-        {
-          for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
-            {
-              for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
-                {
-                  out[x][y] = temp[y][x];
-                }
-            }
-        }
-    }
+    for ( size_t xBlock = 0; xBlock < inWidth; xBlock += cacheBlockSize )
+      for ( size_t y = yBlock, yEnd = min_size(yBlock + cacheBlockSize, inHeight); y < yEnd; y++ )
+        for ( size_t x = xBlock, xEnd = min_size(xBlock + cacheBlockSize, inWidth); x < xEnd; x++ )
+          {
+            out[x][y] = temp[y][x];
+          }
 
   Free(temp);
 }
@@ -56549,7 +56626,7 @@ void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
   int gridId = vlistInqVarGrid(streamptr->vlistID, varId);
   int gridindex = vlistGridIndex(streamptr->vlistID, gridId);
 
-  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = UNDEFID;
+  (*outDimIds)[0] = (*outDimIds)[1] = (*outDimIds)[2] = CDI_UNDEFID;
   switch ( gridInqType(gridId) )
     {
       case GRID_TRAJECTORY:
@@ -56557,12 +56634,12 @@ void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
         break;
 
       case GRID_UNSTRUCTURED:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
+        (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
         break;
 
       default:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        (*outDimIds)[1] = streamptr->ydimID[gridindex];
+        (*outDimIds)[0] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X];
+        (*outDimIds)[1] = streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_Y];
         break;
     }
 
@@ -56574,8 +56651,8 @@ void cdfInqDimIds(stream_t *streamptr, int varId, int (*outDimIds)[3])
 static
 int cdfGetSkipDim(int fileId, int ncvarid, int (*dimIds)[3])
 {
-  if((*dimIds)[0] != UNDEFID) return 0;
-  if((*dimIds)[1] != UNDEFID) return 0;
+  if((*dimIds)[0] != CDI_UNDEFID) return 0;
+  if((*dimIds)[1] != CDI_UNDEFID) return 0;
   int nvdims;
   cdf_inq_varndims(fileId, ncvarid, &nvdims);
   if(nvdims != 3) return 0;
@@ -56607,8 +56684,8 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
   int ncvarid = streamptr->vars[varId].ncvarid;
 
   int gridId = vlistInqVarGrid(vlistId, varId);
-  int tsteptype = vlistInqVarTsteptype(vlistId, varId);
-  int gridsize = gridInqSize(gridId);
+  int timetype = vlistInqVarTimetype(vlistId, varId);
+  size_t gridsize = gridInqSize(gridId);
 
   streamptr->numvals += gridsize;
 
@@ -56620,7 +56697,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
   int dimorder[3];
   vlistInqVarDimorder(vlistId, varId, &dimorder);
 
-  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != UNDEFID && dimIds[1] != UNDEFID ;
+  *outSwapXY = (dimorder[2] == 2 || dimorder[0] == 1) && dimIds[0] != CDI_UNDEFID && dimIds[1] != CDI_UNDEFID ;
 
   int ndims = 0;
 
@@ -56630,17 +56707,16 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
       ndims++; \
   } while(0)
 
-  if ( tsteptype != TSTEP_CONSTANT ) addDimension((size_t)tsID, 1);
+  if ( timetype != TIME_CONSTANT ) addDimension((size_t)tsID, 1);
   if ( skipdim == 1 ) addDimension(0, 1);
 
   for ( int id = 0; id < 3; ++id )
     {
       size_t size;
       int curDimId = dimIds[dimorder[id]-1];
-      if ( curDimId == UNDEFID ) continue;
+      if ( curDimId == CDI_UNDEFID ) continue;
       switch ( dimorder[id] )
         {
-          Error("Internal errror: Malformed dimension order encountered. Please report this bug.\n");
           case 1:
           case 2:
             cdf_inq_dimlen(fileId, curDimId, &size);
@@ -56675,7 +56751,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
 }
 
 static
-void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void cdfReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -56693,7 +56769,7 @@ void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 
   cdf_get_vara_double(fileID, ncvarid, start, count, data);
 
-  size_t size = (size_t)gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
+  size_t size = gridInqSize(gridID)*(size_t)zaxisInqSize(zaxisID);
   double missval = vlistInqVarMissval(vlistID, varID);
   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
@@ -56707,7 +56783,7 @@ void cdfReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
 }
 
 static
-void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
+void cdfReadVarSP(stream_t *streamptr, int varID, float *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
@@ -56725,7 +56801,7 @@ void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
 
   cdf_get_vara_float(fileID, ncvarid, start, count, data);
 
-  size_t size = (size_t)gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
+  size_t size = gridInqSize(gridID) * (size_t)zaxisInqSize(zaxisID);
   double missval = vlistInqVarMissval(vlistID, varID);
   const bool haveMissVal = vlistInqVarMissvalUsed(vlistID, varID);
   double validRange[2];
@@ -56739,7 +56815,7 @@ void cdfReadVarSP(stream_t *streamptr, int varID, float *data, int *nmiss)
 }
 
 
-void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss)
+void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss)
 {
   if ( memtype == MEMTYPE_DOUBLE )
     cdfReadVarDP(streamptr, varID, (double*) data, nmiss);
@@ -56748,7 +56824,7 @@ void cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *
 }
 
 static
-void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, int *nmiss)
+void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
@@ -56762,11 +56838,11 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
 
   int ncvarid = streamptr->vars[varID].ncvarid;
   int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
+  size_t gridsize = gridInqSize(gridId);
+  size_t xsize = gridInqXsize(gridId);
+  size_t ysize = gridInqYsize(gridId);
 
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
+  if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_FLT32 )
     {
       float *data_fp = (float *) Malloc(gridsize*sizeof(*data_fp));
       cdf_get_vara_float(fileID, ncvarid, start, count, data_fp);
@@ -56778,7 +56854,7 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
     {
       cdf_get_vara_double(fileID, ncvarid, start, count, data);
       
-      if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+      if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_UINT8 )
         {
           nc_type xtype;
           cdf_inq_vartype(fileID, ncvarid, &xtype);
@@ -56805,7 +56881,7 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
 }
 
 static
-void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, int *nmiss)
+void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data, size_t *nmiss)
 {
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
@@ -56819,11 +56895,11 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
 
   int ncvarid = streamptr->vars[varID].ncvarid;
   int gridId = vlistInqVarGrid(vlistID, varID);
-  size_t gridsize = (size_t)gridInqSize(gridId);
-  size_t xsize = (size_t)gridInqXsize(gridId);
-  size_t ysize = (size_t)gridInqYsize(gridId);
+  size_t gridsize = gridInqSize(gridId);
+  size_t xsize = gridInqXsize(gridId);
+  size_t ysize = gridInqYsize(gridId);
 
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT64 )
+  if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_FLT64 )
     {
       double *data_dp = (double *) Malloc(gridsize*sizeof(*data_dp));
       cdf_get_vara_double(fileID, ncvarid, start, count, data_dp);
@@ -56835,7 +56911,7 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
     {
       cdf_get_vara_float(fileID, ncvarid, start, count, data);
 
-      if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+      if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_UINT8 )
         {
           nc_type xtype;
           cdf_inq_vartype(fileID, ncvarid, &xtype);
@@ -56862,7 +56938,7 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
 }
 
 
-void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
 {
   if ( memtype == MEMTYPE_DOUBLE )
     cdfReadVarSliceDP(streamptr, varID, levelID, (double*) data, nmiss);
@@ -56871,7 +56947,7 @@ void cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
 }
 
 
-void cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss)
+void cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d", streamptr->self);
 
@@ -57825,8 +57901,8 @@ void swap8byte(void *ptr, size_t size)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _TABLEPAR_H
-#define _TABLEPAR_H
+#ifndef TABLEPAR_H
+#define TABLEPAR_H
 
 enum {
   TABLE_DUP_NAME = 1 << 0,
@@ -57836,18 +57912,21 @@ enum {
 
 typedef struct
 {
-  int   id;	     /* Parameter number (GRIB) */
-  int dupflags;      /* keep track of which attributes got strdup'ed */
-  const char *name;	     /* Parameter name */
-  const char *longname;    /* Parameter long name */
-  const char *units;	     /* Parameter units */
+  int id;	        // Parameter number (GRIB)
+  int ltype;	        // Level type (GRIB)
+  int dupflags;         // keep track of which attributes got strdup'ed
+  const char *name;	// Parameter name
+  const char *longname; // Parameter long name
+  const char *units;	// Parameter units
 }
-PAR;
+param_type;
 
 
-static void tableLink(int tableID, const PAR *pars, int npars);
+static void tableLink(int tableID, const param_type *pars, int npars);
 int tableDef(int modelID, int tablegribID, const char *tablename);
 
+int tableInqParCode(int tableID, char *name, int *code);
+
 #endif
 /*
  * Local Variables:
@@ -57859,1432 +57938,1418 @@ int tableDef(int modelID, int tablegribID, const char *tablename);
  * End:
  */
 /* Automatically generated, do not edit! */
-#ifndef _TABLE_H
-#define _TABLE_H
-
-static const PAR echam4[] = {
-  {   4, 0, "precip",      "total precipitation",                      "m/s"      },
-  {  34, 0, "low_cld",     "low cloud",                                 NULL      },
-  {  35, 0, "mid_cld",     "mid cloud",                                 NULL      },
-  {  36, 0, "hih_cld",     "high cloud",                                NULL      },
-  { 129, 0, "geosp",       "surface geopotential (orography)",         "m^2/s^2"  },
-  { 130, 0, "t",           "temperature",                              "K"        },
-  { 131, 0, "u",           "u-velocity",                               "m/s"      },
-  { 132, 0, "v",           "v-velocity",                               "m/s"      },
-  { 133, 0, "sq",          "specific humidity",                        "kg/kg"    },
-  { 134, 0, "aps",         "Surface pressure",                         "Pa"       },
-  { 135, 0, "omega",       "vertical velocity",                        "Pa/s"     },
-  { 138, 0, "svo",         "vorticity",                                "1/s"      },
-  { 139, 0, "ts",          "surface temperature",                      "K"        },
-  { 140, 0, "ws",          "soil wetness",                             "m"        },
-  { 141, 0, "sn",          "snow depth",                               "m"        },
-  { 142, 0, "aprl",        "large scale precipitation",                "m/s"      },
-  { 143, 0, "aprc",        "convective  precipitation",                "m/s"      },
-  { 144, 0, "aprs",        "snow fall",                                "m/s"      },
-  { 145, 0, "vdis",        "boundary layer dissipation",               "W/m^2"    },
-  { 146, 0, "ahfs",        "surface sensible heat flux",               "W/m^2"    },
-  { 147, 0, "ahfl",        "surface latent heat flux",                 "W/m^2"    },
-  { 148, 0, "stream",      "streamfunction",                           "m^2/s"    },
-  { 149, 0, "velopot",     "velocity potential",                       "m^2/s"    },
-  { 151, 0, "slp",         "mean sea level pressure",                  "Pa"       },
-  { 152, 0, "lsp",         "log surface pressure",                      NULL      },
-  { 153, 0, "sx",          "liquid water content",                     "kg/kg"    },
-  { 155, 0, "sd",          "divergence",                               "1/s"      },
-  { 156, 0, "geopoth",     "geopotential height",                      "m"        },
-  { 157, 0, "rhumidity",   "relative humidity",                        "fraction" },
-  { 158, 0, "var158",      "tendency of surface pressure",             "Pa/s"     },
-  { 159, 0, "ustar3",      "ustar3",                                   "m^3/s^3"  },
-  { 160, 0, "runoff",      "surface runoff",                           "m/s"      },
-  { 161, 0, "alwc",        "liquid water content",                     "kg/kg"    },
-  { 162, 0, "aclc",        "cloud cover",                              "fraction" },
-  { 163, 0, "aclcv",       "total cloud cover",                        "fraction" },
-  { 164, 0, "aclcov",      "total cloud cover",                        "fraction" },
-  { 165, 0, "u10",         "10m u-velocity",                           "m/s"      },
-  { 166, 0, "v10",         "10m v-velocity",                           "m/s"      },
-  { 167, 0, "temp2",       "2m temperature",                           "K"        },
-  { 168, 0, "dew2",        "2m dew point temperature",                 "K"        },
-  { 169, 0, "tsurf",       "surface temperature",                      "K"        },
-  { 170, 0, "td",          "deep soil temperature",                    "K"        },
-  { 171, 0, "wind10",      "10m windspeed",                            "m/s"      },
-  { 172, 0, "slm",         "land sea mask",                            "fraction" },
-  { 173, 0, "az0",         "surface roughness length",                 "m"        },
-  { 174, 0, "alb",         "surface background albedo",                "fraction" },
-  { 175, 0, "albedo",      "surface albedo",                           "fraction" },
-  { 176, 0, "srads",       "net surface solar radiation",              "W/m^2"    },
-  { 177, 0, "trads",       "net surface thermal radiation",            "W/m^2"    },
-  { 178, 0, "srad0",       "net top solar radiation",                  "W/m^2"    },
-  { 179, 0, "trad0",       "top thermal radiation (OLR)",              "W/m^2"    },
-  { 180, 0, "ustr",        "surface u-stress",                         "Pa"       },
-  { 181, 0, "vstr",        "surface v-stress",                         "Pa"       },
-  { 182, 0, "evap",        "surface evaporation",                      "m/s"      },
-  { 183, 0, "tdcl",        "soil temperature",                         "K"        },
-  { 185, 0, "srafs",       "net surf. solar radiation   (clear sky)",  "W/m^2"    },
-  { 186, 0, "trafs",       "net surf. thermal radiation (clear sky)",  "W/m^2"    },
-  { 187, 0, "sraf0",       "net top solar radiation     (clear sky)",  "W/m^2"    },
-  { 188, 0, "traf0",       "net top thermal radiation   (clear sky)",  "W/m^2"    },
-  { 189, 0, "sclfs",       "surface solar cloud forcing",              "W/m^2"    },
-  { 190, 0, "tclfs",       "surface thermal cloud forcing",            "W/m^2"    },
-  { 191, 0, "sclf0",       "top solar cloud forcing",                  "W/m^2"    },
-  { 192, 0, "tclf0",       "top thermal cloud forcing",                "W/m^2"    },
-  { 193, 0, "wl",          "skin reservoir content",                   "m"        },
-  { 194, 0, "wlm1",        "skin reservoir content of plants",         "m"        },
-  { 195, 0, "ustrgw",      "u-gravity wave stress",                    "Pa"       },
-  { 196, 0, "vstrgw",      "v-gravity wave stress",                    "Pa"       },
-  { 197, 0, "vdisgw",      "gravity wave dissipation",                 "W/m^2"    },
-  { 198, 0, "vgrat",       "vegetation ratio",                         "fraction" },
-  { 199, 0, "varor",       "orographic variance",                      "m^2"      },
-  { 200, 0, "vlt",         "leaf area index",                           NULL      },
-  { 201, 0, "t2max",       "maximum 2m-temperature",                   "K"        },
-  { 202, 0, "t2min",       "minimum 2m-temperature",                   "K"        },
-  { 203, 0, "srad0u",      "top solar radiation upward",               "W/m^2"    },
-  { 204, 0, "sradsu",      "surface solar radiation upward",           "W/m^2"    },
-  { 205, 0, "tradsu",      "surface thermal radiation upward",         "W/m^2"    },
-  { 206, 0, "tsn",         "snow temperature",                         "K"        },
-  { 207, 0, "td3",         "soil temperature 3",                       "K"        },
-  { 208, 0, "td4",         "soil temperature 4",                       "K"        },
-  { 209, 0, "td5",         "soil temperature 5",                       "K"        },
-  { 210, 0, "seaice",      "sea ice cover",                            "fraction" },
-  { 211, 0, "siced",       "sea ice depth",                            "m"        },
-  { 212, 0, "forest",      "vegetation type",                          "fraction" },
-  { 213, 0, "teff",        "(effective) sea-ice skin temperature",     "K"        },
-  { 214, 0, "tsmax",       "maximum surface temperature",              "K"        },
-  { 215, 0, "tsmin",       "minimum surface temperature",              "K"        },
-  { 216, 0, "wimax",       "maximum 10m-wind speed",                   "m/s"      },
-  { 217, 0, "topmax",      "maximum height of convective cloud tops",  "Pa"       },
-  { 218, 0, "snmel",       "snow melt",                                "m/s"      },
-  { 219, 0, "runtoc",      "surface runoff into ocean",                 NULL      },
-  { 220, 0, "tslin",       "land: residual surface heat budget",       "W/m^2"    },
-  { 221, 0, "dsnac",       "snow depth change",                        "m/s"      },
-  { 222, 0, "alwcac",      "liquid water content",                     "kg/kg"    },
-  { 223, 0, "aclcac",      "cloud cover",                              "fraction" },
-  { 224, 0, "tke",         "turbulent kinetic energy",                  NULL      },
-  { 225, 0, "tkem1",       "turbulent kinetic energy (t-1)",            NULL      },
-  { 226, 0, "fao",         "FAO data set (soil data flags)",            NULL      },
-  { 227, 0, "rgcgn",       "heat capacity of soil",                     NULL      },
-  { 228, 0, "sodif",       "soil diffusivity",                          NULL      },
-  { 229, 0, "wsmx",        "field capacity of soil",                   "m"        },
-  { 230, 0, "qvi",         "vertically integrated specific humidity",  "kg/m^2"   },
-  { 231, 0, "alwcvi",      "vertically integrated liquid water cont.", "kg/m^2"   },
-  { 232, 0, "glac",        "glacier mask",                             "fraction" },
-  { 233, 0, "runlnd",      "surface runoff not running into ocean",     NULL      },
-  { 259, 0, "windspeed",   "windspeed (sqrt(u^2+v^2))",                 NULL      },
-  { 260, 0, "precip",      "total precipitation",                      "m/s"      },
-  { 261, 0, "net_top",     "total top radiation",                       NULL      },
-  { 262, 0, "net_bot",     "total surface radiation",                   NULL      },
-  { 263, 0, "net_heat",    "net surface heat flux",                     NULL      },
-  { 264, 0, "net_water",   "total surface water",                       NULL      },
-  { 268, 0, "sw_atm",       NULL,                                       NULL      },
-  { 269, 0, "lw_atm",       NULL,                                       NULL      },
-  { 270, 0, "net_atm",      NULL,                                       NULL      },
-  { 271, 0, "surf_runoff", "surface runoff",                            NULL      },
-  { 275, 0, "fresh_water",  NULL,                                       NULL      },
+#ifndef TABLE_H
+#define TABLE_H
+
+static const param_type echam4[] = {
+  {   4, -1, 0, "precip",      "total precipitation",                      "m/s"      },
+  {  34, -1, 0, "low_cld",     "low cloud",                                 NULL      },
+  {  35, -1, 0, "mid_cld",     "mid cloud",                                 NULL      },
+  {  36, -1, 0, "hih_cld",     "high cloud",                                NULL      },
+  { 129, -1, 0, "geosp",       "surface geopotential (orography)",         "m^2/s^2"  },
+  { 130, -1, 0, "t",           "temperature",                              "K"        },
+  { 131, -1, 0, "u",           "u-velocity",                               "m/s"      },
+  { 132, -1, 0, "v",           "v-velocity",                               "m/s"      },
+  { 133, -1, 0, "sq",          "specific humidity",                        "kg/kg"    },
+  { 134, -1, 0, "aps",         "Surface pressure",                         "Pa"       },
+  { 135, -1, 0, "omega",       "vertical velocity",                        "Pa/s"     },
+  { 138, -1, 0, "svo",         "vorticity",                                "1/s"      },
+  { 139, -1, 0, "ts",          "surface temperature",                      "K"        },
+  { 140, -1, 0, "ws",          "soil wetness",                             "m"        },
+  { 141, -1, 0, "sn",          "snow depth",                               "m"        },
+  { 142, -1, 0, "aprl",        "large scale precipitation",                "m/s"      },
+  { 143, -1, 0, "aprc",        "convective  precipitation",                "m/s"      },
+  { 144, -1, 0, "aprs",        "snow fall",                                "m/s"      },
+  { 145, -1, 0, "vdis",        "boundary layer dissipation",               "W/m^2"    },
+  { 146, -1, 0, "ahfs",        "surface sensible heat flux",               "W/m^2"    },
+  { 147, -1, 0, "ahfl",        "surface latent heat flux",                 "W/m^2"    },
+  { 148, -1, 0, "stream",      "streamfunction",                           "m^2/s"    },
+  { 149, -1, 0, "velopot",     "velocity potential",                       "m^2/s"    },
+  { 151, -1, 0, "slp",         "mean sea level pressure",                  "Pa"       },
+  { 152, -1, 0, "lsp",         "log surface pressure",                      NULL      },
+  { 153, -1, 0, "sx",          "liquid water content",                     "kg/kg"    },
+  { 155, -1, 0, "sd",          "divergence",                               "1/s"      },
+  { 156, -1, 0, "geopoth",     "geopotential height",                      "m"        },
+  { 157, -1, 0, "rhumidity",   "relative humidity",                        "fraction" },
+  { 158, -1, 0, "var158",      "tendency of surface pressure",             "Pa/s"     },
+  { 159, -1, 0, "ustar3",      "ustar3",                                   "m^3/s^3"  },
+  { 160, -1, 0, "runoff",      "surface runoff",                           "m/s"      },
+  { 161, -1, 0, "alwc",        "liquid water content",                     "kg/kg"    },
+  { 162, -1, 0, "aclc",        "cloud cover",                              "fraction" },
+  { 163, -1, 0, "aclcv",       "total cloud cover",                        "fraction" },
+  { 164, -1, 0, "aclcov",      "total cloud cover",                        "fraction" },
+  { 165, -1, 0, "u10",         "10m u-velocity",                           "m/s"      },
+  { 166, -1, 0, "v10",         "10m v-velocity",                           "m/s"      },
+  { 167, -1, 0, "temp2",       "2m temperature",                           "K"        },
+  { 168, -1, 0, "dew2",        "2m dew point temperature",                 "K"        },
+  { 169, -1, 0, "tsurf",       "surface temperature",                      "K"        },
+  { 170, -1, 0, "td",          "deep soil temperature",                    "K"        },
+  { 171, -1, 0, "wind10",      "10m windspeed",                            "m/s"      },
+  { 172, -1, 0, "slm",         "land sea mask",                            "fraction" },
+  { 173, -1, 0, "az0",         "surface roughness length",                 "m"        },
+  { 174, -1, 0, "alb",         "surface background albedo",                "fraction" },
+  { 175, -1, 0, "albedo",      "surface albedo",                           "fraction" },
+  { 176, -1, 0, "srads",       "net surface solar radiation",              "W/m^2"    },
+  { 177, -1, 0, "trads",       "net surface thermal radiation",            "W/m^2"    },
+  { 178, -1, 0, "srad0",       "net top solar radiation",                  "W/m^2"    },
+  { 179, -1, 0, "trad0",       "top thermal radiation (OLR)",              "W/m^2"    },
+  { 180, -1, 0, "ustr",        "surface u-stress",                         "Pa"       },
+  { 181, -1, 0, "vstr",        "surface v-stress",                         "Pa"       },
+  { 182, -1, 0, "evap",        "surface evaporation",                      "m/s"      },
+  { 183, -1, 0, "tdcl",        "soil temperature",                         "K"        },
+  { 185, -1, 0, "srafs",       "net surf. solar radiation   (clear sky)",  "W/m^2"    },
+  { 186, -1, 0, "trafs",       "net surf. thermal radiation (clear sky)",  "W/m^2"    },
+  { 187, -1, 0, "sraf0",       "net top solar radiation     (clear sky)",  "W/m^2"    },
+  { 188, -1, 0, "traf0",       "net top thermal radiation   (clear sky)",  "W/m^2"    },
+  { 189, -1, 0, "sclfs",       "surface solar cloud forcing",              "W/m^2"    },
+  { 190, -1, 0, "tclfs",       "surface thermal cloud forcing",            "W/m^2"    },
+  { 191, -1, 0, "sclf0",       "top solar cloud forcing",                  "W/m^2"    },
+  { 192, -1, 0, "tclf0",       "top thermal cloud forcing",                "W/m^2"    },
+  { 193, -1, 0, "wl",          "skin reservoir content",                   "m"        },
+  { 194, -1, 0, "wlm1",        "skin reservoir content of plants",         "m"        },
+  { 195, -1, 0, "ustrgw",      "u-gravity wave stress",                    "Pa"       },
+  { 196, -1, 0, "vstrgw",      "v-gravity wave stress",                    "Pa"       },
+  { 197, -1, 0, "vdisgw",      "gravity wave dissipation",                 "W/m^2"    },
+  { 198, -1, 0, "vgrat",       "vegetation ratio",                         "fraction" },
+  { 199, -1, 0, "varor",       "orographic variance",                      "m^2"      },
+  { 200, -1, 0, "vlt",         "leaf area index",                           NULL      },
+  { 201, -1, 0, "t2max",       "maximum 2m-temperature",                   "K"        },
+  { 202, -1, 0, "t2min",       "minimum 2m-temperature",                   "K"        },
+  { 203, -1, 0, "srad0u",      "top solar radiation upward",               "W/m^2"    },
+  { 204, -1, 0, "sradsu",      "surface solar radiation upward",           "W/m^2"    },
+  { 205, -1, 0, "tradsu",      "surface thermal radiation upward",         "W/m^2"    },
+  { 206, -1, 0, "tsn",         "snow temperature",                         "K"        },
+  { 207, -1, 0, "td3",         "soil temperature 3",                       "K"        },
+  { 208, -1, 0, "td4",         "soil temperature 4",                       "K"        },
+  { 209, -1, 0, "td5",         "soil temperature 5",                       "K"        },
+  { 210, -1, 0, "seaice",      "sea ice cover",                            "fraction" },
+  { 211, -1, 0, "siced",       "sea ice depth",                            "m"        },
+  { 212, -1, 0, "forest",      "vegetation type",                          "fraction" },
+  { 213, -1, 0, "teff",        "(effective) sea-ice skin temperature",     "K"        },
+  { 214, -1, 0, "tsmax",       "maximum surface temperature",              "K"        },
+  { 215, -1, 0, "tsmin",       "minimum surface temperature",              "K"        },
+  { 216, -1, 0, "wimax",       "maximum 10m-wind speed",                   "m/s"      },
+  { 217, -1, 0, "topmax",      "maximum height of convective cloud tops",  "Pa"       },
+  { 218, -1, 0, "snmel",       "snow melt",                                "m/s"      },
+  { 219, -1, 0, "runtoc",      "surface runoff into ocean",                 NULL      },
+  { 220, -1, 0, "tslin",       "land: residual surface heat budget",       "W/m^2"    },
+  { 221, -1, 0, "dsnac",       "snow depth change",                        "m/s"      },
+  { 222, -1, 0, "alwcac",      "liquid water content",                     "kg/kg"    },
+  { 223, -1, 0, "aclcac",      "cloud cover",                              "fraction" },
+  { 224, -1, 0, "tke",         "turbulent kinetic energy",                  NULL      },
+  { 225, -1, 0, "tkem1",       "turbulent kinetic energy (t-1)",            NULL      },
+  { 226, -1, 0, "fao",         "FAO data set (soil data flags)",            NULL      },
+  { 227, -1, 0, "rgcgn",       "heat capacity of soil",                     NULL      },
+  { 228, -1, 0, "sodif",       "soil diffusivity",                          NULL      },
+  { 229, -1, 0, "wsmx",        "field capacity of soil",                   "m"        },
+  { 230, -1, 0, "qvi",         "vertically integrated specific humidity",  "kg/m^2"   },
+  { 231, -1, 0, "alwcvi",      "vertically integrated liquid water cont.", "kg/m^2"   },
+  { 232, -1, 0, "glac",        "glacier mask",                             "fraction" },
+  { 233, -1, 0, "runlnd",      "surface runoff not running into ocean",     NULL      },
+  { 259, -1, 0, "windspeed",   "windspeed (sqrt(u^2+v^2))",                 NULL      },
+  { 260, -1, 0, "precip",      "total precipitation",                      "m/s"      },
+  { 261, -1, 0, "net_top",     "total top radiation",                       NULL      },
+  { 262, -1, 0, "net_bot",     "total surface radiation",                   NULL      },
+  { 263, -1, 0, "net_heat",    "net surface heat flux",                     NULL      },
+  { 264, -1, 0, "net_water",   "total surface water",                       NULL      },
+  { 268, -1, 0, "sw_atm",       NULL,                                       NULL      },
+  { 269, -1, 0, "lw_atm",       NULL,                                       NULL      },
+  { 270, -1, 0, "net_atm",      NULL,                                       NULL      },
+  { 271, -1, 0, "surf_runoff", "surface runoff",                            NULL      },
+  { 275, -1, 0, "fresh_water",  NULL,                                       NULL      },
 };
 
-static const PAR echam5[] = {
-  {   4, 0, "precip",     "total precipitation",                       "kg/m^2s" },
-  {  79, 0, "swnirac",    "net surface NIR flux acc.",                 "W/m^2"   },
-  {  80, 0, "swdifnirac", "fraction of diffuse NIR acc.",              "W/m^2"   },
-  {  81, 0, "swvisac",    "net surface visible flux acc.",             "W/m^2"   },
-  {  82, 0, "swdifvisac", "fraction of diffuse visible acc.",          "W/m^2"   },
-  {  83, 0, "ocu",        "ocean eastw. velocity (coupled mode)",      "m/s"     },
-  {  84, 0, "ocv",        "ocean northw. velocity (coupled mode)",     "m/s"     },
-  {  85, 0, "tradl",      "net LW radiation 200mb",                    "W/m^2"   },
-  {  86, 0, "sradl",      "net SW radiation 200mb",                    "W/m^2"   },
-  {  87, 0, "trafl",      "net LW radiation 200mb (clear sky)",        "W/m^2"   },
-  {  88, 0, "srafl",      "net SW radiation 200mb (clear sky)",        "W/m^2"   },
-  {  89, 0, "amlcorac",   "mixed layer flux correction",               "W/m^2"   },
-  {  90, 0, "amlheatac",  "mixed layer heat content",                  "J/m^2"   },
-  {  91, 0, "trfliac",    "net LW radiation over ice",                 "W/m^2"   },
-  {  92, 0, "trflwac",    "net LW radiation over water",               "W/m^2"   },
-  {  93, 0, "trfllac",    "net LW radiation over land",                "W/m^2"   },
-  {  94, 0, "sofliac",    "net SW radiation over ice",                 "W/m^2"   },
-  {  95, 0, "soflwac",    "net SW radiation over water",               "W/m^2"   },
-  {  96, 0, "sofllac",    "net SW radiation over land",                "W/m^2"   },
-  {  97, 0, "friac",      "ice cover (fraction of grid box)",           NULL     },
-  { 102, 0, "tsi",        "surface temperature of ice",                "K"       },
-  { 103, 0, "tsw",        "surface temperature of water",              "K"       },
-  { 104, 0, "ustri",      "zonal      wind stress over ice",           "Pa"      },
-  { 105, 0, "vstri",      "meridional wind stress over ice",           "Pa"      },
-  { 106, 0, "ustrw",      "zonal      wind stress over water",         "Pa"      },
-  { 107, 0, "vstrw",      "meridional wind stress over water",         "Pa"      },
-  { 108, 0, "ustrl",      "zonal      wind stress over land",          "Pa"      },
-  { 109, 0, "vstrl",      "meridional wind stress over land",          "Pa"      },
-  { 110, 0, "ahfliac",    "latent heat flux over ice",                 "W/m^2"   },
-  { 111, 0, "ahflwac",    "latent heat flux over water",               "W/m^2"   },
-  { 112, 0, "ahfllac",    "latent heat flux over land",                "W/m^2"   },
-  { 113, 0, "evapiac",    "evaporation over ice",                      "kg/m^2s" },
-  { 114, 0, "evapwac",    "evaporation over water",                    "kg/m^2s" },
-  { 115, 0, "evaplac",    "evaporation over land",                     "kg/m^2s" },
-  { 116, 0, "az0i",       "roughness length over ice",                 "m"       },
-  { 117, 0, "az0w",       "roughness length over water",               "m"       },
-  { 118, 0, "az0l",       "roughness length over land",                "m"       },
-  { 119, 0, "ahfsiac",    "sensible heat flux over ice",               "W/m^2"   },
-  { 120, 0, "ahfswac",    "sensible heat flux over water",             "W/m^2"   },
-  { 121, 0, "ahfslac",    "sensible heat flux over land",              "W/m^2"   },
-  { 122, 0, "alsoi",      "albedo of ice",                              NULL     },
-  { 123, 0, "alsow",      "albedo of water",                            NULL     },
-  { 124, 0, "alsol",      "albedo of land",                             NULL     },
-  { 125, 0, "ahfice",     "conductive heat flux through ice",          "W/m^2"   },
-  { 126, 0, "qres",       "residual heat flux for melting sea ice",    "W/m^2"   },
-  { 127, 0, "alake",      "lake fraction",                              NULL     },
-  { 128, 0, "rintop",     "low level inversion",                        NULL     },
-  { 129, 0, "geosp",      "surface geopotential (orography)",          "m^2/s^2" },
-  { 130, 0, "t",          "temperature",                               "K"       },
-  { 131, 0, "u",          "u-velocity",                                "m/s"     },
-  { 132, 0, "v",          "v-velocity",                                "m/s"     },
-  { 133, 0, "q",          "specific humidity",                         "kg/kg"   },
-  { 134, 0, "aps",        "surface pressure",                          "Pa"      },
-  { 135, 0, "omega",      "vertical velocity",                         "Pa/s"    },
-  { 136, 0, "acdnc",      "cloud droplet number concentration",        "1/m^3"   },
-  { 137, 0, "apmeb",      "(P-E) error",                               "kg/m^2s" },
-  { 138, 0, "svo",        "vorticity",                                 "1/s"     },
-  { 139, 0, "tslm1",      "surface temperature of land",               "K"       },
-  { 140, 0, "ws",         "soil wetness",                              "m"       },
-  { 141, 0, "sn",         "water equivalent snow depth",               "m"       },
-  { 142, 0, "aprl",       "large scale precipitation",                 "kg/m^2s" },
-  { 143, 0, "aprc",       "convective  precipitation",                 "kg/m^2s" },
-  { 144, 0, "aprs",       "snow fall",                                 "kg/m^2s" },
-  { 145, 0, "vdis",       "boundary layer dissipation",                "W/m^2"   },
-  { 146, 0, "ahfs",       "sensible heat flux",                        "W/m^2"   },
-  { 147, 0, "ahfl",       "latent heat flux",                          "W/m^2"   },
-  { 148, 0, "stream",     "streamfunction",                            "m^2/s"   },
-  { 149, 0, "velopot",    "velocity potential",                        "m^2/s"   },
-  { 150, 0, "xivi",       "vertically integrated cloud ice",           "kg/m^2"  },
-  { 151, 0, "slp",        "mean sea level pressure",                   "Pa"      },
-  { 152, 0, "lsp",        "log surface pressure",                       NULL     },
-  { 153, 0, "xl",         "cloud water",                               "kg/kg"   },
-  { 154, 0, "xi",         "cloud ice",                                 "kg/kg"   },
-  { 155, 0, "sd",         "divergence",                                "1/s"     },
-  { 156, 0, "geopoth",    "geopotential height",                       "m"       },
-  { 157, 0, "rhumidity",  "relative humidity",                          NULL     },
-  { 159, 0, "wind10w",    "10m windspeed over water",                  "m/s"     },
-  { 160, 0, "runoff",     "surface runoff and drainage",               "kg/m^2s" },
-  { 161, 0, "drain",      "drainage",                                  "kg/m^2s" },
-  { 162, 0, "aclc",       "cloud cover",                                NULL     },
-  { 164, 0, "aclcov",     "total cloud cover",                          NULL     },
-  { 165, 0, "u10",        "10m u-velocity",                            "m/s"     },
-  { 166, 0, "v10",        "10m v-velocity",                            "m/s"     },
-  { 167, 0, "temp2",      "2m temperature",                            "K"       },
-  { 168, 0, "dew2",       "2m dew point temperature",                  "K"       },
-  { 169, 0, "tsurf",      "surface temperature",                       "K"       },
-  { 170, 0, "xvar",       "variance of total water amount",            "kg/kg"   },
-  { 171, 0, "wind10",     "10m windspeed",                             "m/s"     },
-  { 172, 0, "slm",        "land sea mask (1. = land, 0. = sea/lakes)",  NULL     },
-  { 173, 0, "az0",        "roughness length",                          "m"       },
-  { 174, 0, "alb",        "surface background albedo",                  NULL     },
-  { 175, 0, "albedo",     "surface albedo",                             NULL     },
-  { 176, 0, "srads",      "net surface SW radiation",                  "W/m^2"   },
-  { 177, 0, "trads",      "net surface LW radiation",                  "W/m^2"   },
-  { 178, 0, "srad0",      "net top SW radiation",                      "W/m^2"   },
-  { 179, 0, "trad0",      "net top LW radiation (-OLR)",               "W/m^2"   },
-  { 180, 0, "ustr",       "u-stress",                                  "Pa"      },
-  { 181, 0, "vstr",       "v-stress",                                  "Pa"      },
-  { 182, 0, "evap",       "evaporation",                               "kg/m^2s" },
-  { 183, 0, "xskew",      "skewness of total water amount qv+qi+ql",    NULL     },
-  { 184, 0, "srad0d",     "top incoming SW radiation",                 "W/m^2"   },
-  { 185, 0, "srafs",      "net surface SW radiation (clear sky)",      "W/m^2"   },
-  { 186, 0, "trafs",      "net surface LW radiation (clear sky)",      "W/m^2"   },
-  { 187, 0, "sraf0",      "net top SW radiation   (clear sky)",        "W/m^2"   },
-  { 188, 0, "traf0",      "net top LW radiation   (clear sky)",        "W/m^2"   },
-  { 189, 0, "sclfs",      "net surface SW cloud forcing (176-185)",    "W/m^2"   },
-  { 190, 0, "tclfs",      "net surface LW cloud forcing (177-186)",    "W/m^2"   },
-  { 191, 0, "sclf0",      "net SW top cloud forcing (178-187)",        "W/m^2"   },
-  { 192, 0, "tclf0",      "net LW top cloud forcing (179-188)",        "W/m^2"   },
-  { 193, 0, "wl",         "skin reservoir content",                    "m"       },
-  { 194, 0, "slf",        "fractional land cover",                      NULL     },
-  { 195, 0, "ustrgw",     "u-gravity wave stress",                     "Pa"      },
-  { 196, 0, "vstrgw",     "v-gravity wave stress",                     "Pa"      },
-  { 197, 0, "vdisgw",     "gravity wave dissipation",                  "W/m^2"   },
-  { 198, 0, "vgrat",      "vegetation ratio",                           NULL     },
-  { 199, 0, "orostd",     "orographic standard deviation",             "m"       },
-  { 200, 0, "vlt",        "leaf area index",                            NULL     },
-  { 201, 0, "t2max",      "maximum 2m-temperature",                    "K"       },
-  { 202, 0, "t2min",      "minimum 2m-temperature",                    "K"       },
-  { 203, 0, "srad0u",     "top SW radiation upward",                   "W/m^2"   },
-  { 204, 0, "sradsu",     "surface SW radiation upward",               "W/m^2"   },
-  { 205, 0, "tradsu",     "surface LW radiation upward",               "W/m^2"   },
-  { 206, 0, "grndflux",   "surface ground heat flux",                   NULL     },
-  { 207, 0, "tsoil",      "deep soil temperatures (5 layers)",         "K"       },
-  { 208, 0, "ahfcon",     "conductive heat flux through ice",          "W/m^2"   },
-  { 209, 0, "ahfres",     "res. heat flux for melting ice",            "W/m^2"   },
-  { 210, 0, "seaice",     "ice cover (fraction of ice+water)",          NULL     },
-  { 211, 0, "siced",      "ice thickness",                             "m"       },
-  { 212, 0, "forest",     "forest fraction",                            NULL     },
-  { 213, 0, "gld",        "glacier thickness",                         "m"       },
-  { 214, 0, "sni",        "water equivalent of snow on ice",           "m"       },
-  { 215, 0, "rogl",       "glacier runoff",                            "kg/m^2s" },
-  { 216, 0, "wimax",      "maximum 10m-wind speed",                    "m/s"     },
-  { 217, 0, "topmax",     "maximum height of convective cloud tops",   "Pa"      },
-  { 218, 0, "snmel",      "snow melt",                                 "kg/m^2s" },
-  { 219, 0, "runtoc",     "surface runoff into ocean",                 "kg/m^2s" },
-  { 220, 0, "runlnd",     "surface runoff not running into ocean",     "kg/m^2s" },
-  { 221, 0, "apmegl",     "P-E over land ice",                         "kg/m^2s" },
-  { 222, 0, "snacl",      "snow accumulation over land",               "kg/m^2s" },
-  { 223, 0, "aclcac",     "cloud cover",                                NULL     },
-  { 224, 0, "tke",        "turbulent kinetic energy",                  "m^2/s^2" },
-  { 225, 0, "tkem1",      "turbulent kinetic energy (t-1)",            "m^2/s^2" },
-  { 226, 0, "fao",        "FAO data set (soil data flags) 0...5",       NULL     },
-  { 227, 0, "rgcgn",      "heat capacity of soil",                      NULL     },
-  { 228, 0, "sodif",      "soil diffusivity",                          "m^2/s"   },
-  { 229, 0, "wsmx",       "field capacity of soil",                    "m"       },
-  { 230, 0, "qvi",        "vertically integrated water vapor",         "kg/m^2"  },
-  { 231, 0, "xlvi",       "vertically integrated cloud water",         "kg/m^2"  },
-  { 232, 0, "glac",       "fraction of land covered by glaciers",       NULL     },
-  { 233, 0, "snc",        "snow depth at the canopy",                  "m"       },
-  { 234, 0, "rtype",      "type of convection",                        "0...3"   },
-  { 235, 0, "abso4",      "anthropogenic sulfur burden",               "kg/m^2"  },
-  { 236, 0, "ao3",        "ipcc ozone",                                "kg/m^2"  },
-  { 237, 0, "tropo",      "WMO defined tropopause height",             "Pa"      },
-  { 259, 0, "windspeed",  "windspeed (sqrt(u^2+v^2))",                 "m/s"     },
-  { 260, 0, "precip",     "total precipitation  (142+143)",            "kg/m^2s" },
-  { 261, 0, "net_top",    "total top radiation  (178+179)",            "W/m^2"   },
-  { 262, 0, "net_bot",    "total surface radiation (176+177)",         "W/m^2"   },
-  { 272, 0, "mastrfu",    "mass stream function",                      "kg/s"    },
+static const param_type echam5[] = {
+  {   4, -1, 0, "precip",     "total precipitation",                       "kg/m^2s" },
+  {  79, -1, 0, "swnirac",    "net surface NIR flux acc.",                 "W/m^2"   },
+  {  80, -1, 0, "swdifnirac", "fraction of diffuse NIR acc.",              "W/m^2"   },
+  {  81, -1, 0, "swvisac",    "net surface visible flux acc.",             "W/m^2"   },
+  {  82, -1, 0, "swdifvisac", "fraction of diffuse visible acc.",          "W/m^2"   },
+  {  83, -1, 0, "ocu",        "ocean eastw. velocity (coupled mode)",      "m/s"     },
+  {  84, -1, 0, "ocv",        "ocean northw. velocity (coupled mode)",     "m/s"     },
+  {  85, -1, 0, "tradl",      "net LW radiation 200mb",                    "W/m^2"   },
+  {  86, -1, 0, "sradl",      "net SW radiation 200mb",                    "W/m^2"   },
+  {  87, -1, 0, "trafl",      "net LW radiation 200mb (clear sky)",        "W/m^2"   },
+  {  88, -1, 0, "srafl",      "net SW radiation 200mb (clear sky)",        "W/m^2"   },
+  {  89, -1, 0, "amlcorac",   "mixed layer flux correction",               "W/m^2"   },
+  {  90, -1, 0, "amlheatac",  "mixed layer heat content",                  "J/m^2"   },
+  {  91, -1, 0, "trfliac",    "net LW radiation over ice",                 "W/m^2"   },
+  {  92, -1, 0, "trflwac",    "net LW radiation over water",               "W/m^2"   },
+  {  93, -1, 0, "trfllac",    "net LW radiation over land",                "W/m^2"   },
+  {  94, -1, 0, "sofliac",    "net SW radiation over ice",                 "W/m^2"   },
+  {  95, -1, 0, "soflwac",    "net SW radiation over water",               "W/m^2"   },
+  {  96, -1, 0, "sofllac",    "net SW radiation over land",                "W/m^2"   },
+  {  97, -1, 0, "friac",      "ice cover (fraction of grid box)",           NULL     },
+  { 102, -1, 0, "tsi",        "surface temperature of ice",                "K"       },
+  { 103, -1, 0, "tsw",        "surface temperature of water",              "K"       },
+  { 104, -1, 0, "ustri",      "zonal      wind stress over ice",           "Pa"      },
+  { 105, -1, 0, "vstri",      "meridional wind stress over ice",           "Pa"      },
+  { 106, -1, 0, "ustrw",      "zonal      wind stress over water",         "Pa"      },
+  { 107, -1, 0, "vstrw",      "meridional wind stress over water",         "Pa"      },
+  { 108, -1, 0, "ustrl",      "zonal      wind stress over land",          "Pa"      },
+  { 109, -1, 0, "vstrl",      "meridional wind stress over land",          "Pa"      },
+  { 110, -1, 0, "ahfliac",    "latent heat flux over ice",                 "W/m^2"   },
+  { 111, -1, 0, "ahflwac",    "latent heat flux over water",               "W/m^2"   },
+  { 112, -1, 0, "ahfllac",    "latent heat flux over land",                "W/m^2"   },
+  { 113, -1, 0, "evapiac",    "evaporation over ice",                      "kg/m^2s" },
+  { 114, -1, 0, "evapwac",    "evaporation over water",                    "kg/m^2s" },
+  { 115, -1, 0, "evaplac",    "evaporation over land",                     "kg/m^2s" },
+  { 116, -1, 0, "az0i",       "roughness length over ice",                 "m"       },
+  { 117, -1, 0, "az0w",       "roughness length over water",               "m"       },
+  { 118, -1, 0, "az0l",       "roughness length over land",                "m"       },
+  { 119, -1, 0, "ahfsiac",    "sensible heat flux over ice",               "W/m^2"   },
+  { 120, -1, 0, "ahfswac",    "sensible heat flux over water",             "W/m^2"   },
+  { 121, -1, 0, "ahfslac",    "sensible heat flux over land",              "W/m^2"   },
+  { 122, -1, 0, "alsoi",      "albedo of ice",                              NULL     },
+  { 123, -1, 0, "alsow",      "albedo of water",                            NULL     },
+  { 124, -1, 0, "alsol",      "albedo of land",                             NULL     },
+  { 125, -1, 0, "ahfice",     "conductive heat flux through ice",          "W/m^2"   },
+  { 126, -1, 0, "qres",       "residual heat flux for melting sea ice",    "W/m^2"   },
+  { 127, -1, 0, "alake",      "lake fraction",                              NULL     },
+  { 128, -1, 0, "rintop",     "low level inversion",                        NULL     },
+  { 129, -1, 0, "geosp",      "surface geopotential (orography)",          "m^2/s^2" },
+  { 130, -1, 0, "t",          "temperature",                               "K"       },
+  { 131, -1, 0, "u",          "u-velocity",                                "m/s"     },
+  { 132, -1, 0, "v",          "v-velocity",                                "m/s"     },
+  { 133, -1, 0, "q",          "specific humidity",                         "kg/kg"   },
+  { 134, -1, 0, "aps",        "surface pressure",                          "Pa"      },
+  { 135, -1, 0, "omega",      "vertical velocity",                         "Pa/s"    },
+  { 136, -1, 0, "acdnc",      "cloud droplet number concentration",        "1/m^3"   },
+  { 137, -1, 0, "apmeb",      "(P-E) error",                               "kg/m^2s" },
+  { 138, -1, 0, "svo",        "vorticity",                                 "1/s"     },
+  { 139, -1, 0, "tslm1",      "surface temperature of land",               "K"       },
+  { 140, -1, 0, "ws",         "soil wetness",                              "m"       },
+  { 141, -1, 0, "sn",         "water equivalent snow depth",               "m"       },
+  { 142, -1, 0, "aprl",       "large scale precipitation",                 "kg/m^2s" },
+  { 143, -1, 0, "aprc",       "convective  precipitation",                 "kg/m^2s" },
+  { 144, -1, 0, "aprs",       "snow fall",                                 "kg/m^2s" },
+  { 145, -1, 0, "vdis",       "boundary layer dissipation",                "W/m^2"   },
+  { 146, -1, 0, "ahfs",       "sensible heat flux",                        "W/m^2"   },
+  { 147, -1, 0, "ahfl",       "latent heat flux",                          "W/m^2"   },
+  { 148, -1, 0, "stream",     "streamfunction",                            "m^2/s"   },
+  { 149, -1, 0, "velopot",    "velocity potential",                        "m^2/s"   },
+  { 150, -1, 0, "xivi",       "vertically integrated cloud ice",           "kg/m^2"  },
+  { 151, -1, 0, "slp",        "mean sea level pressure",                   "Pa"      },
+  { 152, -1, 0, "lsp",        "log surface pressure",                       NULL     },
+  { 153, -1, 0, "xl",         "cloud water",                               "kg/kg"   },
+  { 154, -1, 0, "xi",         "cloud ice",                                 "kg/kg"   },
+  { 155, -1, 0, "sd",         "divergence",                                "1/s"     },
+  { 156, -1, 0, "geopoth",    "geopotential height",                       "m"       },
+  { 157, -1, 0, "rhumidity",  "relative humidity",                          NULL     },
+  { 159, -1, 0, "wind10w",    "10m windspeed over water",                  "m/s"     },
+  { 160, -1, 0, "runoff",     "surface runoff and drainage",               "kg/m^2s" },
+  { 161, -1, 0, "drain",      "drainage",                                  "kg/m^2s" },
+  { 162, -1, 0, "aclc",       "cloud cover",                                NULL     },
+  { 164, -1, 0, "aclcov",     "total cloud cover",                          NULL     },
+  { 165, -1, 0, "u10",        "10m u-velocity",                            "m/s"     },
+  { 166, -1, 0, "v10",        "10m v-velocity",                            "m/s"     },
+  { 167, -1, 0, "temp2",      "2m temperature",                            "K"       },
+  { 168, -1, 0, "dew2",       "2m dew point temperature",                  "K"       },
+  { 169, -1, 0, "tsurf",      "surface temperature",                       "K"       },
+  { 170, -1, 0, "xvar",       "variance of total water amount",            "kg/kg"   },
+  { 171, -1, 0, "wind10",     "10m windspeed",                             "m/s"     },
+  { 172, -1, 0, "slm",        "land sea mask (1. = land, 0. = sea/lakes)",  NULL     },
+  { 173, -1, 0, "az0",        "roughness length",                          "m"       },
+  { 174, -1, 0, "alb",        "surface background albedo",                  NULL     },
+  { 175, -1, 0, "albedo",     "surface albedo",                             NULL     },
+  { 176, -1, 0, "srads",      "net surface SW radiation",                  "W/m^2"   },
+  { 177, -1, 0, "trads",      "net surface LW radiation",                  "W/m^2"   },
+  { 178, -1, 0, "srad0",      "net top SW radiation",                      "W/m^2"   },
+  { 179, -1, 0, "trad0",      "net top LW radiation (-OLR)",               "W/m^2"   },
+  { 180, -1, 0, "ustr",       "u-stress",                                  "Pa"      },
+  { 181, -1, 0, "vstr",       "v-stress",                                  "Pa"      },
+  { 182, -1, 0, "evap",       "evaporation",                               "kg/m^2s" },
+  { 183, -1, 0, "xskew",      "skewness of total water amount qv+qi+ql",    NULL     },
+  { 184, -1, 0, "srad0d",     "top incoming SW radiation",                 "W/m^2"   },
+  { 185, -1, 0, "srafs",      "net surface SW radiation (clear sky)",      "W/m^2"   },
+  { 186, -1, 0, "trafs",      "net surface LW radiation (clear sky)",      "W/m^2"   },
+  { 187, -1, 0, "sraf0",      "net top SW radiation   (clear sky)",        "W/m^2"   },
+  { 188, -1, 0, "traf0",      "net top LW radiation   (clear sky)",        "W/m^2"   },
+  { 189, -1, 0, "sclfs",      "net surface SW cloud forcing (176-185)",    "W/m^2"   },
+  { 190, -1, 0, "tclfs",      "net surface LW cloud forcing (177-186)",    "W/m^2"   },
+  { 191, -1, 0, "sclf0",      "net SW top cloud forcing (178-187)",        "W/m^2"   },
+  { 192, -1, 0, "tclf0",      "net LW top cloud forcing (179-188)",        "W/m^2"   },
+  { 193, -1, 0, "wl",         "skin reservoir content",                    "m"       },
+  { 194, -1, 0, "slf",        "fractional land cover",                      NULL     },
+  { 195, -1, 0, "ustrgw",     "u-gravity wave stress",                     "Pa"      },
+  { 196, -1, 0, "vstrgw",     "v-gravity wave stress",                     "Pa"      },
+  { 197, -1, 0, "vdisgw",     "gravity wave dissipation",                  "W/m^2"   },
+  { 198, -1, 0, "vgrat",      "vegetation ratio",                           NULL     },
+  { 199, -1, 0, "orostd",     "orographic standard deviation",             "m"       },
+  { 200, -1, 0, "vlt",        "leaf area index",                            NULL     },
+  { 201, -1, 0, "t2max",      "maximum 2m-temperature",                    "K"       },
+  { 202, -1, 0, "t2min",      "minimum 2m-temperature",                    "K"       },
+  { 203, -1, 0, "srad0u",     "top SW radiation upward",                   "W/m^2"   },
+  { 204, -1, 0, "sradsu",     "surface SW radiation upward",               "W/m^2"   },
+  { 205, -1, 0, "tradsu",     "surface LW radiation upward",               "W/m^2"   },
+  { 206, -1, 0, "grndflux",   "surface ground heat flux",                   NULL     },
+  { 207, -1, 0, "tsoil",      "deep soil temperatures (5 layers)",         "K"       },
+  { 208, -1, 0, "ahfcon",     "conductive heat flux through ice",          "W/m^2"   },
+  { 209, -1, 0, "ahfres",     "res. heat flux for melting ice",            "W/m^2"   },
+  { 210, -1, 0, "seaice",     "ice cover (fraction of ice+water)",          NULL     },
+  { 211, -1, 0, "siced",      "ice thickness",                             "m"       },
+  { 212, -1, 0, "forest",     "forest fraction",                            NULL     },
+  { 213, -1, 0, "gld",        "glacier thickness",                         "m"       },
+  { 214, -1, 0, "sni",        "water equivalent of snow on ice",           "m"       },
+  { 215, -1, 0, "rogl",       "glacier runoff",                            "kg/m^2s" },
+  { 216, -1, 0, "wimax",      "maximum 10m-wind speed",                    "m/s"     },
+  { 217, -1, 0, "topmax",     "maximum height of convective cloud tops",   "Pa"      },
+  { 218, -1, 0, "snmel",      "snow melt",                                 "kg/m^2s" },
+  { 219, -1, 0, "runtoc",     "surface runoff into ocean",                 "kg/m^2s" },
+  { 220, -1, 0, "runlnd",     "surface runoff not running into ocean",     "kg/m^2s" },
+  { 221, -1, 0, "apmegl",     "P-E over land ice",                         "kg/m^2s" },
+  { 222, -1, 0, "snacl",      "snow accumulation over land",               "kg/m^2s" },
+  { 223, -1, 0, "aclcac",     "cloud cover",                                NULL     },
+  { 224, -1, 0, "tke",        "turbulent kinetic energy",                  "m^2/s^2" },
+  { 225, -1, 0, "tkem1",      "turbulent kinetic energy (t-1)",            "m^2/s^2" },
+  { 226, -1, 0, "fao",        "FAO data set (soil data flags) 0...5",       NULL     },
+  { 227, -1, 0, "rgcgn",      "heat capacity of soil",                      NULL     },
+  { 228, -1, 0, "sodif",      "soil diffusivity",                          "m^2/s"   },
+  { 229, -1, 0, "wsmx",       "field capacity of soil",                    "m"       },
+  { 230, -1, 0, "qvi",        "vertically integrated water vapor",         "kg/m^2"  },
+  { 231, -1, 0, "xlvi",       "vertically integrated cloud water",         "kg/m^2"  },
+  { 232, -1, 0, "glac",       "fraction of land covered by glaciers",       NULL     },
+  { 233, -1, 0, "snc",        "snow depth at the canopy",                  "m"       },
+  { 234, -1, 0, "rtype",      "type of convection",                        "0...3"   },
+  { 235, -1, 0, "abso4",      "anthropogenic sulfur burden",               "kg/m^2"  },
+  { 236, -1, 0, "ao3",        "ipcc ozone",                                "kg/m^2"  },
+  { 237, -1, 0, "tropo",      "WMO defined tropopause height",             "Pa"      },
+  { 259, -1, 0, "windspeed",  "windspeed (sqrt(u^2+v^2))",                 "m/s"     },
+  { 260, -1, 0, "precip",     "total precipitation  (142+143)",            "kg/m^2s" },
+  { 261, -1, 0, "net_top",    "total top radiation  (178+179)",            "W/m^2"   },
+  { 262, -1, 0, "net_bot",    "total surface radiation (176+177)",         "W/m^2"   },
+  { 272, -1, 0, "mastrfu",    "mass stream function",                      "kg/s"    },
 };
 
-static const PAR echam6[] = {
-  {   4, 0, "precip",         "total precipitation",                       "kg m-2 s-1" },
-  {  34, 0, "low_cld",        "low cloud",                                  NULL        },
-  {  35, 0, "mid_cld",        "mid cloud",                                  NULL        },
-  {  36, 0, "hih_cld",        "high cloud",                                 NULL        },
-  {  68, 0, "fage",           "aging factor of snow on ice",                NULL        },
-  {  69, 0, "snifrac",        "fraction of ice covered with snow",          NULL        },
-  {  70, 0, "barefrac",       "bare ice fraction",                          NULL        },
-  {  71, 0, "alsom",          "albedo of melt ponds",                       NULL        },
-  {  72, 0, "alsobs",         "albedo of bare ice and snow",                NULL        },
-  {  73, 0, "sicepdw",        "melt pond depth on sea-ice",                "m"          },
-  {  74, 0, "sicepdi",        "ice thickness on melt pond",                "m"          },
-  {  75, 0, "tsicepdi",       "ice temperature on frozen melt pond",       "K"          },
-  {  76, 0, "sicepres",       "residual heat flux",                        "W m-2"      },
-  {  77, 0, "ameltdepth",     "total melt pond depth",                     "m"          },
-  {  78, 0, "ameltfrac",      "fractional area of melt ponds on sea-ice",   NULL        },
-  {  79, 0, "albedo_vis_dir", "surface albedo visible range direct",        NULL        },
-  {  80, 0, "albedo_nir_dir", "surface albedo NIR range direct",            NULL        },
-  {  81, 0, "albedo_vis_dif", "surface albedo visible range diffuse",       NULL        },
-  {  82, 0, "albedo_nir_dif", "surface albedo NIR range diffuse",           NULL        },
-  {  83, 0, "ocu",            "ocean eastw. velocity (coupled mode)",      "m/s"        },
-  {  84, 0, "ocv",            "ocean northw. velocity (coupled mode)",     "m/s"        },
-  {  85, 0, "tradl",          "thermal radiation 200mb",                   "W m-2"      },
-  {  86, 0, "sradl",          "solar radiation 200mb",                     "W m-2"      },
-  {  87, 0, "trafl",          "thermal radiation 200mb (clear sky)",       "W m-2"      },
-  {  88, 0, "srafl",          "solar radiation 200mb (clear sky)",         "W m-2"      },
-  {  89, 0, "amlcorac",       "mixed layer flux correction",               "W m-2"      },
-  {  90, 0, "amlheatac",      "mixed layer heat content",                  "J m-2"      },
-  {  91, 0, "trfliac",        "LW flux over ice",                          "W m-2"      },
-  {  92, 0, "trflwac",        "LW flux over water",                        "W m-2"      },
-  {  93, 0, "trfllac",        "LW flux over land",                         "W m-2"      },
-  {  94, 0, "sofliac",        "SW flux over ice",                          "W m-2"      },
-  {  95, 0, "soflwac",        "SW flux over water",                        "W m-2"      },
-  {  96, 0, "sofllac",        "SW flux over land",                         "W m-2"      },
-  {  97, 0, "friac",          "ice cover (fraction of grid box)",           NULL        },
-  { 102, 0, "tsi",            "surface temperature of ice",                "K"          },
-  { 103, 0, "tsw",            "surface temperature of water",              "K"          },
-  { 104, 0, "ustri",          "zonal      wind stress over ice",           "Pa"         },
-  { 105, 0, "vstri",          "meridional wind stress over ice",           "Pa"         },
-  { 106, 0, "ustrw",          "zonal      wind stress over water",         "Pa"         },
-  { 107, 0, "vstrw",          "meridional wind stress over water",         "Pa"         },
-  { 108, 0, "ustrl",          "zonal      wind stress over land",          "Pa"         },
-  { 109, 0, "vstrl",          "meridional wind stress over land",          "Pa"         },
-  { 110, 0, "ahfliac",        "latent heat flux over ice",                 "W m-2"      },
-  { 111, 0, "ahflwac",        "latent heat flux over water",               "W m-2"      },
-  { 112, 0, "ahfllac",        "latent heat flux over land",                "W m-2"      },
-  { 113, 0, "evapiac",        "evaporation over ice",                      "kg m-2 s-1" },
-  { 114, 0, "evapwac",        "evaporation over water",                    "kg m-2 s-1" },
-  { 115, 0, "evaplac",        "evaporation over land",                     "kg m-2 s-1" },
-  { 116, 0, "az0i",           "roughness length over ice",                 "m"          },
-  { 117, 0, "az0w",           "roughness length over water",               "m"          },
-  { 118, 0, "az0l",           "roughness length over land",                "m"          },
-  { 119, 0, "ahfsiac",        "sensible heat flux over ice",               "W m-2"      },
-  { 120, 0, "ahfswac",        "sensible heat flux over water",             "W m-2"      },
-  { 121, 0, "ahfslac",        "sensible heat flux over land",              "W m-2"      },
-  { 122, 0, "alsoi",          "albedo of ice",                              NULL        },
-  { 123, 0, "alsow",          "albedo of water",                            NULL        },
-  { 124, 0, "alsol",          "albedo of land",                             NULL        },
-  { 125, 0, "ahfice",         "conductive heat flux",                      "W m-2"      },
-  { 126, 0, "qres",           "residual heat flux for melting sea ice",    "W m-2"      },
-  { 127, 0, "alake",          "lake fraction of grid box",                 "fraction"   },
-  { 128, 0, "rintop",         "low level inversion",                        NULL        },
-  { 129, 0, "geosp",          "surface geopotential (orography)",          "m^2/s^2"    },
-  { 130, 0, "t",              "temperature",                               "K"          },
-  { 131, 0, "u",              "u-velocity",                                "m/s"        },
-  { 132, 0, "v",              "v-velocity",                                "m/s"        },
-  { 133, 0, "q",              "specific humidity",                         "kg/kg"      },
-  { 134, 0, "aps",            "surface pressure",                          "Pa"         },
-  { 135, 0, "omega",          "vertical velocity",                         "Pa/s"       },
-  { 136, 0, "acdnc",          "cloud droplet number concentration",        "1 m-3"      },
-  { 137, 0, "apmeb",          "vert. integr. tendencies of water",         "kg m-2 s-1" },
-  { 138, 0, "svo",            "vorticity",                                 "1/s"        },
-  { 139, 0, "tslm1",          "surface temperature of land",               "K"          },
-  { 140, 0, "ws",             "soil wetness",                              "m"          },
-  { 141, 0, "sn",             "snow depth",                                "m"          },
-  { 142, 0, "aprl",           "large scale precipitation",                 "kg m-2 s-1" },
-  { 143, 0, "aprc",           "convective  precipitation",                 "kg m-2 s-1" },
-  { 144, 0, "aprs",           "snow fall",                                 "kg m-2 s-1" },
-  { 145, 0, "vdis",           "boundary layer dissipation",                "W m-2"      },
-  { 146, 0, "ahfs",           "sensible heat flux",                        "W m-2"      },
-  { 147, 0, "ahfl",           "latent heat flux",                          "W m-2"      },
-  { 148, 0, "stream",         "streamfunction",                            "m^2/s"      },
-  { 149, 0, "velopot",        "velocity potential",                        "m^2/s"      },
-  { 150, 0, "xivi",           "vertically integrated cloud ice",           "kg m-2"     },
-  { 151, 0, "slp",            "mean sea level pressure",                   "Pa"         },
-  { 152, 0, "lsp",            "log surface pressure",                       NULL        },
-  { 153, 0, "xl",             "cloud water",                               "kg/kg"      },
-  { 154, 0, "xi",             "cloud ice",                                 "kg/kg"      },
-  { 155, 0, "sd",             "divergence",                                "1/s"        },
-  { 156, 0, "geopoth",        "geopotential height",                       "m"          },
-  { 157, 0, "rhumidity",      "relative humidity",                         "fraction"   },
-  { 158, 0, "var158",         "tendency of surface pressure",              "Pa/s"       },
-  { 159, 0, "wind10w",        "10m windspeed over water",                  "m/s"        },
-  { 160, 0, "runoff",         "surface runoff and drainage",               "kg m-2 s-1" },
-  { 161, 0, "drain",          "drainage",                                  "kg m-2 s-1" },
-  { 162, 0, "aclc",           "cloud cover",                                NULL        },
-  { 163, 0, "aclcv",          "total cloud cover",                          NULL        },
-  { 164, 0, "aclcov",         "total cloud cover (mean)",                   NULL        },
-  { 165, 0, "u10",            "10m u-velocity",                            "m/s"        },
-  { 166, 0, "v10",            "10m v-velocity",                            "m/s"        },
-  { 167, 0, "temp2",          "2m temperature",                            "K"          },
-  { 168, 0, "dew2",           "2m dew point temperature",                  "K"          },
-  { 169, 0, "tsurf",          "surface temperature",                       "K"          },
-  { 170, 0, "xvar",           "variance of total water amount qv+qi+ql",   "kg/kg"      },
-  { 171, 0, "wind10",         "10m windspeed",                             "m/s"        },
-  { 172, 0, "slm",            "land sea mask (1. = land, 0. = sea/lakes)",  NULL        },
-  { 173, 0, "az0",            "roughness length",                          "m"          },
-  { 174, 0, "alb",            "surface background albedo",                  NULL        },
-  { 175, 0, "albedo",         "surface albedo",                             NULL        },
-  { 176, 0, "srads",          "net surface solar radiation",               "W m-2"      },
-  { 177, 0, "trads",          "net surface thermal radiation",             "W m-2"      },
-  { 178, 0, "srad0",          "net top solar radiation",                   "W m-2"      },
-  { 179, 0, "trad0",          "top thermal radiation (OLR)",               "W m-2"      },
-  { 180, 0, "ustr",           "u-stress",                                  "Pa"         },
-  { 181, 0, "vstr",           "v-stress",                                  "Pa"         },
-  { 182, 0, "evap",           "evaporation",                               "kg m-2 s-1" },
-  { 183, 0, "xskew",          "skewness of total water amount qv+qi+ql",    NULL        },
-  { 184, 0, "srad0d",         "top incoming solar radiation",              "W m-2"      },
-  { 185, 0, "srafs",          "net surf. solar radiation   (clear sky)",   "W m-2"      },
-  { 186, 0, "trafs",          "net surf. thermal radiation (clear sky)",   "W m-2"      },
-  { 187, 0, "sraf0",          "net top solar radiation     (clear sky)",   "W m-2"      },
-  { 188, 0, "traf0",          "net top thermal radiation   (clear sky)",   "W m-2"      },
-  { 189, 0, "sclfs",          "surface solar cloud forcing",               "W m-2"      },
-  { 190, 0, "tclfs",          "surface thermal cloud forcing",             "W m-2"      },
-  { 191, 0, "sclf0",          "SW top cloud forcing (178-187)",            "W m-2"      },
-  { 192, 0, "tclf0",          "LW top cloud forcing (179-188)",            "W m-2"      },
-  { 193, 0, "wl",             "skin reservoir content",                    "m"          },
-  { 194, 0, "slf",            "sea land fraction",                          NULL        },
-  { 195, 0, "ustrgw",         "u-gravity wave stress",                     "Pa"         },
-  { 196, 0, "vstrgw",         "v-gravity wave stress",                     "Pa"         },
-  { 197, 0, "vdisgw",         "gravity wave dissipation",                  "W m-2"      },
-  { 198, 0, "vgrat",          "vegetation ratio",                           NULL        },
-  { 199, 0, "orostd",         "orographic standard deviation",             "m"          },
-  { 200, 0, "vlt",            "leaf area index",                            NULL        },
-  { 201, 0, "t2max",          "maximum 2m-temperature",                    "K"          },
-  { 202, 0, "t2min",          "minimum 2m-temperature",                    "K"          },
-  { 203, 0, "srad0u",         "top solar radiation upward",                "W m-2"      },
-  { 204, 0, "sradsu",         "surface solar radiation upward",            "W m-2"      },
-  { 205, 0, "tradsu",         "surface thermal radiation upward",          "W m-2"      },
-  { 206, 0, "grndflux",       "surface ground heat flux",                   NULL        },
-  { 207, 0, "tsoil",          "deep soil temperatures (5 layers)",         "K"          },
-  { 208, 0, "ahfcon",         "conductive heat flux through ice",          "W m-2"      },
-  { 209, 0, "ahfres",         "melting of ice",                            "W m-2"      },
-  { 210, 0, "seaice",         "ice cover (fraction of 1-SLM)",              NULL        },
-  { 211, 0, "siced",          "ice depth",                                 "m"          },
-  { 212, 0, "forest",         "forest fraction",                            NULL        },
-  { 213, 0, "gld",            "glacier depth",                             "m"          },
-  { 214, 0, "sni",            "water equivalent of snow on ice",           "m"          },
-  { 215, 0, "rogl",           "glacier runoff",                            "kg m-2 s-1" },
-  { 216, 0, "wimax",          "maximum 10m-wind speed",                    "m/s"        },
-  { 217, 0, "topmax",         "maximum height of convective cloud tops",   "Pa"         },
-  { 218, 0, "snmel",          "snow melt",                                 "kg m-2 s-1" },
-  { 219, 0, "runtoc",         "surface runoff into ocean",                 "kg m-2 s-1" },
-  { 220, 0, "runlnd",         "surface runoff not running into ocean",     "kg m-2 s-1" },
-  { 221, 0, "apmegl",         "P-E over land ice",                         "kg m-2 s-1" },
-  { 222, 0, "snacl",          "snow accumulation over land",               "kg m-2 s-1" },
-  { 223, 0, "aclcac",         "cloud cover",                                NULL        },
-  { 224, 0, "tke",            "turbulent kinetic energy",                  "m^2/s^2"    },
-  { 225, 0, "tkem1",          "turbulent kinetic energy (t-1)",            "m^2/s^2"    },
-  { 226, 0, "fao",            "FAO data set (soil data flags)",            "0...5"      },
-  { 227, 0, "rgcgn",          "heat capacity of soil",                      NULL        },
-  { 228, 0, "sodif",          "diffusivity of soil and land ice",          "m^2/s"      },
-  { 229, 0, "wsmx",           "field capacity of soil",                    "m"          },
-  { 230, 0, "qvi",            "vertically integrated water vapor",         "kg m-2"     },
-  { 231, 0, "xlvi",           "vertically integrated cloud water",         "kg m-2"     },
-  { 232, 0, "glac",           "fraction of land covered by glaciers",       NULL        },
-  { 233, 0, "snc",            "snow depth at the canopy",                  "m"          },
-  { 234, 0, "rtype",          "type of convection",                        "0...3"      },
-  { 235, 0, "abso4",          "antropogenic sulfur burden",                "kg m-2"     },
-  { 236, 0, "ao3",            "ipcc ozone",                                "kg m-2"     },
-  { 237, 0, "tropo",          "WMO defined tropopause height",             "Pa"         },
-  { 259, 0, "windspeed",      "windspeed (sqrt(u^2+v^2))",                 "m/s"        },
-  { 260, 0, "precip",         "total precipitation  (142+143)",            "kg m-2 s-1" },
-  { 261, 0, "net_top",        "total top radiation  (178+179)",            "W m-2"      },
-  { 262, 0, "net_bot",        "total surface radiation (176+177)",         "W m-2"      },
-  { 272, 0, "mastfru",        "mass stream function",                      "kg/s"       },
+static const param_type echam6[] = {
+  {   4, -1, 0, "precip",         "total precipitation",                       "kg m-2 s-1" },
+  {  34, -1, 0, "low_cld",        "low cloud",                                  NULL        },
+  {  35, -1, 0, "mid_cld",        "mid cloud",                                  NULL        },
+  {  36, -1, 0, "hih_cld",        "high cloud",                                 NULL        },
+  {  68, -1, 0, "fage",           "aging factor of snow on ice",                NULL        },
+  {  69, -1, 0, "snifrac",        "fraction of ice covered with snow",          NULL        },
+  {  70, -1, 0, "barefrac",       "bare ice fraction",                          NULL        },
+  {  71, -1, 0, "alsom",          "albedo of melt ponds",                       NULL        },
+  {  72, -1, 0, "alsobs",         "albedo of bare ice and snow",                NULL        },
+  {  73, -1, 0, "sicepdw",        "melt pond depth on sea-ice",                "m"          },
+  {  74, -1, 0, "sicepdi",        "ice thickness on melt pond",                "m"          },
+  {  75, -1, 0, "tsicepdi",       "ice temperature on frozen melt pond",       "K"          },
+  {  76, -1, 0, "sicepres",       "residual heat flux",                        "W m-2"      },
+  {  77, -1, 0, "ameltdepth",     "total melt pond depth",                     "m"          },
+  {  78, -1, 0, "ameltfrac",      "fractional area of melt ponds on sea-ice",   NULL        },
+  {  79, -1, 0, "albedo_vis_dir", "surface albedo visible range direct",        NULL        },
+  {  80, -1, 0, "albedo_nir_dir", "surface albedo NIR range direct",            NULL        },
+  {  81, -1, 0, "albedo_vis_dif", "surface albedo visible range diffuse",       NULL        },
+  {  82, -1, 0, "albedo_nir_dif", "surface albedo NIR range diffuse",           NULL        },
+  {  83, -1, 0, "ocu",            "ocean eastw. velocity (coupled mode)",      "m/s"        },
+  {  84, -1, 0, "ocv",            "ocean northw. velocity (coupled mode)",     "m/s"        },
+  {  85, -1, 0, "tradl",          "thermal radiation 200mb",                   "W m-2"      },
+  {  86, -1, 0, "sradl",          "solar radiation 200mb",                     "W m-2"      },
+  {  87, -1, 0, "trafl",          "thermal radiation 200mb (clear sky)",       "W m-2"      },
+  {  88, -1, 0, "srafl",          "solar radiation 200mb (clear sky)",         "W m-2"      },
+  {  89, -1, 0, "amlcorac",       "mixed layer flux correction",               "W m-2"      },
+  {  90, -1, 0, "amlheatac",      "mixed layer heat content",                  "J m-2"      },
+  {  91, -1, 0, "trfliac",        "LW flux over ice",                          "W m-2"      },
+  {  92, -1, 0, "trflwac",        "LW flux over water",                        "W m-2"      },
+  {  93, -1, 0, "trfllac",        "LW flux over land",                         "W m-2"      },
+  {  94, -1, 0, "sofliac",        "SW flux over ice",                          "W m-2"      },
+  {  95, -1, 0, "soflwac",        "SW flux over water",                        "W m-2"      },
+  {  96, -1, 0, "sofllac",        "SW flux over land",                         "W m-2"      },
+  {  97, -1, 0, "friac",          "ice cover (fraction of grid box)",           NULL        },
+  { 102, -1, 0, "tsi",            "surface temperature of ice",                "K"          },
+  { 103, -1, 0, "tsw",            "surface temperature of water",              "K"          },
+  { 104, -1, 0, "ustri",          "zonal      wind stress over ice",           "Pa"         },
+  { 105, -1, 0, "vstri",          "meridional wind stress over ice",           "Pa"         },
+  { 106, -1, 0, "ustrw",          "zonal      wind stress over water",         "Pa"         },
+  { 107, -1, 0, "vstrw",          "meridional wind stress over water",         "Pa"         },
+  { 108, -1, 0, "ustrl",          "zonal      wind stress over land",          "Pa"         },
+  { 109, -1, 0, "vstrl",          "meridional wind stress over land",          "Pa"         },
+  { 110, -1, 0, "ahfliac",        "latent heat flux over ice",                 "W m-2"      },
+  { 111, -1, 0, "ahflwac",        "latent heat flux over water",               "W m-2"      },
+  { 112, -1, 0, "ahfllac",        "latent heat flux over land",                "W m-2"      },
+  { 113, -1, 0, "evapiac",        "evaporation over ice",                      "kg m-2 s-1" },
+  { 114, -1, 0, "evapwac",        "evaporation over water",                    "kg m-2 s-1" },
+  { 115, -1, 0, "evaplac",        "evaporation over land",                     "kg m-2 s-1" },
+  { 116, -1, 0, "az0i",           "roughness length over ice",                 "m"          },
+  { 117, -1, 0, "az0w",           "roughness length over water",               "m"          },
+  { 118, -1, 0, "az0l",           "roughness length over land",                "m"          },
+  { 119, -1, 0, "ahfsiac",        "sensible heat flux over ice",               "W m-2"      },
+  { 120, -1, 0, "ahfswac",        "sensible heat flux over water",             "W m-2"      },
+  { 121, -1, 0, "ahfslac",        "sensible heat flux over land",              "W m-2"      },
+  { 122, -1, 0, "alsoi",          "albedo of ice",                              NULL        },
+  { 123, -1, 0, "alsow",          "albedo of water",                            NULL        },
+  { 124, -1, 0, "alsol",          "albedo of land",                             NULL        },
+  { 125, -1, 0, "ahfice",         "conductive heat flux",                      "W m-2"      },
+  { 126, -1, 0, "qres",           "residual heat flux for melting sea ice",    "W m-2"      },
+  { 127, -1, 0, "alake",          "lake fraction of grid box",                 "fraction"   },
+  { 128, -1, 0, "rintop",         "low level inversion",                        NULL        },
+  { 129, -1, 0, "geosp",          "surface geopotential (orography)",          "m^2/s^2"    },
+  { 130, -1, 0, "t",              "temperature",                               "K"          },
+  { 131, -1, 0, "u",              "u-velocity",                                "m/s"        },
+  { 132, -1, 0, "v",              "v-velocity",                                "m/s"        },
+  { 133, -1, 0, "q",              "specific humidity",                         "kg/kg"      },
+  { 134, -1, 0, "aps",            "surface pressure",                          "Pa"         },
+  { 135, -1, 0, "omega",          "vertical velocity",                         "Pa/s"       },
+  { 136, -1, 0, "acdnc",          "cloud droplet number concentration",        "1 m-3"      },
+  { 137, -1, 0, "apmeb",          "vert. integr. tendencies of water",         "kg m-2 s-1" },
+  { 138, -1, 0, "svo",            "vorticity",                                 "1/s"        },
+  { 139, -1, 0, "tslm1",          "surface temperature of land",               "K"          },
+  { 140, -1, 0, "ws",             "soil wetness",                              "m"          },
+  { 141, -1, 0, "sn",             "snow depth",                                "m"          },
+  { 142, -1, 0, "aprl",           "large scale precipitation",                 "kg m-2 s-1" },
+  { 143, -1, 0, "aprc",           "convective  precipitation",                 "kg m-2 s-1" },
+  { 144, -1, 0, "aprs",           "snow fall",                                 "kg m-2 s-1" },
+  { 145, -1, 0, "vdis",           "boundary layer dissipation",                "W m-2"      },
+  { 146, -1, 0, "ahfs",           "sensible heat flux",                        "W m-2"      },
+  { 147, -1, 0, "ahfl",           "latent heat flux",                          "W m-2"      },
+  { 148, -1, 0, "stream",         "streamfunction",                            "m^2/s"      },
+  { 149, -1, 0, "velopot",        "velocity potential",                        "m^2/s"      },
+  { 150, -1, 0, "xivi",           "vertically integrated cloud ice",           "kg m-2"     },
+  { 151, -1, 0, "slp",            "mean sea level pressure",                   "Pa"         },
+  { 152, -1, 0, "lsp",            "log surface pressure",                       NULL        },
+  { 153, -1, 0, "xl",             "cloud water",                               "kg/kg"      },
+  { 154, -1, 0, "xi",             "cloud ice",                                 "kg/kg"      },
+  { 155, -1, 0, "sd",             "divergence",                                "1/s"        },
+  { 156, -1, 0, "geopoth",        "geopotential height",                       "m"          },
+  { 157, -1, 0, "rhumidity",      "relative humidity",                         "fraction"   },
+  { 158, -1, 0, "var158",         "tendency of surface pressure",              "Pa/s"       },
+  { 159, -1, 0, "wind10w",        "10m windspeed over water",                  "m/s"        },
+  { 160, -1, 0, "runoff",         "surface runoff and drainage",               "kg m-2 s-1" },
+  { 161, -1, 0, "drain",          "drainage",                                  "kg m-2 s-1" },
+  { 162, -1, 0, "aclc",           "cloud cover",                                NULL        },
+  { 163, -1, 0, "aclcv",          "total cloud cover",                          NULL        },
+  { 164, -1, 0, "aclcov",         "total cloud cover (mean)",                   NULL        },
+  { 165, -1, 0, "u10",            "10m u-velocity",                            "m/s"        },
+  { 166, -1, 0, "v10",            "10m v-velocity",                            "m/s"        },
+  { 167, -1, 0, "temp2",          "2m temperature",                            "K"          },
+  { 168, -1, 0, "dew2",           "2m dew point temperature",                  "K"          },
+  { 169, -1, 0, "tsurf",          "surface temperature",                       "K"          },
+  { 170, -1, 0, "xvar",           "variance of total water amount qv+qi+ql",   "kg/kg"      },
+  { 171, -1, 0, "wind10",         "10m windspeed",                             "m/s"        },
+  { 172, -1, 0, "slm",            "land sea mask (1. = land, 0. = sea/lakes)",  NULL        },
+  { 173, -1, 0, "az0",            "roughness length",                          "m"          },
+  { 174, -1, 0, "alb",            "surface background albedo",                  NULL        },
+  { 175, -1, 0, "albedo",         "surface albedo",                             NULL        },
+  { 176, -1, 0, "srads",          "net surface solar radiation",               "W m-2"      },
+  { 177, -1, 0, "trads",          "net surface thermal radiation",             "W m-2"      },
+  { 178, -1, 0, "srad0",          "net top solar radiation",                   "W m-2"      },
+  { 179, -1, 0, "trad0",          "top thermal radiation (OLR)",               "W m-2"      },
+  { 180, -1, 0, "ustr",           "u-stress",                                  "Pa"         },
+  { 181, -1, 0, "vstr",           "v-stress",                                  "Pa"         },
+  { 182, -1, 0, "evap",           "evaporation",                               "kg m-2 s-1" },
+  { 183, -1, 0, "xskew",          "skewness of total water amount qv+qi+ql",    NULL        },
+  { 184, -1, 0, "srad0d",         "top incoming solar radiation",              "W m-2"      },
+  { 185, -1, 0, "srafs",          "net surf. solar radiation   (clear sky)",   "W m-2"      },
+  { 186, -1, 0, "trafs",          "net surf. thermal radiation (clear sky)",   "W m-2"      },
+  { 187, -1, 0, "sraf0",          "net top solar radiation     (clear sky)",   "W m-2"      },
+  { 188, -1, 0, "traf0",          "net top thermal radiation   (clear sky)",   "W m-2"      },
+  { 189, -1, 0, "sclfs",          "surface solar cloud forcing",               "W m-2"      },
+  { 190, -1, 0, "tclfs",          "surface thermal cloud forcing",             "W m-2"      },
+  { 191, -1, 0, "sclf0",          "SW top cloud forcing (178-187)",            "W m-2"      },
+  { 192, -1, 0, "tclf0",          "LW top cloud forcing (179-188)",            "W m-2"      },
+  { 193, -1, 0, "wl",             "skin reservoir content",                    "m"          },
+  { 194, -1, 0, "slf",            "sea land fraction",                          NULL        },
+  { 195, -1, 0, "ustrgw",         "u-gravity wave stress",                     "Pa"         },
+  { 196, -1, 0, "vstrgw",         "v-gravity wave stress",                     "Pa"         },
+  { 197, -1, 0, "vdisgw",         "gravity wave dissipation",                  "W m-2"      },
+  { 198, -1, 0, "vgrat",          "vegetation ratio",                           NULL        },
+  { 199, -1, 0, "orostd",         "orographic standard deviation",             "m"          },
+  { 200, -1, 0, "vlt",            "leaf area index",                            NULL        },
+  { 201, -1, 0, "t2max",          "maximum 2m-temperature",                    "K"          },
+  { 202, -1, 0, "t2min",          "minimum 2m-temperature",                    "K"          },
+  { 203, -1, 0, "srad0u",         "top solar radiation upward",                "W m-2"      },
+  { 204, -1, 0, "sradsu",         "surface solar radiation upward",            "W m-2"      },
+  { 205, -1, 0, "tradsu",         "surface thermal radiation upward",          "W m-2"      },
+  { 206, -1, 0, "grndflux",       "surface ground heat flux",                   NULL        },
+  { 207, -1, 0, "tsoil",          "deep soil temperatures (5 layers)",         "K"          },
+  { 208, -1, 0, "ahfcon",         "conductive heat flux through ice",          "W m-2"      },
+  { 209, -1, 0, "ahfres",         "melting of ice",                            "W m-2"      },
+  { 210, -1, 0, "seaice",         "ice cover (fraction of 1-SLM)",              NULL        },
+  { 211, -1, 0, "siced",          "ice depth",                                 "m"          },
+  { 212, -1, 0, "forest",         "forest fraction",                            NULL        },
+  { 213, -1, 0, "gld",            "glacier depth",                             "m"          },
+  { 214, -1, 0, "sni",            "water equivalent of snow on ice",           "m"          },
+  { 215, -1, 0, "rogl",           "glacier runoff",                            "kg m-2 s-1" },
+  { 216, -1, 0, "wimax",          "maximum 10m-wind speed",                    "m/s"        },
+  { 217, -1, 0, "topmax",         "maximum height of convective cloud tops",   "Pa"         },
+  { 218, -1, 0, "snmel",          "snow melt",                                 "kg m-2 s-1" },
+  { 219, -1, 0, "runtoc",         "surface runoff into ocean",                 "kg m-2 s-1" },
+  { 220, -1, 0, "runlnd",         "surface runoff not running into ocean",     "kg m-2 s-1" },
+  { 221, -1, 0, "apmegl",         "P-E over land ice",                         "kg m-2 s-1" },
+  { 222, -1, 0, "snacl",          "snow accumulation over land",               "kg m-2 s-1" },
+  { 223, -1, 0, "aclcac",         "cloud cover",                                NULL        },
+  { 224, -1, 0, "tke",            "turbulent kinetic energy",                  "m^2/s^2"    },
+  { 225, -1, 0, "tkem1",          "turbulent kinetic energy (t-1)",            "m^2/s^2"    },
+  { 226, -1, 0, "fao",            "FAO data set (soil data flags)",            "0...5"      },
+  { 227, -1, 0, "rgcgn",          "heat capacity of soil",                      NULL        },
+  { 228, -1, 0, "sodif",          "diffusivity of soil and land ice",          "m^2/s"      },
+  { 229, -1, 0, "wsmx",           "field capacity of soil",                    "m"          },
+  { 230, -1, 0, "qvi",            "vertically integrated water vapor",         "kg m-2"     },
+  { 231, -1, 0, "xlvi",           "vertically integrated cloud water",         "kg m-2"     },
+  { 232, -1, 0, "glac",           "fraction of land covered by glaciers",       NULL        },
+  { 233, -1, 0, "snc",            "snow depth at the canopy",                  "m"          },
+  { 234, -1, 0, "rtype",          "type of convection",                        "0...3"      },
+  { 235, -1, 0, "abso4",          "antropogenic sulfur burden",                "kg m-2"     },
+  { 236, -1, 0, "ao3",            "ipcc ozone",                                "kg m-2"     },
+  { 237, -1, 0, "tropo",          "WMO defined tropopause height",             "Pa"         },
+  { 259, -1, 0, "windspeed",      "windspeed (sqrt(u^2+v^2))",                 "m/s"        },
+  { 260, -1, 0, "precip",         "total precipitation  (142+143)",            "kg m-2 s-1" },
+  { 261, -1, 0, "net_top",        "total top radiation  (178+179)",            "W m-2"      },
+  { 262, -1, 0, "net_bot",        "total surface radiation (176+177)",         "W m-2"      },
+  { 272, -1, 0, "mastfru",        "mass stream function",                      "kg/s"       },
 };
 
-static const PAR mpiom1[] = {
-  {   2, 0, "THO",      "temperature",                     "C"        },
-  {   5, 0, "SAO",      "salinity",                        "psu"      },
-  {   3, 0, "UKO",      "zon. velocity",                   "m/s"      },
-  {   4, 0, "VKE",      "mer. velocity",                   "m/s"      },
-  { 303, 0, "UKOMFL",   "zon. velocity (divergence free)", "m/s"      },
-  { 304, 0, "VKEMFL",   "mer. velocity (divergence free)", "m/s"      },
-  {   7, 0, "WO",       "ver. velocity",                   "m/s"      },
-  {   8, 0, "RHO",      "insitu density",                  "kg/m**3"  },
-  {   6, 0, "PO",       "pressure",                        "Pa"       },
-  {  67, 0, "EMINPO",   "freshwaterflux by restoring",     "m/s"      },
-  {  70, 0, "FLUM",     "total heatflux",                  "W/m**2"   },
-  {  79, 0, "PEM",      "total freshwaterflux",            "m/s"      },
-  {  13, 0, "SICTHO",   "ice thickness",                   "m"        },
-  {  15, 0, "SICOMO",   "ice compactness",                 "frac."    },
-  {  35, 0, "SICUO",    "zon. ice velocity",               "m/s"      },
-  {  36, 0, "SICVE",    "mer. ice velocity",               "m/s"      },
-  {  92, 0, "TAFO",     "surface air temperature",         "C"        },
-  { 164, 0, "FCLOU",    "cloud cover",                      NULL      },
-  {  52, 0, "TXO",      "surface u-stress",                "Pa/1025." },
-  {  53, 0, "TYE",      "surface v-stress",                "Pa/1025." },
-  { 260, 0, "FPREC",    "prescr. precipitation",           "m/s"      },
-  {  80, 0, "FSWR",     "downward shortwave rad.",         "W/m**2"   },
-  {  81, 0, "FTDEW",    "dewpoint temperature",            "K"        },
-  { 171, 0, "FU10",     "10m windspeed",                   "m/s"      },
-  { 141, 0, "SICSNO",   "snow thickness",                  "m"        },
-  { 176, 0, "QSWO",     "heat flux shortwave",             "W/m**2"   },
-  { 177, 0, "QLWO",     "heat flux longwave",              "W/m**2"   },
-  { 147, 0, "QLAO",     "heat flux latent",                "W/m**2"   },
-  { 146, 0, "QSEO",     "heat flux sensible",              "W/m**2"   },
-  {  65, 0, "PRECO",    "net freshwater flux + runoff",    "m/s"      },
-  {   1, 0, "ZO",       "sealevel",                        "m"        },
-  {  82, 0, "Z1O",      "sealevel change",                 "m"        },
-  {  69, 0, "KCONDEP",  "depth of convection",             "level"    },
-  {  27, 0, "PSIUWE",   "hor. bar. streamfunction",        "Sv"       },
-  {  83, 0, "AMLD",     "mixed layer depth",               "m"        },
-  { 172, 0, "WETO",     "landseamask (pressure points)",    NULL      },
-  { 507, 0, "AMSUE",    "landseamask (vector points v)",    NULL      },
-  { 508, 0, "AMSUO",    "landseamask (vector points u)",    NULL      },
-  {  84, 0, "DEPTO",    "depth at pressure points",        "m"        },
-  { 484, 0, "DEUTO",    "depth at vector points (u)",      "m"        },
-  { 584, 0, "DEUTE",    "depth at vector points (v)",      "m"        },
-  { 184, 0, "DDUO",     "level thickness (vector u )",     "m"        },
-  { 284, 0, "DDUE",     "level thickness (vector v )",     "m"        },
-  { 384, 0, "DDPO",     "level thickness (pressure )",     "m"        },
-  {  85, 0, "DLXP",     "grid distance x",                 "m"        },
-  {  86, 0, "DLYP",     "grid distance y",                 "m"        },
-  { 185, 0, "DLXU",     "grid distance x  (vector u)",     "m"        },
-  { 186, 0, "DLYU",     "grid distance y  (vector u)",     "m"        },
-  { 285, 0, "DLXV",     "grid distance x  (vector v)",     "m"        },
-  { 286, 0, "DLYV",     "grid distance y  (vector v)",     "m"        },
-  {  54, 0, "GILA",     "latitude in radiants",            "rad"      },
-  {  55, 0, "GIPH",     "longitude in radiants",           "rad"      },
-  { 354, 0, "ALAT",     "latitude in degrees (pressure)",  "deg"      },
-  { 355, 0, "ALON",     "longitude in degrees (pressure)", "deg"      },
-  { 154, 0, "ALATU",    "latitude in degrees (vector u)",  "deg"      },
-  { 155, 0, "ALONU",    "longitude in degrees (vector u)", "deg"      },
-  { 254, 0, "ALATV",    "latitude in degrees (vector v)",  "deg"      },
-  { 255, 0, "ALONV",    "longitude in degrees (vector v)", "deg"      },
-  { 110, 0, "AVO",      "vertical impuls diffusion",       "m**2/s"   },
-  { 111, 0, "DVO",      "vertical T,S diffusion",          "m**2/s"   },
-  { 142, 0, "SICTRU",   "seaice transport x",              "m**2/s"   },
-  { 143, 0, "SICTRV",   "seaice transport y",              "m**2/s"   },
-  { 612, 0, "WTMIX",    "wind mixing",                     "m**2/s"   },
-  { 183, 0, "zmld",     "mixed layer depth (SJ)",          "m"        },
-  { 207, 0, "WGO",      "GM vertical velocity",            "m/s"      },
-  { 305, 0, "rivrun",   "RiverRunoff",                     "m/s"      },
-  { 158, 0, "TMCDO",    "mon. mean depth of convection",   "level"    },
-  { 247, 0, "DQSWO",    "heatflux sw over water",          "W/m**2"   },
-  { 248, 0, "DQLWO",    "heatflux lw over water",          "W/m**2"   },
-  { 249, 0, "DQSEO",    "heatflux se over water",          "W/m**2"   },
-  { 250, 0, "DQLAO",    "heatflux la over water",          "W/m**2"   },
-  { 251, 0, "DQTHO",    "heatflux net over water",         "W/m**2"   },
-  { 252, 0, "DQSWI",    "heatflux sw over seaice",         "W/m**2"   },
-  { 253, 0, "DQLWI",    "heatflux lw over seaice",         "W/m**2"   },
-  { 254, 0, "DQSEI",    "heatflux se over seaice",         "W/m**2"   },
-  { 255, 0, "DQLAI",    "heatflux la over seaice",         "W/m**2"   },
-  { 256, 0, "DQTHI",    "heatflux net over seaice",        "W/m**2"   },
-  { 257, 0, "DTICEO",   "Equi. temp over seaice",          "K"        },
-  { 270, 0, "AOFLNHWO", "oasis net heat flux water",       "W/m**2"   },
-  { 271, 0, "AOFLSHWO", "oasis downward short wave",       "W/m**2"   },
-  { 272, 0, "AOFLRHIO", "oasis residual heat flux ice",    "W/m**2"   },
-  { 273, 0, "AOFLCHIO", "oasis conduct. heat flux ice",    "W/m**2"   },
-  { 274, 0, "AOFLFRWO", "oasis fluid fresh water flux",    "m/s"      },
-  { 275, 0, "AOFLFRIO", "oasis solid fresh water flux",    "m/s"      },
-  { 276, 0, "AOFLTXWO", "oasis wind stress water x",       "Pa/102"   },
-  { 277, 0, "AOFLTYWO", "oasis wind stress water y",       "Pa/102"   },
-  { 278, 0, "AOFLTXIO", "oasis wind stress ice x",         "Pa/102"   },
-  { 279, 0, "AOFLTYIO", "oasis wind stress ice x",         "Pa/102"   },
-  { 280, 0, "AOFLWSVO", "oasis wind speed",                "m/s"      },
+static const param_type mpiom1[] = {
+  {   2, -1, 0, "THO",      "temperature",                     "C"        },
+  {   5, -1, 0, "SAO",      "salinity",                        "psu"      },
+  {   3, -1, 0, "UKO",      "zon. velocity",                   "m/s"      },
+  {   4, -1, 0, "VKE",      "mer. velocity",                   "m/s"      },
+  { 303, -1, 0, "UKOMFL",   "zon. velocity (divergence free)", "m/s"      },
+  { 304, -1, 0, "VKEMFL",   "mer. velocity (divergence free)", "m/s"      },
+  {   7, -1, 0, "WO",       "ver. velocity",                   "m/s"      },
+  {   8, -1, 0, "RHO",      "insitu density",                  "kg/m**3"  },
+  {   6, -1, 0, "PO",       "pressure",                        "Pa"       },
+  {  67, -1, 0, "EMINPO",   "freshwaterflux by restoring",     "m/s"      },
+  {  70, -1, 0, "FLUM",     "total heatflux",                  "W/m**2"   },
+  {  79, -1, 0, "PEM",      "total freshwaterflux",            "m/s"      },
+  {  13, -1, 0, "SICTHO",   "ice thickness",                   "m"        },
+  {  15, -1, 0, "SICOMO",   "ice compactness",                 "frac."    },
+  {  35, -1, 0, "SICUO",    "zon. ice velocity",               "m/s"      },
+  {  36, -1, 0, "SICVE",    "mer. ice velocity",               "m/s"      },
+  {  92, -1, 0, "TAFO",     "surface air temperature",         "C"        },
+  { 164, -1, 0, "FCLOU",    "cloud cover",                      NULL      },
+  {  52, -1, 0, "TXO",      "surface u-stress",                "Pa/1025." },
+  {  53, -1, 0, "TYE",      "surface v-stress",                "Pa/1025." },
+  { 260, -1, 0, "FPREC",    "prescr. precipitation",           "m/s"      },
+  {  80, -1, 0, "FSWR",     "downward shortwave rad.",         "W/m**2"   },
+  {  81, -1, 0, "FTDEW",    "dewpoint temperature",            "K"        },
+  { 171, -1, 0, "FU10",     "10m windspeed",                   "m/s"      },
+  { 141, -1, 0, "SICSNO",   "snow thickness",                  "m"        },
+  { 176, -1, 0, "QSWO",     "heat flux shortwave",             "W/m**2"   },
+  { 177, -1, 0, "QLWO",     "heat flux longwave",              "W/m**2"   },
+  { 147, -1, 0, "QLAO",     "heat flux latent",                "W/m**2"   },
+  { 146, -1, 0, "QSEO",     "heat flux sensible",              "W/m**2"   },
+  {  65, -1, 0, "PRECO",    "net freshwater flux + runoff",    "m/s"      },
+  {   1, -1, 0, "ZO",       "sealevel",                        "m"        },
+  {  82, -1, 0, "Z1O",      "sealevel change",                 "m"        },
+  {  69, -1, 0, "KCONDEP",  "depth of convection",             "level"    },
+  {  27, -1, 0, "PSIUWE",   "hor. bar. streamfunction",        "Sv"       },
+  {  83, -1, 0, "AMLD",     "mixed layer depth",               "m"        },
+  { 172, -1, 0, "WETO",     "landseamask (pressure points)",    NULL      },
+  { 507, -1, 0, "AMSUE",    "landseamask (vector points v)",    NULL      },
+  { 508, -1, 0, "AMSUO",    "landseamask (vector points u)",    NULL      },
+  {  84, -1, 0, "DEPTO",    "depth at pressure points",        "m"        },
+  { 484, -1, 0, "DEUTO",    "depth at vector points (u)",      "m"        },
+  { 584, -1, 0, "DEUTE",    "depth at vector points (v)",      "m"        },
+  { 184, -1, 0, "DDUO",     "level thickness (vector u )",     "m"        },
+  { 284, -1, 0, "DDUE",     "level thickness (vector v )",     "m"        },
+  { 384, -1, 0, "DDPO",     "level thickness (pressure )",     "m"        },
+  {  85, -1, 0, "DLXP",     "grid distance x",                 "m"        },
+  {  86, -1, 0, "DLYP",     "grid distance y",                 "m"        },
+  { 185, -1, 0, "DLXU",     "grid distance x  (vector u)",     "m"        },
+  { 186, -1, 0, "DLYU",     "grid distance y  (vector u)",     "m"        },
+  { 285, -1, 0, "DLXV",     "grid distance x  (vector v)",     "m"        },
+  { 286, -1, 0, "DLYV",     "grid distance y  (vector v)",     "m"        },
+  {  54, -1, 0, "GILA",     "latitude in radiants",            "rad"      },
+  {  55, -1, 0, "GIPH",     "longitude in radiants",           "rad"      },
+  { 354, -1, 0, "ALAT",     "latitude in degrees (pressure)",  "deg"      },
+  { 355, -1, 0, "ALON",     "longitude in degrees (pressure)", "deg"      },
+  { 154, -1, 0, "ALATU",    "latitude in degrees (vector u)",  "deg"      },
+  { 155, -1, 0, "ALONU",    "longitude in degrees (vector u)", "deg"      },
+  { 254, -1, 0, "ALATV",    "latitude in degrees (vector v)",  "deg"      },
+  { 255, -1, 0, "ALONV",    "longitude in degrees (vector v)", "deg"      },
+  { 110, -1, 0, "AVO",      "vertical impuls diffusion",       "m**2/s"   },
+  { 111, -1, 0, "DVO",      "vertical T,S diffusion",          "m**2/s"   },
+  { 142, -1, 0, "SICTRU",   "seaice transport x",              "m**2/s"   },
+  { 143, -1, 0, "SICTRV",   "seaice transport y",              "m**2/s"   },
+  { 612, -1, 0, "WTMIX",    "wind mixing",                     "m**2/s"   },
+  { 183, -1, 0, "zmld",     "mixed layer depth (SJ)",          "m"        },
+  { 207, -1, 0, "WGO",      "GM vertical velocity",            "m/s"      },
+  { 305, -1, 0, "rivrun",   "RiverRunoff",                     "m/s"      },
+  { 158, -1, 0, "TMCDO",    "mon. mean depth of convection",   "level"    },
+  { 247, -1, 0, "DQSWO",    "heatflux sw over water",          "W/m**2"   },
+  { 248, -1, 0, "DQLWO",    "heatflux lw over water",          "W/m**2"   },
+  { 249, -1, 0, "DQSEO",    "heatflux se over water",          "W/m**2"   },
+  { 250, -1, 0, "DQLAO",    "heatflux la over water",          "W/m**2"   },
+  { 251, -1, 0, "DQTHO",    "heatflux net over water",         "W/m**2"   },
+  { 252, -1, 0, "DQSWI",    "heatflux sw over seaice",         "W/m**2"   },
+  { 253, -1, 0, "DQLWI",    "heatflux lw over seaice",         "W/m**2"   },
+  { 254, -1, 0, "DQSEI",    "heatflux se over seaice",         "W/m**2"   },
+  { 255, -1, 0, "DQLAI",    "heatflux la over seaice",         "W/m**2"   },
+  { 256, -1, 0, "DQTHI",    "heatflux net over seaice",        "W/m**2"   },
+  { 257, -1, 0, "DTICEO",   "Equi. temp over seaice",          "K"        },
+  { 270, -1, 0, "AOFLNHWO", "oasis net heat flux water",       "W/m**2"   },
+  { 271, -1, 0, "AOFLSHWO", "oasis downward short wave",       "W/m**2"   },
+  { 272, -1, 0, "AOFLRHIO", "oasis residual heat flux ice",    "W/m**2"   },
+  { 273, -1, 0, "AOFLCHIO", "oasis conduct. heat flux ice",    "W/m**2"   },
+  { 274, -1, 0, "AOFLFRWO", "oasis fluid fresh water flux",    "m/s"      },
+  { 275, -1, 0, "AOFLFRIO", "oasis solid fresh water flux",    "m/s"      },
+  { 276, -1, 0, "AOFLTXWO", "oasis wind stress water x",       "Pa/102"   },
+  { 277, -1, 0, "AOFLTYWO", "oasis wind stress water y",       "Pa/102"   },
+  { 278, -1, 0, "AOFLTXIO", "oasis wind stress ice x",         "Pa/102"   },
+  { 279, -1, 0, "AOFLTYIO", "oasis wind stress ice x",         "Pa/102"   },
+  { 280, -1, 0, "AOFLWSVO", "oasis wind speed",                "m/s"      },
 };
 
-static const PAR ecmwf[] = {
-  {   1, 0, "STRF",     "Stream function",                                            "m**2 s**-1"            },
-  {   2, 0, "VPOT",     "Velocity potential",                                         "m**2 s**-1"            },
-  {   3, 0, "PT",       "Potential temperature",                                      "K"                     },
-  {   4, 0, "EQPT",     "Equivalent potential temperature",                           "K"                     },
-  {   5, 0, "SEPT",     "Saturated equivalent potential temperature",                 "K"                     },
-  {  11, 0, "UDVW",     "U component of divergent wind",                              "m s**-1"               },
-  {  12, 0, "VDVW",     "V component of divergent wind",                              "m s**-1"               },
-  {  13, 0, "URTW",     "U component of rotational wind",                             "m s**-1"               },
-  {  14, 0, "VRTW",     "V component of rotational wind",                             "m s**-1"               },
-  {  21, 0, "UCTP",     "Unbalanced component of temperature",                        "K"                     },
-  {  22, 0, "UCLN",     "Unbalanced component of logarithm of surface pressure",       NULL                   },
-  {  23, 0, "UCDV",     "Unbalanced component of divergence",                         "s**-1"                 },
-  {  26, 0, "CL",       "Lake cover",                                                  NULL                   },
-  {  27, 0, "CVL",      "Low vegetation cover",                                        NULL                   },
-  {  28, 0, "CVH",      "High vegetation cover",                                       NULL                   },
-  {  29, 0, "TVL",      "Type of low vegetation",                                      NULL                   },
-  {  30, 0, "TVH",      "Type of high vegetation",                                     NULL                   },
-  {  31, 0, "CI",       "Sea-ice cover",                                               NULL                   },
-  {  32, 0, "ASN",      "Snow albedo",                                                 NULL                   },
-  {  33, 0, "RSN",      "Snow density kg",                                            "m**-3"                 },
-  {  34, 0, "SSTK",     "Sea surface temperature",                                    "K"                     },
-  {  35, 0, "ISTL1",    "Ice surface temperature layer 1",                            "K"                     },
-  {  36, 0, "ISTL2",    "Ice surface temperature layer 2",                            "K"                     },
-  {  37, 0, "ISTL3",    "Ice surface temperature layer 3",                            "K"                     },
-  {  38, 0, "ISTL4",    "Ice surface temperature layer 4",                            "K"                     },
-  {  39, 0, "SWVL1",    "Volumetric soil water layer 1",                              "m**3 m**-3"            },
-  {  40, 0, "SWVL2",    "Volumetric soil water layer 2",                              "m**3 m**-3"            },
-  {  41, 0, "SWVL3",    "Volumetric soil water layer 3",                              "m**3 m**-3"            },
-  {  42, 0, "SWVL4",    "Volumetric soil water layer 4",                              "m**3 m**-3"            },
-  {  43, 0, "SLT",      "Soil type",                                                   NULL                   },
-  {  44, 0, "ES",       "Snow evaporation m of water",                                 NULL                   },
-  {  45, 0, "SMLT",     "Snowmelt m of water",                                         NULL                   },
-  {  46, 0, "SDUR",     "Solar duration",                                             "s"                     },
-  {  47, 0, "DSRP",     "Direct solar radiation",                                     "w m**-2"               },
-  {  48, 0, "MAGSS",    "Magnitude of surface stress",                                "N m**-2 s"             },
-  {  49, 0, "WG10",     "Wind gust at 10 metres",                                     "m s**-1"               },
-  {  50, 0, "LSPF",     "Large-scale precipitation fraction",                         "s"                     },
-  {  51, 0, "MX2T24",   "Maximum 2 metre temperature",                                "K"                     },
-  {  52, 0, "MN2T24",   "Minimum 2 metre temperature",                                "K"                     },
-  {  53, 0, "MONT",     "Montgomery potential",                                       "m**2 s**-2"            },
-  {  54, 0, "PRES",     "Pressure",                                                   "Pa"                    },
-  {  55, 0, "MEAN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
-  {  56, 0, "MEAN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
-  {  60, 0, "PV",       "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
-  { 127, 0, "AT",       "Atmospheric tide",                                            NULL                   },
-  { 128, 0, "BV",       "Budget values",                                               NULL                   },
-  { 129, 0, "Z",        "Geopotential",                                               "m**2 s**-2"            },
-  { 130, 0, "T",        "Temperature",                                                "K"                     },
-  { 131, 0, "U",        "U velocity",                                                 "m s**-1"               },
-  { 132, 0, "V",        "V velocity",                                                 "m s**-1"               },
-  { 133, 0, "Q",        "Specific humidity",                                          "kg kg**-1"             },
-  { 134, 0, "SP",       "Surface pressure",                                           "Pa"                    },
-  { 135, 0, "W",        "Vertical velocity",                                          "Pa s**-1"              },
-  { 136, 0, "TCW",      "Total column water",                                         "kg m**-2"              },
-  { 137, 0, "TCWV",     "Total column water vapour",                                  "kg m**-2"              },
-  { 138, 0, "VO",       "Vorticity (relative)",                                       "s**-1"                 },
-  { 139, 0, "STL1",     "Soil temperature level 1",                                   "K"                     },
-  { 140, 0, "SWL1",     "Soil wetness level 1 m of water",                             NULL                   },
-  { 141, 0, "SD",       "Snow depth         1 m of water equivalent",                  NULL                   },
-  { 142, 0, "LSP",      "Stratiform precipitation (Large scale precipitation)",       "m"                     },
-  { 143, 0, "CP",       "Convective precipitation",                                   "m"                     },
-  { 144, 0, "SF",       "Snowfall (convective + stratiform)",                         "m"                     },
-  { 145, 0, "BLD",      "Boundary layer dissipation",                                 "W m**-2 s"             },
-  { 146, 0, "SSHF",     "Surface sensible heat flux",                                 "W m**-2 s"             },
-  { 147, 0, "SLHF",     "Surface latent heat flux",                                   "W m**-2 s"             },
-  { 148, 0, "CHNK",     "Charnock",                                                    NULL                   },
-  { 149, 0, "SNR",      "Surface net radiation",                                      "W m**-2 s"             },
-  { 150, 0, "TNR",      "Top net radiation",                                           NULL                   },
-  { 151, 0, "MSL",      "Mean sea-level pressure",                                    "Pa"                    },
-  { 152, 0, "LNSP",     "Logarithm of surface pressure",                               NULL                   },
-  { 153, 0, "SWHR",     "Short-wave heating rate",                                    "K"                     },
-  { 154, 0, "LWHR",     "Long-wave heating rate",                                     "K"                     },
-  { 155, 0, "D",        "Divergence",                                                 "s**-1"                 },
-  { 156, 0, "GH",       "Height m Geopotential height",                                NULL                   },
-  { 157, 0, "R",        "Relative humidity",                                          "%"                     },
-  { 158, 0, "TSP",      "Tendency of surface pressure",                               "Pa s**-1"              },
-  { 159, 0, "BLH",      "Boundary layer height",                                      "m"                     },
-  { 160, 0, "SDOR",     "Standard deviation of orography",                             NULL                   },
-  { 161, 0, "ISOR",     "Anisotropy of sub-gridscale orography",                       NULL                   },
-  { 162, 0, "ANOR",     "Angle of sub-gridscale orography",                           "rad"                   },
-  { 163, 0, "SLOR",     "Slope of sub-gridscale orography",                            NULL                   },
-  { 164, 0, "TCC",      "Total cloud cover",                                           NULL                   },
-  { 165, 0, "U10M",     "10 metre U wind component",                                  "m s**-1"               },
-  { 166, 0, "V10M",     "10 metre V wind component",                                  "m s**-1"               },
-  { 167, 0, "T2M",      "2 metre temperature",                                        "K"                     },
-  { 168, 0, "D2M",      "2 metre dewpoint temperature",                               "K"                     },
-  { 169, 0, "SSRD",     "Surface solar radiation downwards",                          "W m**-2 s"             },
-  { 170, 0, "STL2",     "Soil temperature level 2",                                   "K"                     },
-  { 171, 0, "SWL2",     "Soil wetness level 2",                                       "m of water"            },
-  { 172, 0, "LSM",      "Land/sea mask",                                               NULL                   },
-  { 173, 0, "SR",       "Surface roughness",                                          "m"                     },
-  { 174, 0, "AL",       "Albedo",                                                      NULL                   },
-  { 175, 0, "STRD",     "Surface thermal radiation downwards",                        "W m**-2 s"             },
-  { 176, 0, "SSR",      "Surface solar radiation",                                    "W m**-2 s"             },
-  { 177, 0, "STR",      "Surface thermal radiation",                                  "W m**-2 s"             },
-  { 178, 0, "TSR",      "Top solar radiation",                                        "W m**-2 s"             },
-  { 179, 0, "TTR",      "Top thermal radiation",                                      "W m**-2 s"             },
-  { 180, 0, "EWSS",     "East/West surface stress",                                   "N m**-2 s"             },
-  { 181, 0, "NSSS",     "North/South surface stress",                                 "N m**-2 s"             },
-  { 182, 0, "E",        "Evaporation",                                                "m of water"            },
-  { 183, 0, "STL3",     "Soil temperature level 3",                                   "K"                     },
-  { 184, 0, "SWL3",     "Soil wetness level 3",                                       "m of water"            },
-  { 185, 0, "CCC",      "Convective cloud cover",                                      NULL                   },
-  { 186, 0, "LCC",      "Low cloud cover",                                             NULL                   },
-  { 187, 0, "MCC",      "Medium cloud cover",                                          NULL                   },
-  { 188, 0, "HCC",      "High cloud cover",                                            NULL                   },
-  { 189, 0, "SUND",     "Sunshine duration",                                          "s"                     },
-  { 190, 0, "EWOV",     "EW component of subgrid orographic variance",                "m**2"                  },
-  { 191, 0, "NSOV",     "NS component of subgrid orographic variance",                "m**2"                  },
-  { 192, 0, "NWOV",     "NWSE component of subgrid orographic variance",              "m**2"                  },
-  { 193, 0, "NEOV",     "NESW component of subgrid orographic variance",              "m**2"                  },
-  { 194, 0, "BTMP",     "Brightness temperature",                                     "K"                     },
-  { 195, 0, "LGWS",     "Lat. component of gravity wave stress",                      "N m**-2 s"             },
-  { 196, 0, "MGWS",     "Meridional component of gravity wave stress",                "N m**-2 s"             },
-  { 197, 0, "GWD",      "Gravity wave dissipation",                                   "W m**-2 s"             },
-  { 198, 0, "SRC",      "Skin reservoir content",                                     "m of water"            },
-  { 199, 0, "VEG",      "Vegetation fraction",                                         NULL                   },
-  { 200, 0, "VSO",      "Variance of sub-gridscale orography",                        "m**2"                  },
-  { 201, 0, "MX2T",     "Maximum 2 metre temperature since previous post-processing", "K"                     },
-  { 202, 0, "MN2T",     "Minimum 2 metre temperature since previous post-processing", "K"                     },
-  { 203, 0, "O3",       "Ozone mass mixing ratio",                                    "kg kg**-1"             },
-  { 204, 0, "PAW",      "Precipiation analysis weights",                               NULL                   },
-  { 205, 0, "RO",       "Runoff",                                                     "m"                     },
-  { 206, 0, "TCO3",     "Total column ozone",                                         "kg m**-2"              },
-  { 207, 0, "WS10",     "10 meter windspeed",                                         "m s**-1"               },
-  { 208, 0, "TSRC",     "Top net solar radiation, clear sky",                         "W m**-2"               },
-  { 209, 0, "TTRC",     "Top net thermal radiation, clear sky",                       "W m**-2"               },
-  { 210, 0, "SSRC",     "Surface net solar radiation, clear sky",                     "W m**-2"               },
-  { 211, 0, "STRC",     "Surface net thermal radiation, clear sky",                   "W m**-2"               },
-  { 212, 0, "SI",       "Solar insolation",                                           "W m**-2"               },
-  { 214, 0, "DHR",      "Diabatic heating by radiation",                              "K"                     },
-  { 215, 0, "DHVD",     "Diabatic heating by vertical diffusion",                     "K"                     },
-  { 216, 0, "DHCC",     "Diabatic heating by cumulus convection",                     "K"                     },
-  { 217, 0, "DHLC",     "Diabatic heating large-scale condensation",                  "K"                     },
-  { 218, 0, "VDZW",     "Vertical diffusion of zonal wind",                           "m s**-1"               },
-  { 219, 0, "VDMW",     "Vertical diffusion of meridional wind",                      "m s**-1"               },
-  { 220, 0, "EWGD",     "EW gravity wave drag tendency",                              "m s**-1"               },
-  { 221, 0, "NSGD",     "NS gravity wave drag tendency",                              "m s**-1"               },
-  { 222, 0, "CTZW",     "Convective tendency of zonal wind",                          "m s**-1"               },
-  { 223, 0, "CTMW",     "Convective tendency of meridional wind",                     "m s**-1"               },
-  { 224, 0, "VDH",      "Vertical diffusion of humidity",                             "kg kg**-1"             },
-  { 225, 0, "HTCC",     "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
-  { 226, 0, "HTLC",     "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
-  { 227, 0, "CRNH",     "Change from removing negative humidity",                     "kg kg**-1"             },
-  { 228, 0, "TP",       "Total precipitation",                                        "m"                     },
-  { 229, 0, "IEWS",     "Instantaneous X surface stress",                             "N m**-2"               },
-  { 230, 0, "INSS",     "Instantaneous Y surface stress",                             "N m**-2"               },
-  { 231, 0, "ISHF",     "Instantaneous surface heat flux",                            "W m**-2"               },
-  { 232, 0, "IE",       "Instantaneous moisture flux",                                "kg m**-2 s"            },
-  { 233, 0, "ASQ",      "Apparent surface humidity",                                  "kg kg**-1"             },
-  { 234, 0, "LSRH",     "Logarithm of surface roughness length for heat",              NULL                   },
-  { 235, 0, "SKT",      "Skin temperature",                                           "K"                     },
-  { 236, 0, "STL4",     "Soil temperature level 4",                                   "K"                     },
-  { 237, 0, "SWL4",     "Soil wetness level 4",                                       "m"                     },
-  { 238, 0, "TSN",      "Temperature of snow layer",                                  "K"                     },
-  { 239, 0, "CSF",      "Convective snowfall",                                        "m of water equivalent" },
-  { 240, 0, "LSF",      "Large-scale snowfall",                                       "m of water equivalent" },
-  { 241, 0, "ACF",      "Accumulated cloud fraction tendency",                         NULL                   },
-  { 242, 0, "ALW",      "Accumulated liquid water tendency",                           NULL                   },
-  { 243, 0, "FAL",      "Forecast albedo",                                             NULL                   },
-  { 244, 0, "FSR",      "Forecast surface roughness",                                 "m"                     },
-  { 245, 0, "FLSR",     "Forecast log of surface roughness for heat",                  NULL                   },
-  { 246, 0, "CLWC",     "Cloud liquid water content",                                 "kg kg**-1"             },
-  { 247, 0, "CIWC",     "Cloud ice water content",                                    "kg kg**-1"             },
-  { 248, 0, "CC",       "Cloud cover",                                                 NULL                   },
-  { 249, 0, "AIW",      "Accumulated ice water tendency",                              NULL                   },
-  { 250, 0, "ICE",      "Ice age",                                                     NULL                   },
-  { 251, 0, "ATTE",     "Adiabatic tendency of temperature",                          "K"                     },
-  { 252, 0, "ATHE",     "Adiabatic tendency of humidity",                             "kg kg**-1"             },
-  { 253, 0, "ATZE",     "Adiabatic tendency of zonal wind",                           "m s**-1"               },
-  { 254, 0, "ATMW",     "Adiabatic tendency of meridional wind",                      "m s**-1"               },
+static const param_type ecmwf[] = {
+  {   1, -1, 0, "STRF",     "Stream function",                                            "m**2 s**-1"            },
+  {   2, -1, 0, "VPOT",     "Velocity potential",                                         "m**2 s**-1"            },
+  {   3, -1, 0, "PT",       "Potential temperature",                                      "K"                     },
+  {   4, -1, 0, "EQPT",     "Equivalent potential temperature",                           "K"                     },
+  {   5, -1, 0, "SEPT",     "Saturated equivalent potential temperature",                 "K"                     },
+  {  11, -1, 0, "UDVW",     "U component of divergent wind",                              "m s**-1"               },
+  {  12, -1, 0, "VDVW",     "V component of divergent wind",                              "m s**-1"               },
+  {  13, -1, 0, "URTW",     "U component of rotational wind",                             "m s**-1"               },
+  {  14, -1, 0, "VRTW",     "V component of rotational wind",                             "m s**-1"               },
+  {  21, -1, 0, "UCTP",     "Unbalanced component of temperature",                        "K"                     },
+  {  22, -1, 0, "UCLN",     "Unbalanced component of logarithm of surface pressure",       NULL                   },
+  {  23, -1, 0, "UCDV",     "Unbalanced component of divergence",                         "s**-1"                 },
+  {  26, -1, 0, "CL",       "Lake cover",                                                  NULL                   },
+  {  27, -1, 0, "CVL",      "Low vegetation cover",                                        NULL                   },
+  {  28, -1, 0, "CVH",      "High vegetation cover",                                       NULL                   },
+  {  29, -1, 0, "TVL",      "Type of low vegetation",                                      NULL                   },
+  {  30, -1, 0, "TVH",      "Type of high vegetation",                                     NULL                   },
+  {  31, -1, 0, "CI",       "Sea-ice cover",                                               NULL                   },
+  {  32, -1, 0, "ASN",      "Snow albedo",                                                 NULL                   },
+  {  33, -1, 0, "RSN",      "Snow density kg",                                            "m**-3"                 },
+  {  34, -1, 0, "SSTK",     "Sea surface temperature",                                    "K"                     },
+  {  35, -1, 0, "ISTL1",    "Ice surface temperature layer 1",                            "K"                     },
+  {  36, -1, 0, "ISTL2",    "Ice surface temperature layer 2",                            "K"                     },
+  {  37, -1, 0, "ISTL3",    "Ice surface temperature layer 3",                            "K"                     },
+  {  38, -1, 0, "ISTL4",    "Ice surface temperature layer 4",                            "K"                     },
+  {  39, -1, 0, "SWVL1",    "Volumetric soil water layer 1",                              "m**3 m**-3"            },
+  {  40, -1, 0, "SWVL2",    "Volumetric soil water layer 2",                              "m**3 m**-3"            },
+  {  41, -1, 0, "SWVL3",    "Volumetric soil water layer 3",                              "m**3 m**-3"            },
+  {  42, -1, 0, "SWVL4",    "Volumetric soil water layer 4",                              "m**3 m**-3"            },
+  {  43, -1, 0, "SLT",      "Soil type",                                                   NULL                   },
+  {  44, -1, 0, "ES",       "Snow evaporation m of water",                                 NULL                   },
+  {  45, -1, 0, "SMLT",     "Snowmelt m of water",                                         NULL                   },
+  {  46, -1, 0, "SDUR",     "Solar duration",                                             "s"                     },
+  {  47, -1, 0, "DSRP",     "Direct solar radiation",                                     "w m**-2"               },
+  {  48, -1, 0, "MAGSS",    "Magnitude of surface stress",                                "N m**-2 s"             },
+  {  49, -1, 0, "WG10",     "Wind gust at 10 metres",                                     "m s**-1"               },
+  {  50, -1, 0, "LSPF",     "Large-scale precipitation fraction",                         "s"                     },
+  {  51, -1, 0, "MX2T24",   "Maximum 2 metre temperature",                                "K"                     },
+  {  52, -1, 0, "MN2T24",   "Minimum 2 metre temperature",                                "K"                     },
+  {  53, -1, 0, "MONT",     "Montgomery potential",                                       "m**2 s**-2"            },
+  {  54, -1, 0, "PRES",     "Pressure",                                                   "Pa"                    },
+  {  55, -1, 0, "MEAN2T24", "Mean 2 metre temperature past 24 hours",                     "K"                     },
+  {  56, -1, 0, "MEAN2D24", "Mean 2 metre dewpoint temperature past 24 hours",            "K"                     },
+  {  60, -1, 0, "PV",       "Potential vorticity",                                        "K m**2 kg**-1 s**-1"   },
+  { 127, -1, 0, "AT",       "Atmospheric tide",                                            NULL                   },
+  { 128, -1, 0, "BV",       "Budget values",                                               NULL                   },
+  { 129, -1, 0, "Z",        "Geopotential",                                               "m**2 s**-2"            },
+  { 130, -1, 0, "T",        "Temperature",                                                "K"                     },
+  { 131, -1, 0, "U",        "U velocity",                                                 "m s**-1"               },
+  { 132, -1, 0, "V",        "V velocity",                                                 "m s**-1"               },
+  { 133, -1, 0, "Q",        "Specific humidity",                                          "kg kg**-1"             },
+  { 134, -1, 0, "SP",       "Surface pressure",                                           "Pa"                    },
+  { 135, -1, 0, "W",        "Vertical velocity",                                          "Pa s**-1"              },
+  { 136, -1, 0, "TCW",      "Total column water",                                         "kg m**-2"              },
+  { 137, -1, 0, "TCWV",     "Total column water vapour",                                  "kg m**-2"              },
+  { 138, -1, 0, "VO",       "Vorticity (relative)",                                       "s**-1"                 },
+  { 139, -1, 0, "STL1",     "Soil temperature level 1",                                   "K"                     },
+  { 140, -1, 0, "SWL1",     "Soil wetness level 1 m of water",                             NULL                   },
+  { 141, -1, 0, "SD",       "Snow depth         1 m of water equivalent",                  NULL                   },
+  { 142, -1, 0, "LSP",      "Stratiform precipitation (Large scale precipitation)",       "m"                     },
+  { 143, -1, 0, "CP",       "Convective precipitation",                                   "m"                     },
+  { 144, -1, 0, "SF",       "Snowfall (convective + stratiform)",                         "m"                     },
+  { 145, -1, 0, "BLD",      "Boundary layer dissipation",                                 "W m**-2 s"             },
+  { 146, -1, 0, "SSHF",     "Surface sensible heat flux",                                 "W m**-2 s"             },
+  { 147, -1, 0, "SLHF",     "Surface latent heat flux",                                   "W m**-2 s"             },
+  { 148, -1, 0, "CHNK",     "Charnock",                                                    NULL                   },
+  { 149, -1, 0, "SNR",      "Surface net radiation",                                      "W m**-2 s"             },
+  { 150, -1, 0, "TNR",      "Top net radiation",                                           NULL                   },
+  { 151, -1, 0, "MSL",      "Mean sea-level pressure",                                    "Pa"                    },
+  { 152, -1, 0, "LNSP",     "Logarithm of surface pressure",                               NULL                   },
+  { 153, -1, 0, "SWHR",     "Short-wave heating rate",                                    "K"                     },
+  { 154, -1, 0, "LWHR",     "Long-wave heating rate",                                     "K"                     },
+  { 155, -1, 0, "D",        "Divergence",                                                 "s**-1"                 },
+  { 156, -1, 0, "GH",       "Height m Geopotential height",                                NULL                   },
+  { 157, -1, 0, "R",        "Relative humidity",                                          "%"                     },
+  { 158, -1, 0, "TSP",      "Tendency of surface pressure",                               "Pa s**-1"              },
+  { 159, -1, 0, "BLH",      "Boundary layer height",                                      "m"                     },
+  { 160, -1, 0, "SDOR",     "Standard deviation of orography",                             NULL                   },
+  { 161, -1, 0, "ISOR",     "Anisotropy of sub-gridscale orography",                       NULL                   },
+  { 162, -1, 0, "ANOR",     "Angle of sub-gridscale orography",                           "rad"                   },
+  { 163, -1, 0, "SLOR",     "Slope of sub-gridscale orography",                            NULL                   },
+  { 164, -1, 0, "TCC",      "Total cloud cover",                                           NULL                   },
+  { 165, -1, 0, "U10M",     "10 metre U wind component",                                  "m s**-1"               },
+  { 166, -1, 0, "V10M",     "10 metre V wind component",                                  "m s**-1"               },
+  { 167, -1, 0, "T2M",      "2 metre temperature",                                        "K"                     },
+  { 168, -1, 0, "D2M",      "2 metre dewpoint temperature",                               "K"                     },
+  { 169, -1, 0, "SSRD",     "Surface solar radiation downwards",                          "W m**-2 s"             },
+  { 170, -1, 0, "STL2",     "Soil temperature level 2",                                   "K"                     },
+  { 171, -1, 0, "SWL2",     "Soil wetness level 2",                                       "m of water"            },
+  { 172, -1, 0, "LSM",      "Land/sea mask",                                               NULL                   },
+  { 173, -1, 0, "SR",       "Surface roughness",                                          "m"                     },
+  { 174, -1, 0, "AL",       "Albedo",                                                      NULL                   },
+  { 175, -1, 0, "STRD",     "Surface thermal radiation downwards",                        "W m**-2 s"             },
+  { 176, -1, 0, "SSR",      "Surface solar radiation",                                    "W m**-2 s"             },
+  { 177, -1, 0, "STR",      "Surface thermal radiation",                                  "W m**-2 s"             },
+  { 178, -1, 0, "TSR",      "Top solar radiation",                                        "W m**-2 s"             },
+  { 179, -1, 0, "TTR",      "Top thermal radiation",                                      "W m**-2 s"             },
+  { 180, -1, 0, "EWSS",     "East/West surface stress",                                   "N m**-2 s"             },
+  { 181, -1, 0, "NSSS",     "North/South surface stress",                                 "N m**-2 s"             },
+  { 182, -1, 0, "E",        "Evaporation",                                                "m of water"            },
+  { 183, -1, 0, "STL3",     "Soil temperature level 3",                                   "K"                     },
+  { 184, -1, 0, "SWL3",     "Soil wetness level 3",                                       "m of water"            },
+  { 185, -1, 0, "CCC",      "Convective cloud cover",                                      NULL                   },
+  { 186, -1, 0, "LCC",      "Low cloud cover",                                             NULL                   },
+  { 187, -1, 0, "MCC",      "Medium cloud cover",                                          NULL                   },
+  { 188, -1, 0, "HCC",      "High cloud cover",                                            NULL                   },
+  { 189, -1, 0, "SUND",     "Sunshine duration",                                          "s"                     },
+  { 190, -1, 0, "EWOV",     "EW component of subgrid orographic variance",                "m**2"                  },
+  { 191, -1, 0, "NSOV",     "NS component of subgrid orographic variance",                "m**2"                  },
+  { 192, -1, 0, "NWOV",     "NWSE component of subgrid orographic variance",              "m**2"                  },
+  { 193, -1, 0, "NEOV",     "NESW component of subgrid orographic variance",              "m**2"                  },
+  { 194, -1, 0, "BTMP",     "Brightness temperature",                                     "K"                     },
+  { 195, -1, 0, "LGWS",     "Lat. component of gravity wave stress",                      "N m**-2 s"             },
+  { 196, -1, 0, "MGWS",     "Meridional component of gravity wave stress",                "N m**-2 s"             },
+  { 197, -1, 0, "GWD",      "Gravity wave dissipation",                                   "W m**-2 s"             },
+  { 198, -1, 0, "SRC",      "Skin reservoir content",                                     "m of water"            },
+  { 199, -1, 0, "VEG",      "Vegetation fraction",                                         NULL                   },
+  { 200, -1, 0, "VSO",      "Variance of sub-gridscale orography",                        "m**2"                  },
+  { 201, -1, 0, "MX2T",     "Maximum 2 metre temperature since previous post-processing", "K"                     },
+  { 202, -1, 0, "MN2T",     "Minimum 2 metre temperature since previous post-processing", "K"                     },
+  { 203, -1, 0, "O3",       "Ozone mass mixing ratio",                                    "kg kg**-1"             },
+  { 204, -1, 0, "PAW",      "Precipiation analysis weights",                               NULL                   },
+  { 205, -1, 0, "RO",       "Runoff",                                                     "m"                     },
+  { 206, -1, 0, "TCO3",     "Total column ozone",                                         "kg m**-2"              },
+  { 207, -1, 0, "WS10",     "10 meter windspeed",                                         "m s**-1"               },
+  { 208, -1, 0, "TSRC",     "Top net solar radiation, clear sky",                         "W m**-2"               },
+  { 209, -1, 0, "TTRC",     "Top net thermal radiation, clear sky",                       "W m**-2"               },
+  { 210, -1, 0, "SSRC",     "Surface net solar radiation, clear sky",                     "W m**-2"               },
+  { 211, -1, 0, "STRC",     "Surface net thermal radiation, clear sky",                   "W m**-2"               },
+  { 212, -1, 0, "SI",       "Solar insolation",                                           "W m**-2"               },
+  { 214, -1, 0, "DHR",      "Diabatic heating by radiation",                              "K"                     },
+  { 215, -1, 0, "DHVD",     "Diabatic heating by vertical diffusion",                     "K"                     },
+  { 216, -1, 0, "DHCC",     "Diabatic heating by cumulus convection",                     "K"                     },
+  { 217, -1, 0, "DHLC",     "Diabatic heating large-scale condensation",                  "K"                     },
+  { 218, -1, 0, "VDZW",     "Vertical diffusion of zonal wind",                           "m s**-1"               },
+  { 219, -1, 0, "VDMW",     "Vertical diffusion of meridional wind",                      "m s**-1"               },
+  { 220, -1, 0, "EWGD",     "EW gravity wave drag tendency",                              "m s**-1"               },
+  { 221, -1, 0, "NSGD",     "NS gravity wave drag tendency",                              "m s**-1"               },
+  { 222, -1, 0, "CTZW",     "Convective tendency of zonal wind",                          "m s**-1"               },
+  { 223, -1, 0, "CTMW",     "Convective tendency of meridional wind",                     "m s**-1"               },
+  { 224, -1, 0, "VDH",      "Vertical diffusion of humidity",                             "kg kg**-1"             },
+  { 225, -1, 0, "HTCC",     "Humidity tendency by cumulus convection",                    "kg kg**-1"             },
+  { 226, -1, 0, "HTLC",     "Humidity tendency large-scale condensation",                 "kg kg**-1"             },
+  { 227, -1, 0, "CRNH",     "Change from removing negative humidity",                     "kg kg**-1"             },
+  { 228, -1, 0, "TP",       "Total precipitation",                                        "m"                     },
+  { 229, -1, 0, "IEWS",     "Instantaneous X surface stress",                             "N m**-2"               },
+  { 230, -1, 0, "INSS",     "Instantaneous Y surface stress",                             "N m**-2"               },
+  { 231, -1, 0, "ISHF",     "Instantaneous surface heat flux",                            "W m**-2"               },
+  { 232, -1, 0, "IE",       "Instantaneous moisture flux",                                "kg m**-2 s"            },
+  { 233, -1, 0, "ASQ",      "Apparent surface humidity",                                  "kg kg**-1"             },
+  { 234, -1, 0, "LSRH",     "Logarithm of surface roughness length for heat",              NULL                   },
+  { 235, -1, 0, "SKT",      "Skin temperature",                                           "K"                     },
+  { 236, -1, 0, "STL4",     "Soil temperature level 4",                                   "K"                     },
+  { 237, -1, 0, "SWL4",     "Soil wetness level 4",                                       "m"                     },
+  { 238, -1, 0, "TSN",      "Temperature of snow layer",                                  "K"                     },
+  { 239, -1, 0, "CSF",      "Convective snowfall",                                        "m of water equivalent" },
+  { 240, -1, 0, "LSF",      "Large-scale snowfall",                                       "m of water equivalent" },
+  { 241, -1, 0, "ACF",      "Accumulated cloud fraction tendency",                         NULL                   },
+  { 242, -1, 0, "ALW",      "Accumulated liquid water tendency",                           NULL                   },
+  { 243, -1, 0, "FAL",      "Forecast albedo",                                             NULL                   },
+  { 244, -1, 0, "FSR",      "Forecast surface roughness",                                 "m"                     },
+  { 245, -1, 0, "FLSR",     "Forecast log of surface roughness for heat",                  NULL                   },
+  { 246, -1, 0, "CLWC",     "Cloud liquid water content",                                 "kg kg**-1"             },
+  { 247, -1, 0, "CIWC",     "Cloud ice water content",                                    "kg kg**-1"             },
+  { 248, -1, 0, "CC",       "Cloud cover",                                                 NULL                   },
+  { 249, -1, 0, "AIW",      "Accumulated ice water tendency",                              NULL                   },
+  { 250, -1, 0, "ICE",      "Ice age",                                                     NULL                   },
+  { 251, -1, 0, "ATTE",     "Adiabatic tendency of temperature",                          "K"                     },
+  { 252, -1, 0, "ATHE",     "Adiabatic tendency of humidity",                             "kg kg**-1"             },
+  { 253, -1, 0, "ATZE",     "Adiabatic tendency of zonal wind",                           "m s**-1"               },
+  { 254, -1, 0, "ATMW",     "Adiabatic tendency of meridional wind",                      "m s**-1"               },
 };
 
-static const PAR remo[] = {
-  {  14, 0, "FTKVM",     "turbulent transfer coefficient of momentum in the atmosphere",   NULL           },
-  {  15, 0, "FTKVH",     "turbulent transfer coefficient of heat in the atmosphere",       NULL           },
-  {  38, 0, "U10ER",     "10m u-velocity",                                                "m/s"           },
-  {  39, 0, "V10ER",     "10m v-velocity",                                                "m/s"           },
-  {  40, 0, "CAPE",      "convetive available potential energy",                           NULL           },
-  {  41, 0, "GHPBL",     "height of the planetary boudary layer",                         "gpm"           },
-  {  42, 0, "BETA",      "BETA",                                                           NULL           },
-  {  43, 0, "WMINLOK",   "WMINLOK",                                                        NULL           },
-  {  44, 0, "WMAXLOK",   "WMAXLOK",                                                        NULL           },
-  {  45, 0, "VBM10M",    "maximum of the expected gust velocity near the surface",        "m/s"           },
-  {  46, 0, "BFLHS",     "surface sensible heat flux",                                    "W/m**2"        },
-  {  47, 0, "BFLQDS",    "surface latent heat flux",                                      "W/m**2"        },
-  {  48, 0, "TMCM",      "turbulent transfer coefficient of momentum at the surface",      NULL           },
-  {  49, 0, "TRSOL",     "TRSOL",                                                          NULL           },
-  {  50, 0, "TMCH",      "turbulent transfer coefficient of heat at the surface",          NULL           },
-  {  51, 0, "EMTEF",     "EMTEF",                                                          NULL           },
-  {  52, 0, "TRSOF",     "TRSOF",                                                          NULL           },
-  {  53, 0, "DRAIN",     "drainage",                                                      "mm"            },
-  {  54, 0, "TSL",       "surface temperature (land)",                                    "K"             },
-  {  55, 0, "TSW",       "surface temperature (water)",                                   "K"             },
-  {  56, 0, "TSI",       "surface temperature (ice)",                                     "K"             },
-  {  57, 0, "USTRL",     "surface u-stress (land)",                                       "Pa"            },
-  {  58, 0, "USTRW",     "surface u-stress (water)",                                      "Pa"            },
-  {  59, 0, "USTRI",     "surface u-stress (ice)",                                        "Pa"            },
-  {  60, 0, "VSTRL",     "surface v-stress (land)",                                       "Pa"            },
-  {  61, 0, "VSTRW",     "surface v-stress (water)",                                      "Pa"            },
-  {  62, 0, "VSTRI",     "surface v-stress (ice)",                                        "Pa"            },
-  {  63, 0, "EVAPL",     "surface evaporation (land)",                                    "mm"            },
-  {  64, 0, "EVAPW",     "surface evaporation (water)",                                   "mm"            },
-  {  65, 0, "EVAPI",     "surface evaporation (ice)",                                     "mm"            },
-  {  66, 0, "AHFLL",     "surface latent heat flux (land)",                               "W/m**2"        },
-  {  67, 0, "AHFLW",     "surface latent heat flux (water)",                              "W/m**2"        },
-  {  68, 0, "AHFLI",     "surface latent heat flux (ice)",                                "W/m**2"        },
-  {  69, 0, "AHFSL",     "surface sensible heat flux (land)",                             "W/m**2"        },
-  {  70, 0, "AHFSW",     "surface sensible heat flux (water)",                            "W/m**2"        },
-  {  71, 0, "AHFSI",     "surface sensible heat flux (ice)",                              "W/m**2"        },
-  {  72, 0, "AZ0L",      "surface roughness length (land)",                               "m"             },
-  {  73, 0, "AZ0W",      "surface roughness length (water)",                              "m"             },
-  {  74, 0, "AZ0I",      "surface roughness length (ice)",                                "m"             },
-  {  75, 0, "ALSOL",     "surface albedo (land)",                                         "fract."        },
-  {  76, 0, "ALSOW",     "surface albedo (water)",                                        "fract."        },
-  {  77, 0, "ALSOI",     "surface albedo (ice)",                                          "fract."        },
-  {  81, 0, "TMCHL",     "turbulent transfer coefficient of heat at the surface (land)",   NULL           },
-  {  82, 0, "TMCHW",     "turbulent transfer coefficient of heat at the surface (water)",  NULL           },
-  {  83, 0, "TMCHI",     "turbulent transfer coefficient of heat at the surface (ice)",    NULL           },
-  {  84, 0, "QDBL",      "specific humidity surface (land)",                              "kg/kg"         },
-  {  85, 0, "QDBW",      "specific humidity surface (water)",                             "kg/kg"         },
-  {  86, 0, "QDBI",      "specific humidity surface (ice)",                               "kg/kg"         },
-  {  87, 0, "BFLHSL",    "surface sensible heat flux (land)",                             "W/m**2"        },
-  {  88, 0, "BFLHSW",    "surface sensible heat flux (water)",                            "W/m**2"        },
-  {  89, 0, "BFLHSI",    "surface sensible heat flux (ice)",                              "W/m**2"        },
-  {  90, 0, "BFLQDSL",   "surface latent heat flux (land)",                               "W/m**2"        },
-  {  91, 0, "BFLQDSW",   "surface latent heat flux (water)",                              "W/m**2"        },
-  {  92, 0, "BFLQDSI",   "surface latent heat flux (ice)",                                "W/m**2"        },
-  {  93, 0, "AHFICE",    "sea-ice: conductive heat",                                      "W/m"           },
-  {  94, 0, "QRES",      "residual heat flux for melting sea ice",                        "W/m**2"        },
-  {  95, 0, "SRFL",      "SRFL",                                                           NULL           },
-  {  96, 0, "QDBOXS",    "horizontal transport of water vapour",                          "kg/m**2"       },
-  {  97, 0, "QWBOXS",    "horizontal transport of cloud water",                           "kg/m**2"       },
-  {  98, 0, "EKBOXS",    "horizontal transport of kinetic energy",                        "(3600*J)/m**2" },
-  {  99, 0, "FHBOXS",    "horizontal transport of sensible heat",                         "(3600*J)/m**2" },
-  { 100, 0, "FIBOXS",    "horizontal transport of potential energy",                      "(3600*J)/m**2" },
-  { 101, 0, "TLAMBDA",   "heat conductivity of dry soil",                                 "W/(K*m)"       },
-  { 103, 0, "DLAMBDA",   "parameter for increasing the heat conductivity of the soil",     NULL           },
-  { 104, 0, "PORVOL",    "pore volume",                                                    NULL           },
-  { 105, 0, "FCAP",      "field capacity of soil",                                         NULL           },
-  { 106, 0, "WI3",       "fraction of frozen soil",                                        NULL           },
-  { 107, 0, "WI4",       "fraction of frozen soil",                                        NULL           },
-  { 108, 0, "WI5",       "fraction of frozen soil",                                        NULL           },
-  { 109, 0, "WI",        "fraction of frozen soil",                                        NULL           },
-  { 110, 0, "WICL",      "fraction of frozen soil",                                        NULL           },
-  { 112, 0, "QDB",       "specific humidity surface",                                     "kg/kg"         },
-  { 129, 0, "FIB",       "surface geopotential (orography)",                              "m"             },
-  { 130, 0, "T",         "temperature",                                                   "K"             },
-  { 131, 0, "U",         "u-velocity",                                                    "m/s"           },
-  { 132, 0, "V",         "v-velocity",                                                    "m/s"           },
-  { 133, 0, "QD",        "specific humidity",                                             "kg/kg"         },
-  { 134, 0, "PS",        "Surface pressure",                                              "Pa"            },
-  { 135, 0, "VERVEL",    "Vertical velocity",                                             "Pa/s"          },
-  { 138, 0, "SVO",       "vorticity",                                                     "1/s"           },
-  { 139, 0, "TS",        "surface temperature",                                           "K"             },
-  { 140, 0, "WS",        "soil wetness",                                                  "m"             },
-  { 141, 0, "SN",        "snow depth",                                                    "m"             },
-  { 142, 0, "APRL",      "large scale precipitation",                                     "mm"            },
-  { 143, 0, "APRC",      "convective  precipitation",                                     "mm"            },
-  { 144, 0, "APRS",      "snow fall",                                                     "mm"            },
-  { 145, 0, "VDIS",      "boundary layer dissipation",                                    "W/m**2"        },
-  { 146, 0, "AHFS",      "surface sensible heat flux",                                    "W/m**2"        },
-  { 147, 0, "AHFL",      "surface latent heat flux",                                      "W/m**2"        },
-  { 148, 0, "STREAM",    "streamfunction",                                                "m**2/s"        },
-  { 149, 0, "VELOPOT",   "velocity potential",                                            "m**2/s"        },
-  { 151, 0, "PSRED",     "mean sea level pressure",                                       "Pa"            },
-  { 152, 0, "LSP",       "log surface pressure",                                           NULL           },
-  { 153, 0, "QW",        "liquid water content",                                          "kg/kg"         },
-  { 155, 0, "SD",        "divergence",                                                    "1/s"           },
-  { 156, 0, "FI",        "geopotential height",                                           "gpm"           },
-  { 159, 0, "USTAR3",    "ustar**3",                                                      "m**3/s**3"     },
-  { 160, 0, "RUNOFF",    "surface runoff",                                                "mm"            },
-  { 162, 0, "ACLC",      "cloud cover",                                                   "fract."        },
-  { 163, 0, "ACLCV",     "total cloud cover",                                             "fract."        },
-  { 164, 0, "ACLCOV",    "total cloud cover",                                             "fract."        },
-  { 165, 0, "U10",       "10m u-velocity",                                                "m/s"           },
-  { 166, 0, "V10",       "10m v-velocity",                                                "m/s"           },
-  { 167, 0, "TEMP2",     "2m temperature",                                                "K"             },
-  { 168, 0, "DEW2",      "2m dew point temperature",                                      "K"             },
-  { 169, 0, "TSURF",     "surface temperature (land)",                                    "K"             },
-  { 170, 0, "TD",        "deep soil temperature",                                         "K"             },
-  { 171, 0, "WIND10",    "10m windspeed",                                                 "m/s"           },
-  { 172, 0, "BLA",       "land sea mask",                                                 "fract."        },
-  { 173, 0, "AZ0",       "surface roughness length",                                      "m"             },
-  { 174, 0, "ALB",       "surface background albedo",                                     "fract."        },
-  { 175, 0, "ALBEDO",    "surface albedo",                                                "fract."        },
-  { 176, 0, "SRADS",     "net surface solar radiation",                                   "W/m**2"        },
-  { 177, 0, "TRADS",     "net surface thermal radiation",                                 "W/m**2"        },
-  { 178, 0, "SRAD0",     "net top solar radiation",                                       "W/m**2"        },
-  { 179, 0, "TRAD0",     "top thermal radiation (OLR)",                                   "W/m**2"        },
-  { 180, 0, "USTR",      "surface u-stress",                                              "Pa"            },
-  { 181, 0, "VSTR",      "surface v-stress",                                              "Pa"            },
-  { 182, 0, "EVAP",      "surface evaporation",                                           "mm"            },
-  { 183, 0, "TDCL",      "soil temperature",                                              "K"             },
-  { 185, 0, "SRAFS",     "net surf. solar radiation   (clear sky)",                       "W/m**2"        },
-  { 186, 0, "TRAFS",     "net surf. thermal radiation (clear sky)",                       "W/m**2"        },
-  { 187, 0, "SRAF0",     "net top solar radiation     (clear sky)",                       "W/m**2"        },
-  { 188, 0, "TRAF0",     "net top thermal radiation   (clear sky)",                       "W/m**2"        },
-  { 189, 0, "SCLFS",     "surface solar cloud forcing",                                   "W/m**2"        },
-  { 190, 0, "TCLFS",     "surface thermal cloud forcing",                                 "W/m**2"        },
-  { 191, 0, "SCLF0",     "top solar cloud forcing",                                       "W/m**2"        },
-  { 192, 0, "TCLF0",     "top thermal cloud forcing",                                     "W/m**2"        },
-  { 194, 0, "WL",        "skin reservoir content",                                        "m"             },
-  { 195, 0, "USTRGW",    "u-gravity wave stress",                                         "Pa"            },
-  { 196, 0, "VSTRGW",    "v-gravity wave stress",                                         "Pa"            },
-  { 197, 0, "VDISGW",    "gravity wave dissipation",                                      "W/m**2"        },
-  { 198, 0, "VGRAT",     "vegetation ratio",                                               NULL           },
-  { 199, 0, "VAROR",     "orographic variance (for surface runoff)",                       NULL           },
-  { 200, 0, "VLT",       "leaf area index",                                                NULL           },
-  { 201, 0, "T2MAX",     "maximum 2m-temperature",                                        "K"             },
-  { 202, 0, "T2MIN",     "minimum 2m-temperature",                                        "K"             },
-  { 203, 0, "SRAD0U",    "top solar radiation upward",                                    "W/m**2"        },
-  { 204, 0, "SRADSU",    "surface solar radiation upward",                                "W/m**2"        },
-  { 205, 0, "TRADSU",    "surface thermal radiation upward",                              "W/m**2"        },
-  { 206, 0, "TSN",       "snow temperature",                                              "K"             },
-  { 207, 0, "TD3",       "soil temperature",                                              "K"             },
-  { 208, 0, "TD4",       "soil temperature",                                              "K"             },
-  { 209, 0, "TD5",       "soil temperature",                                              "K"             },
-  { 210, 0, "SEAICE",    "sea ice cover",                                                 "fract."        },
-  { 211, 0, "SICED",     "sea ice depth",                                                 "m"             },
-  { 212, 0, "FOREST",    "vegetation type",                                                NULL           },
-  { 213, 0, "TEFF",      "(effective) sea-ice skin temperature",                          "K"             },
-  { 214, 0, "TSMAX",     "maximum surface temperature",                                   "K"             },
-  { 215, 0, "TSMIN",     "minimum surface temperature",                                   "K"             },
-  { 216, 0, "WIMAX",     "maximum 10m-wind speed",                                        "m/s"           },
-  { 217, 0, "TOPMAX",    "maximum height of convective cloud tops",                       "Pa"            },
-  { 218, 0, "SNMEL",     "snow melt",                                                     "mm"            },
-  { 220, 0, "TSLIN",     "land: residual surface heat budget",                            "W/m**2"        },
-  { 221, 0, "DSNAC",     "snow depth change",                                             "mm"            },
-  { 222, 0, "EMTER",     "EMTER",                                                          NULL           },
-  { 223, 0, "ACLCAC",    "cloud cover",                                                   "fract."        },
-  { 224, 0, "TKE",       "turbulent kinetic energy",                                       NULL           },
-  { 226, 0, "FAO",       "FAO data set (soil data flags)",                                 NULL           },
-  { 227, 0, "RGCGN",     "heat capacity of soil",                                          NULL           },
-  { 229, 0, "WSMX",      "field capacity of soil",                                         NULL           },
-  { 230, 0, "QVI",       "vertically integrated specific humidity",                       "kg/m**2"       },
-  { 231, 0, "ALWCVI",    "vertically integrated liquid water cont.",                      "kg/m**2"       },
-  { 232, 0, "GLAC",      "glacier mask",                                                   NULL           },
-  { 253, 0, "PHI",       "latitude in real coordinates",                                  "degrees_north" },
-  { 254, 0, "RLA",       "longitude in real coordinates",                                 "degrees_east"  },
-  { 259, 0, "WINDSPEED", "windspeed (sqrt(u**2+v**2))",                                    NULL           },
-  { 260, 0, "PRECIP",    "total precipitation",                                            NULL           },
+static const param_type remo[] = {
+  {  14, -1, 0, "FTKVM",     "turbulent transfer coefficient of momentum in the atmosphere",   NULL           },
+  {  15, -1, 0, "FTKVH",     "turbulent transfer coefficient of heat in the atmosphere",       NULL           },
+  {  38, -1, 0, "U10ER",     "10m u-velocity",                                                "m/s"           },
+  {  39, -1, 0, "V10ER",     "10m v-velocity",                                                "m/s"           },
+  {  40, -1, 0, "CAPE",      "convetive available potential energy",                           NULL           },
+  {  41, -1, 0, "GHPBL",     "height of the planetary boudary layer",                         "gpm"           },
+  {  42, -1, 0, "BETA",      "BETA",                                                           NULL           },
+  {  43, -1, 0, "WMINLOK",   "WMINLOK",                                                        NULL           },
+  {  44, -1, 0, "WMAXLOK",   "WMAXLOK",                                                        NULL           },
+  {  45, -1, 0, "VBM10M",    "maximum of the expected gust velocity near the surface",        "m/s"           },
+  {  46, -1, 0, "BFLHS",     "surface sensible heat flux",                                    "W/m**2"        },
+  {  47, -1, 0, "BFLQDS",    "surface latent heat flux",                                      "W/m**2"        },
+  {  48, -1, 0, "TMCM",      "turbulent transfer coefficient of momentum at the surface",      NULL           },
+  {  49, -1, 0, "TRSOL",     "TRSOL",                                                          NULL           },
+  {  50, -1, 0, "TMCH",      "turbulent transfer coefficient of heat at the surface",          NULL           },
+  {  51, -1, 0, "EMTEF",     "EMTEF",                                                          NULL           },
+  {  52, -1, 0, "TRSOF",     "TRSOF",                                                          NULL           },
+  {  53, -1, 0, "DRAIN",     "drainage",                                                      "mm"            },
+  {  54, -1, 0, "TSL",       "surface temperature (land)",                                    "K"             },
+  {  55, -1, 0, "TSW",       "surface temperature (water)",                                   "K"             },
+  {  56, -1, 0, "TSI",       "surface temperature (ice)",                                     "K"             },
+  {  57, -1, 0, "USTRL",     "surface u-stress (land)",                                       "Pa"            },
+  {  58, -1, 0, "USTRW",     "surface u-stress (water)",                                      "Pa"            },
+  {  59, -1, 0, "USTRI",     "surface u-stress (ice)",                                        "Pa"            },
+  {  60, -1, 0, "VSTRL",     "surface v-stress (land)",                                       "Pa"            },
+  {  61, -1, 0, "VSTRW",     "surface v-stress (water)",                                      "Pa"            },
+  {  62, -1, 0, "VSTRI",     "surface v-stress (ice)",                                        "Pa"            },
+  {  63, -1, 0, "EVAPL",     "surface evaporation (land)",                                    "mm"            },
+  {  64, -1, 0, "EVAPW",     "surface evaporation (water)",                                   "mm"            },
+  {  65, -1, 0, "EVAPI",     "surface evaporation (ice)",                                     "mm"            },
+  {  66, -1, 0, "AHFLL",     "surface latent heat flux (land)",                               "W/m**2"        },
+  {  67, -1, 0, "AHFLW",     "surface latent heat flux (water)",                              "W/m**2"        },
+  {  68, -1, 0, "AHFLI",     "surface latent heat flux (ice)",                                "W/m**2"        },
+  {  69, -1, 0, "AHFSL",     "surface sensible heat flux (land)",                             "W/m**2"        },
+  {  70, -1, 0, "AHFSW",     "surface sensible heat flux (water)",                            "W/m**2"        },
+  {  71, -1, 0, "AHFSI",     "surface sensible heat flux (ice)",                              "W/m**2"        },
+  {  72, -1, 0, "AZ0L",      "surface roughness length (land)",                               "m"             },
+  {  73, -1, 0, "AZ0W",      "surface roughness length (water)",                              "m"             },
+  {  74, -1, 0, "AZ0I",      "surface roughness length (ice)",                                "m"             },
+  {  75, -1, 0, "ALSOL",     "surface albedo (land)",                                         "fract."        },
+  {  76, -1, 0, "ALSOW",     "surface albedo (water)",                                        "fract."        },
+  {  77, -1, 0, "ALSOI",     "surface albedo (ice)",                                          "fract."        },
+  {  81, -1, 0, "TMCHL",     "turbulent transfer coefficient of heat at the surface (land)",   NULL           },
+  {  82, -1, 0, "TMCHW",     "turbulent transfer coefficient of heat at the surface (water)",  NULL           },
+  {  83, -1, 0, "TMCHI",     "turbulent transfer coefficient of heat at the surface (ice)",    NULL           },
+  {  84, -1, 0, "QDBL",      "specific humidity surface (land)",                              "kg/kg"         },
+  {  85, -1, 0, "QDBW",      "specific humidity surface (water)",                             "kg/kg"         },
+  {  86, -1, 0, "QDBI",      "specific humidity surface (ice)",                               "kg/kg"         },
+  {  87, -1, 0, "BFLHSL",    "surface sensible heat flux (land)",                             "W/m**2"        },
+  {  88, -1, 0, "BFLHSW",    "surface sensible heat flux (water)",                            "W/m**2"        },
+  {  89, -1, 0, "BFLHSI",    "surface sensible heat flux (ice)",                              "W/m**2"        },
+  {  90, -1, 0, "BFLQDSL",   "surface latent heat flux (land)",                               "W/m**2"        },
+  {  91, -1, 0, "BFLQDSW",   "surface latent heat flux (water)",                              "W/m**2"        },
+  {  92, -1, 0, "BFLQDSI",   "surface latent heat flux (ice)",                                "W/m**2"        },
+  {  93, -1, 0, "AHFICE",    "sea-ice: conductive heat",                                      "W/m"           },
+  {  94, -1, 0, "QRES",      "residual heat flux for melting sea ice",                        "W/m**2"        },
+  {  95, -1, 0, "SRFL",      "SRFL",                                                           NULL           },
+  {  96, -1, 0, "QDBOXS",    "horizontal transport of water vapour",                          "kg/m**2"       },
+  {  97, -1, 0, "QWBOXS",    "horizontal transport of cloud water",                           "kg/m**2"       },
+  {  98, -1, 0, "EKBOXS",    "horizontal transport of kinetic energy",                        "(3600*J)/m**2" },
+  {  99, -1, 0, "FHBOXS",    "horizontal transport of sensible heat",                         "(3600*J)/m**2" },
+  { 100, -1, 0, "FIBOXS",    "horizontal transport of potential energy",                      "(3600*J)/m**2" },
+  { 101, -1, 0, "TLAMBDA",   "heat conductivity of dry soil",                                 "W/(K*m)"       },
+  { 103, -1, 0, "DLAMBDA",   "parameter for increasing the heat conductivity of the soil",     NULL           },
+  { 104, -1, 0, "PORVOL",    "pore volume",                                                    NULL           },
+  { 105, -1, 0, "FCAP",      "field capacity of soil",                                         NULL           },
+  { 106, -1, 0, "WI3",       "fraction of frozen soil",                                        NULL           },
+  { 107, -1, 0, "WI4",       "fraction of frozen soil",                                        NULL           },
+  { 108, -1, 0, "WI5",       "fraction of frozen soil",                                        NULL           },
+  { 109, -1, 0, "WI",        "fraction of frozen soil",                                        NULL           },
+  { 110, -1, 0, "WICL",      "fraction of frozen soil",                                        NULL           },
+  { 112, -1, 0, "QDB",       "specific humidity surface",                                     "kg/kg"         },
+  { 129, -1, 0, "FIB",       "surface geopotential (orography)",                              "m"             },
+  { 130, -1, 0, "T",         "temperature",                                                   "K"             },
+  { 131, -1, 0, "U",         "u-velocity",                                                    "m/s"           },
+  { 132, -1, 0, "V",         "v-velocity",                                                    "m/s"           },
+  { 133, -1, 0, "QD",        "specific humidity",                                             "kg/kg"         },
+  { 134, -1, 0, "PS",        "Surface pressure",                                              "Pa"            },
+  { 135, -1, 0, "VERVEL",    "Vertical velocity",                                             "Pa/s"          },
+  { 138, -1, 0, "SVO",       "vorticity",                                                     "1/s"           },
+  { 139, -1, 0, "TS",        "surface temperature",                                           "K"             },
+  { 140, -1, 0, "WS",        "soil wetness",                                                  "m"             },
+  { 141, -1, 0, "SN",        "snow depth",                                                    "m"             },
+  { 142, -1, 0, "APRL",      "large scale precipitation",                                     "mm"            },
+  { 143, -1, 0, "APRC",      "convective  precipitation",                                     "mm"            },
+  { 144, -1, 0, "APRS",      "snow fall",                                                     "mm"            },
+  { 145, -1, 0, "VDIS",      "boundary layer dissipation",                                    "W/m**2"        },
+  { 146, -1, 0, "AHFS",      "surface sensible heat flux",                                    "W/m**2"        },
+  { 147, -1, 0, "AHFL",      "surface latent heat flux",                                      "W/m**2"        },
+  { 148, -1, 0, "STREAM",    "streamfunction",                                                "m**2/s"        },
+  { 149, -1, 0, "VELOPOT",   "velocity potential",                                            "m**2/s"        },
+  { 151, -1, 0, "PSRED",     "mean sea level pressure",                                       "Pa"            },
+  { 152, -1, 0, "LSP",       "log surface pressure",                                           NULL           },
+  { 153, -1, 0, "QW",        "liquid water content",                                          "kg/kg"         },
+  { 155, -1, 0, "SD",        "divergence",                                                    "1/s"           },
+  { 156, -1, 0, "FI",        "geopotential height",                                           "gpm"           },
+  { 159, -1, 0, "USTAR3",    "ustar**3",                                                      "m**3/s**3"     },
+  { 160, -1, 0, "RUNOFF",    "surface runoff",                                                "mm"            },
+  { 162, -1, 0, "ACLC",      "cloud cover",                                                   "fract."        },
+  { 163, -1, 0, "ACLCV",     "total cloud cover",                                             "fract."        },
+  { 164, -1, 0, "ACLCOV",    "total cloud cover",                                             "fract."        },
+  { 165, -1, 0, "U10",       "10m u-velocity",                                                "m/s"           },
+  { 166, -1, 0, "V10",       "10m v-velocity",                                                "m/s"           },
+  { 167, -1, 0, "TEMP2",     "2m temperature",                                                "K"             },
+  { 168, -1, 0, "DEW2",      "2m dew point temperature",                                      "K"             },
+  { 169, -1, 0, "TSURF",     "surface temperature (land)",                                    "K"             },
+  { 170, -1, 0, "TD",        "deep soil temperature",                                         "K"             },
+  { 171, -1, 0, "WIND10",    "10m windspeed",                                                 "m/s"           },
+  { 172, -1, 0, "BLA",       "land sea mask",                                                 "fract."        },
+  { 173, -1, 0, "AZ0",       "surface roughness length",                                      "m"             },
+  { 174, -1, 0, "ALB",       "surface background albedo",                                     "fract."        },
+  { 175, -1, 0, "ALBEDO",    "surface albedo",                                                "fract."        },
+  { 176, -1, 0, "SRADS",     "net surface solar radiation",                                   "W/m**2"        },
+  { 177, -1, 0, "TRADS",     "net surface thermal radiation",                                 "W/m**2"        },
+  { 178, -1, 0, "SRAD0",     "net top solar radiation",                                       "W/m**2"        },
+  { 179, -1, 0, "TRAD0",     "top thermal radiation (OLR)",                                   "W/m**2"        },
+  { 180, -1, 0, "USTR",      "surface u-stress",                                              "Pa"            },
+  { 181, -1, 0, "VSTR",      "surface v-stress",                                              "Pa"            },
+  { 182, -1, 0, "EVAP",      "surface evaporation",                                           "mm"            },
+  { 183, -1, 0, "TDCL",      "soil temperature",                                              "K"             },
+  { 185, -1, 0, "SRAFS",     "net surf. solar radiation   (clear sky)",                       "W/m**2"        },
+  { 186, -1, 0, "TRAFS",     "net surf. thermal radiation (clear sky)",                       "W/m**2"        },
+  { 187, -1, 0, "SRAF0",     "net top solar radiation     (clear sky)",                       "W/m**2"        },
+  { 188, -1, 0, "TRAF0",     "net top thermal radiation   (clear sky)",                       "W/m**2"        },
+  { 189, -1, 0, "SCLFS",     "surface solar cloud forcing",                                   "W/m**2"        },
+  { 190, -1, 0, "TCLFS",     "surface thermal cloud forcing",                                 "W/m**2"        },
+  { 191, -1, 0, "SCLF0",     "top solar cloud forcing",                                       "W/m**2"        },
+  { 192, -1, 0, "TCLF0",     "top thermal cloud forcing",                                     "W/m**2"        },
+  { 194, -1, 0, "WL",        "skin reservoir content",                                        "m"             },
+  { 195, -1, 0, "USTRGW",    "u-gravity wave stress",                                         "Pa"            },
+  { 196, -1, 0, "VSTRGW",    "v-gravity wave stress",                                         "Pa"            },
+  { 197, -1, 0, "VDISGW",    "gravity wave dissipation",                                      "W/m**2"        },
+  { 198, -1, 0, "VGRAT",     "vegetation ratio",                                               NULL           },
+  { 199, -1, 0, "VAROR",     "orographic variance (for surface runoff)",                       NULL           },
+  { 200, -1, 0, "VLT",       "leaf area index",                                                NULL           },
+  { 201, -1, 0, "T2MAX",     "maximum 2m-temperature",                                        "K"             },
+  { 202, -1, 0, "T2MIN",     "minimum 2m-temperature",                                        "K"             },
+  { 203, -1, 0, "SRAD0U",    "top solar radiation upward",                                    "W/m**2"        },
+  { 204, -1, 0, "SRADSU",    "surface solar radiation upward",                                "W/m**2"        },
+  { 205, -1, 0, "TRADSU",    "surface thermal radiation upward",                              "W/m**2"        },
+  { 206, -1, 0, "TSN",       "snow temperature",                                              "K"             },
+  { 207, -1, 0, "TD3",       "soil temperature",                                              "K"             },
+  { 208, -1, 0, "TD4",       "soil temperature",                                              "K"             },
+  { 209, -1, 0, "TD5",       "soil temperature",                                              "K"             },
+  { 210, -1, 0, "SEAICE",    "sea ice cover",                                                 "fract."        },
+  { 211, -1, 0, "SICED",     "sea ice depth",                                                 "m"             },
+  { 212, -1, 0, "FOREST",    "vegetation type",                                                NULL           },
+  { 213, -1, 0, "TEFF",      "(effective) sea-ice skin temperature",                          "K"             },
+  { 214, -1, 0, "TSMAX",     "maximum surface temperature",                                   "K"             },
+  { 215, -1, 0, "TSMIN",     "minimum surface temperature",                                   "K"             },
+  { 216, -1, 0, "WIMAX",     "maximum 10m-wind speed",                                        "m/s"           },
+  { 217, -1, 0, "TOPMAX",    "maximum height of convective cloud tops",                       "Pa"            },
+  { 218, -1, 0, "SNMEL",     "snow melt",                                                     "mm"            },
+  { 220, -1, 0, "TSLIN",     "land: residual surface heat budget",                            "W/m**2"        },
+  { 221, -1, 0, "DSNAC",     "snow depth change",                                             "mm"            },
+  { 222, -1, 0, "EMTER",     "EMTER",                                                          NULL           },
+  { 223, -1, 0, "ACLCAC",    "cloud cover",                                                   "fract."        },
+  { 224, -1, 0, "TKE",       "turbulent kinetic energy",                                       NULL           },
+  { 226, -1, 0, "FAO",       "FAO data set (soil data flags)",                                 NULL           },
+  { 227, -1, 0, "RGCGN",     "heat capacity of soil",                                          NULL           },
+  { 229, -1, 0, "WSMX",      "field capacity of soil",                                         NULL           },
+  { 230, -1, 0, "QVI",       "vertically integrated specific humidity",                       "kg/m**2"       },
+  { 231, -1, 0, "ALWCVI",    "vertically integrated liquid water cont.",                      "kg/m**2"       },
+  { 232, -1, 0, "GLAC",      "glacier mask",                                                   NULL           },
+  { 253, -1, 0, "PHI",       "latitude in real coordinates",                                  "degrees_north" },
+  { 254, -1, 0, "RLA",       "longitude in real coordinates",                                 "degrees_east"  },
+  { 259, -1, 0, "WINDSPEED", "windspeed (sqrt(u**2+v**2))",                                    NULL           },
+  { 260, -1, 0, "PRECIP",    "total precipitation",                                            NULL           },
 };
 
-static const PAR cosmo002[] = {
-  {   1, 0, "P",         "pressure",                                          "Pa"         },
-  {   2, 0, "PMSL",      "mean sea level pressure",                           "Pa"         },
-  {   3, 0, "DPSDT",     "surface pressure change",                           "Pa s-1"     },
-  {   6, 0, "FI",        "geopotential",                                      "m2 s-2"     },
-  {   8, 0, "HH",        "height",                                            "m"          },
-  {  10, 0, "TO3",       "vertical integrated ozone content",                 "Dobson"     },
-  {  11, 0, "T",         "temperature",                                       "K"          },
-  {  15, 0, "TMAX",      "2m maximum temperature",                            "K"          },
-  {  16, 0, "TMIN",      "2m minimum temperature",                            "K"          },
-  {  17, 0, "TD",        "2m dew point temperature",                          "K"          },
-  {  31, 0, "DD",        "undefined",                                         "undefined"  },
-  {  32, 0, "FF",        "undefined",                                         "undefined"  },
-  {  33, 0, "U",         "U-component of wind",                               "m s-1"      },
-  {  34, 0, "V",         "V-component of wind",                               "m s-1"      },
-  {  39, 0, "OMEGA",     "omega",                                             "Pa s-1"     },
-  {  40, 0, "W",         "vertical wind velocity",                            "m s-1"      },
-  {  51, 0, "QV",        "specific humidity",                                 "kg kg-1"    },
-  {  52, 0, "RELHUM",    "relative humidity",                                 "%"          },
-  {  54, 0, "TQV",       "precipitable water",                                "kg m-2"     },
-  {  57, 0, "AEVAP",     "surface evaporation",                               "kg m-2"     },
-  {  58, 0, "TQI",       "vertical integrated cloud ice",                     "kg m-2"     },
-  {  59, 0, "TOT_PR",    "total precipitation rate",                          "kg m-2 s-1" },
-  {  61, 0, "TOT_PREC",  "total precipitation amount",                        "kg m-2"     },
-  {  65, 0, "W_SNOW",    "surface snow amount",                               "m"          },
-  {  66, 0, "H_SNOW",    "thickness of snow",                                 "m"          },
-  {  71, 0, "CLCT",      "total cloud cover",                                 "1"          },
-  {  72, 0, "CLC_CON",   "convective cloud area fraction",                    "1"          },
-  {  73, 0, "CLCL",      "low cloud cover",                                   "1"          },
-  {  74, 0, "CLCM",      "medium cloud cover",                                "1"          },
-  {  75, 0, "CLCH",      "high cloud cover",                                  "1"          },
-  {  76, 0, "TQC",       "vertical integrated cloud water",                   "kg m-2"     },
-  {  78, 0, "SNOW_CON",  "convective snowfall",                               "kg m-2"     },
-  {  79, 0, "SNOW_GSP",  "large scale snowfall",                              "kg m-2"     },
-  {  81, 0, "FR_LAND",   "land-sea fraction",                                 "1"          },
-  {  83, 0, "Z0",        "surface roughness length",                          "m"          },
-  {  84, 0, "ALB_RAD",   "surface albedo",                                    "1"          },
-  {  85, 0, "TSOIL",     "soil surface temperature",                          "K"          },
-  {  86, 0, "WSOIL",     "water content of 1. soil layer",                    "m"          },
-  {  87, 0, "PLCOV",     "vegetation area fraction",                          "1"          },
-  {  90, 0, "RUNOFF",    "subsurface runoff",                                 "kg m-2"     },
-  {  91, 0, "FR_ICE",    "sea ice area fraction",                             "1"          },
-  {  92, 0, "H_ICE",     "sea ice thickness",                                 "m"          },
-  { 111, 0, "ASOB",      "averaged surface net downward shortwave radiation", "W m-2"      },
-  { 112, 0, "ATHB",      "averaged surface net downward longwave radiation",  "W m-2"      },
-  { 113, 0, "ASOB",      "averaged TOA net downward shortwave radiation",     "W m-2"      },
-  { 114, 0, "ATHB",      "averaged TOA outgoing longwave radiation",          "W m-2"      },
-  { 115, 0, "ASWDIR",    "direct downward sw radiation at the surface",       "W m-2"      },
-  { 116, 0, "ASWDIFD",   "diffuse downward sw radiation at the surface",      "W m-2"      },
-  { 117, 0, "ASWDIFU",   "diffuse upwnward sw radiation at the surface",      "W m-2"      },
-  { 118, 0, "ALWD",      "downward lw radiation at the surface",              "W m-2"      },
-  { 119, 0, "ALWU",      "upward lw radiation at the surface",                "W m-2"      },
-  { 121, 0, "ALHFL",     "averaged surface latent heat flux",                 "W m-2"      },
-  { 122, 0, "ASHFL",     "averaged surface sensible heat flux",               "W m-2"      },
-  { 124, 0, "AUMFL",     "averaged eastward stress",                          "Pa"         },
-  { 125, 0, "AVMFL",     "averaged northward stress",                         "Pa"         },
-  { 128, 0, "SUNSH",     "undefined",                                         "undefined"  },
-  { 129, 0, "SUNSH2",    "undefined",                                         "undefined"  },
-  { 130, 0, "SUN_SUM",   "undefined",                                         "undefined"  },
-  { 131, 0, "SUN_SUM2",  "undefined",                                         "undefined"  },
-  { 133, 0, "FCOR",      "undefined",                                         "undefined"  },
-  { 134, 0, "SKYVIEW",   "sky-view factor",                                   "1"          },
-  { 137, 0, "SWDIR_COR", "topo correction of direct solar radiarion",         "1"          },
+static const param_type cosmo002[] = {
+  {   1, -1, 0, "P",         "pressure",                                          "Pa"         },
+  {   2, -1, 0, "PMSL",      "mean sea level pressure",                           "Pa"         },
+  {   3, -1, 0, "DPSDT",     "surface pressure change",                           "Pa s-1"     },
+  {   6, -1, 0, "FI",        "geopotential",                                      "m2 s-2"     },
+  {   8, -1, 0, "HH",        "height",                                            "m"          },
+  {  10, -1, 0, "TO3",       "vertical integrated ozone content",                 "Dobson"     },
+  {  11, -1, 0, "T",         "temperature",                                       "K"          },
+  {  15, -1, 0, "TMAX",      "2m maximum temperature",                            "K"          },
+  {  16, -1, 0, "TMIN",      "2m minimum temperature",                            "K"          },
+  {  17, -1, 0, "TD",        "2m dew point temperature",                          "K"          },
+  {  31, -1, 0, "DD",        "undefined",                                         "undefined"  },
+  {  32, -1, 0, "FF",        "undefined",                                         "undefined"  },
+  {  33, -1, 0, "U",         "U-component of wind",                               "m s-1"      },
+  {  34, -1, 0, "V",         "V-component of wind",                               "m s-1"      },
+  {  39, -1, 0, "OMEGA",     "omega",                                             "Pa s-1"     },
+  {  40, -1, 0, "W",         "vertical wind velocity",                            "m s-1"      },
+  {  51, -1, 0, "QV",        "specific humidity",                                 "kg kg-1"    },
+  {  52, -1, 0, "RELHUM",    "relative humidity",                                 "%"          },
+  {  54, -1, 0, "TQV",       "precipitable water",                                "kg m-2"     },
+  {  57, -1, 0, "AEVAP",     "surface evaporation",                               "kg m-2"     },
+  {  58, -1, 0, "TQI",       "vertical integrated cloud ice",                     "kg m-2"     },
+  {  59, -1, 0, "TOT_PR",    "total precipitation rate",                          "kg m-2 s-1" },
+  {  61, -1, 0, "TOT_PREC",  "total precipitation amount",                        "kg m-2"     },
+  {  65, -1, 0, "W_SNOW",    "surface snow amount",                               "m"          },
+  {  66, -1, 0, "H_SNOW",    "thickness of snow",                                 "m"          },
+  {  71, -1, 0, "CLCT",      "total cloud cover",                                 "1"          },
+  {  72, -1, 0, "CLC_CON",   "convective cloud area fraction",                    "1"          },
+  {  73, -1, 0, "CLCL",      "low cloud cover",                                   "1"          },
+  {  74, -1, 0, "CLCM",      "medium cloud cover",                                "1"          },
+  {  75, -1, 0, "CLCH",      "high cloud cover",                                  "1"          },
+  {  76, -1, 0, "TQC",       "vertical integrated cloud water",                   "kg m-2"     },
+  {  78, -1, 0, "SNOW_CON",  "convective snowfall",                               "kg m-2"     },
+  {  79, -1, 0, "SNOW_GSP",  "large scale snowfall",                              "kg m-2"     },
+  {  81, -1, 0, "FR_LAND",   "land-sea fraction",                                 "1"          },
+  {  83, -1, 0, "Z0",        "surface roughness length",                          "m"          },
+  {  84, -1, 0, "ALB_RAD",   "surface albedo",                                    "1"          },
+  {  85, -1, 0, "TSOIL",     "soil surface temperature",                          "K"          },
+  {  86, -1, 0, "WSOIL",     "water content of 1. soil layer",                    "m"          },
+  {  87, -1, 0, "PLCOV",     "vegetation area fraction",                          "1"          },
+  {  90, -1, 0, "RUNOFF",    "subsurface runoff",                                 "kg m-2"     },
+  {  91, -1, 0, "FR_ICE",    "sea ice area fraction",                             "1"          },
+  {  92, -1, 0, "H_ICE",     "sea ice thickness",                                 "m"          },
+  { 111, -1, 0, "ASOB",      "averaged surface net downward shortwave radiation", "W m-2"      },
+  { 112, -1, 0, "ATHB",      "averaged surface net downward longwave radiation",  "W m-2"      },
+  { 113, -1, 0, "ASOB",      "averaged TOA net downward shortwave radiation",     "W m-2"      },
+  { 114, -1, 0, "ATHB",      "averaged TOA outgoing longwave radiation",          "W m-2"      },
+  { 115, -1, 0, "ASWDIR",    "direct downward sw radiation at the surface",       "W m-2"      },
+  { 116, -1, 0, "ASWDIFD",   "diffuse downward sw radiation at the surface",      "W m-2"      },
+  { 117, -1, 0, "ASWDIFU",   "diffuse upwnward sw radiation at the surface",      "W m-2"      },
+  { 118, -1, 0, "ALWD",      "downward lw radiation at the surface",              "W m-2"      },
+  { 119, -1, 0, "ALWU",      "upward lw radiation at the surface",                "W m-2"      },
+  { 121, -1, 0, "ALHFL",     "averaged surface latent heat flux",                 "W m-2"      },
+  { 122, -1, 0, "ASHFL",     "averaged surface sensible heat flux",               "W m-2"      },
+  { 124, -1, 0, "AUMFL",     "averaged eastward stress",                          "Pa"         },
+  { 125, -1, 0, "AVMFL",     "averaged northward stress",                         "Pa"         },
+  { 128, -1, 0, "SUNSH",     "undefined",                                         "undefined"  },
+  { 129, -1, 0, "SUNSH2",    "undefined",                                         "undefined"  },
+  { 130, -1, 0, "SUN_SUM",   "undefined",                                         "undefined"  },
+  { 131, -1, 0, "SUN_SUM2",  "undefined",                                         "undefined"  },
+  { 133, -1, 0, "FCOR",      "undefined",                                         "undefined"  },
+  { 134, -1, 0, "SKYVIEW",   "sky-view factor",                                   "1"          },
+  { 137, -1, 0, "SWDIR_COR", "topo correction of direct solar radiarion",         "1"          },
 };
 
-static const PAR cosmo201[] = {
-  {   5, 0, "APAB",      "&",                                                         "W m-2"      },
-  {  13, 0, "SOHR_RAD",  "&",                                                         "K s-1"      },
-  {  14, 0, "THHR_RAD",  "&",                                                         "K s-1"      },
-  {  20, 0, "DURSUN",    "duration of sunshine",                                      "s"          },
-  {  29, 0, "CLC",       "cloud area fraction",                                       "1"          },
-  {  30, 0, "CLC_SGS",   "grid scale cloud area fraction",                            "1"          },
-  {  31, 0, "QC",        "specific cloud liquid water content",                       "kg kg-1"    },
-  {  33, 0, "QI",        "specific cloud ice content",                                "kg kg-1"    },
-  {  35, 0, "QR",        "specific rain content",                                     "kg kg-1"    },
-  {  36, 0, "QS",        "specific snow content",                                     "kg kg-1"    },
-  {  37, 0, "TQR",       "total rain water content vertically integrated",            "kg m-2"     },
-  {  38, 0, "TQS",       "total snow content vertically integrated",                  "kg m-2"     },
-  {  39, 0, "QG",        "specific graupel content",                                  "kg kg-1"    },
-  {  40, 0, "TQG",       "total graupel content vertically integrated",               "kg m-2"     },
-  {  41, 0, "TWATER",    "cloud condensed water content",                             "kg m-2"     },
-  {  42, 0, "TDIV_HUM",  "atmosphere water divergence",                               "kg m-2"     },
-  {  43, 0, "QC_RAD",    "sub scale specific cloud liquid water content",             "kg kg-1"    },
-  {  44, 0, "QI_RAD",    "sub scale specific cloud ice content",                      "kg kg-1"    },
-  {  61, 0, "CLW_CON",   "convective cloud liquid water",                             "1"          },
-  {  68, 0, "HBAS_CON",  "height of convective cloud base",                           "m"          },
-  {  69, 0, "HTOP_CON",  "height of convective cloud top",                            "m"          },
-  {  70, 0, "HBAS_CONI", "height of convective cloud base",                           "m"          },
-  {  71, 0, "HTOP_CONI", "height of convective cloud top",                            "m"          },
-  {  72, 0, "BAS_CON",   "index of convective cloud base",                            "1"          },
-  {  73, 0, "TOP_CON",   "index of convective cloud top",                             "1"          },
-  {  74, 0, "DT_CON",    "convective tendency of temperature",                        "K s-1"      },
-  {  75, 0, "DQV_CON",   "convective tendency of specific humidity",                  "s-1"        },
-  {  78, 0, "DU_CON",    "convective tendency of u-wind component",                   "m s-2"      },
-  {  79, 0, "DV_CON",    "convective tendency of v-wind component",                   "m s-2"      },
-  {  82, 0, "HTOP_DC",   "height of dry convection top",                              "m"          },
-  {  84, 0, "HZEROCL",   "height of freezing level",                                  "m"          },
-  {  85, 0, "SNOWLMT",   "height of the snow fall limit in m above sea level",        "m"          },
-  {  86, 0, "HCBAS",     "height of cloud base",                                      "m"          },
-  {  87, 0, "HCTOP",     "height of cloud top",                                       "m"          },
-  {  91, 0, "C_T_LK",    "&",                                                         "1"          },
-  {  92, 0, "GAMSO_LK",  "&",                                                         "m-1"        },
-  {  93, 0, "DP_BS_LK",  "&",                                                         "m"          },
-  {  94, 0, "H_B1_LK",   "&",                                                         "m"          },
-  {  95, 0, "H_ML_LK",   "&",                                                         "m"          },
-  {  96, 0, "DEPTH_LK",  "lake depth",                                                "m"          },
-  {  97, 0, "FETCH_LK",  "wind fetch over lake",                                      "m"          },
-  {  99, 0, "QRS",       "precipitation water (water loading)",                       "1"          },
-  { 100, 0, "PRR_GSP",   "mass flux density of large scale rainfall",                 "kg m-2 s-1" },
-  { 101, 0, "PRS_GSP",   "mass flux density of large scale snowfall",                 "kg m-2 s-1" },
-  { 102, 0, "RAIN_GSP",  "large scale rainfall",                                      "kg m-2"     },
-  { 111, 0, "PRR_CON",   "mass flux density of convective rainfall",                  "kg m-2 s-1" },
-  { 112, 0, "PRS_CON",   "mass flux density of convective snowfall",                  "kg m-2 s-1" },
-  { 113, 0, "RAIN_CON",  "convective rainfall",                                       "kg m-2"     },
-  { 129, 0, "FRESHSNW",  "freshness of snow",                                         "undefined"  },
-  { 131, 0, "PRG_GSP",   "mass flux density of large scale graupel",                  "kg m-2 s-1" },
-  { 132, 0, "GRAU_GSP",  "large scale graupel",                                       "kg m-2"     },
-  { 133, 0, "RHO_SNOW",  "density of snow",                                           "kg m-3"     },
-  { 139, 0, "PP",        "deviation from reference pressure",                         "Pa"         },
-  { 140, 0, "RCLD",      "standard deviation of saturation deficit",                  "undefined"  },
-  { 143, 0, "CAPE_MU",   "cape of most unstable parcel",                              "J kg-1"     },
-  { 144, 0, "CIN_MU",    "convective inhibition of most unstable parcel",             "J kg-1"     },
-  { 145, 0, "CAPE_ML",   "cape of mean surface layer parcel",                         "J kg-1"     },
-  { 146, 0, "CIN_ML",    "convective inhibition of mean surface layer parcel",        "J kg-1"     },
-  { 147, 0, "TKE_CON",   "convective turbulent kinetic energy",                       "undefined"  },
-  { 148, 0, "TKETENS",   "tendency of turbulent kinetic energy",                      "undefined"  },
-  { 152, 0, "TKE",       "turbulent kinetic energy",                                  "m2 s-2"     },
-  { 153, 0, "TKVM",      "diffusion coefficient of momentum",                         "m2 s-1"     },
-  { 154, 0, "TKVH",      "diffusion coefficient of heat",                             "m2 s-1"     },
-  { 170, 0, "TCM",       "drag coefficient of momentum",                              "1"          },
-  { 171, 0, "TCH",       "drag coefficient of heat",                                  "1"          },
-  { 187, 0, "VMAX",      "maximum turbulent wind gust in 10m",                        "m s-1"      },
-  { 190, 0, "TSOIL",     "&",                                                         "K"          },
-  { 191, 0, "TSOIL",     "&",                                                         "K"          },
-  { 192, 0, "TSOIL",     "&",                                                         "K"          },
-  { 193, 0, "TSOIL",     "mixed layer temperature",                                   "K"          },
-  { 194, 0, "TSOIL",     "mean temperature of water column",                          "K"          },
-  { 197, 0, "TSOIL",     "soil temperature",                                          "K"          },
-  { 198, 0, "W_SO",      "soil water content",                                        "m"          },
-  { 199, 0, "W_SO_ICE",  "soil frozen water content",                                 "m"          },
-  { 200, 0, "W_I",       "canopy water amount",                                       "m"          },
-  { 203, 0, "TSOIL",     "snow surface temperature",                                  "K"          },
-  { 215, 0, "TSOIL",     "temperature of ice upper surface",                          "K"          },
-  { 230, 0, "dBZ",       "unattenuated radar reflectivity in Rayleigh approximation", "1"          },
-  { 240, 0, "MFLX_CON",  "convective mass flux density",                              "kg m-2 s-1" },
-  { 241, 0, "CAPE_CON",  "&",                                                         "J kg-1"     },
-  { 243, 0, "QCVG_CON",  "&",                                                         "s-1"        },
+static const param_type cosmo201[] = {
+  {   5, -1, 0, "APAB",      "&",                                                         "W m-2"      },
+  {  13, -1, 0, "SOHR_RAD",  "&",                                                         "K s-1"      },
+  {  14, -1, 0, "THHR_RAD",  "&",                                                         "K s-1"      },
+  {  20, -1, 0, "DURSUN",    "duration of sunshine",                                      "s"          },
+  {  29, -1, 0, "CLC",       "cloud area fraction",                                       "1"          },
+  {  30, -1, 0, "CLC_SGS",   "grid scale cloud area fraction",                            "1"          },
+  {  31, -1, 0, "QC",        "specific cloud liquid water content",                       "kg kg-1"    },
+  {  33, -1, 0, "QI",        "specific cloud ice content",                                "kg kg-1"    },
+  {  35, -1, 0, "QR",        "specific rain content",                                     "kg kg-1"    },
+  {  36, -1, 0, "QS",        "specific snow content",                                     "kg kg-1"    },
+  {  37, -1, 0, "TQR",       "total rain water content vertically integrated",            "kg m-2"     },
+  {  38, -1, 0, "TQS",       "total snow content vertically integrated",                  "kg m-2"     },
+  {  39, -1, 0, "QG",        "specific graupel content",                                  "kg kg-1"    },
+  {  40, -1, 0, "TQG",       "total graupel content vertically integrated",               "kg m-2"     },
+  {  41, -1, 0, "TWATER",    "cloud condensed water content",                             "kg m-2"     },
+  {  42, -1, 0, "TDIV_HUM",  "atmosphere water divergence",                               "kg m-2"     },
+  {  43, -1, 0, "QC_RAD",    "sub scale specific cloud liquid water content",             "kg kg-1"    },
+  {  44, -1, 0, "QI_RAD",    "sub scale specific cloud ice content",                      "kg kg-1"    },
+  {  61, -1, 0, "CLW_CON",   "convective cloud liquid water",                             "1"          },
+  {  68, -1, 0, "HBAS_CON",  "height of convective cloud base",                           "m"          },
+  {  69, -1, 0, "HTOP_CON",  "height of convective cloud top",                            "m"          },
+  {  70, -1, 0, "HBAS_CONI", "height of convective cloud base",                           "m"          },
+  {  71, -1, 0, "HTOP_CONI", "height of convective cloud top",                            "m"          },
+  {  72, -1, 0, "BAS_CON",   "index of convective cloud base",                            "1"          },
+  {  73, -1, 0, "TOP_CON",   "index of convective cloud top",                             "1"          },
+  {  74, -1, 0, "DT_CON",    "convective tendency of temperature",                        "K s-1"      },
+  {  75, -1, 0, "DQV_CON",   "convective tendency of specific humidity",                  "s-1"        },
+  {  78, -1, 0, "DU_CON",    "convective tendency of u-wind component",                   "m s-2"      },
+  {  79, -1, 0, "DV_CON",    "convective tendency of v-wind component",                   "m s-2"      },
+  {  82, -1, 0, "HTOP_DC",   "height of dry convection top",                              "m"          },
+  {  84, -1, 0, "HZEROCL",   "height of freezing level",                                  "m"          },
+  {  85, -1, 0, "SNOWLMT",   "height of the snow fall limit in m above sea level",        "m"          },
+  {  86, -1, 0, "HCBAS",     "height of cloud base",                                      "m"          },
+  {  87, -1, 0, "HCTOP",     "height of cloud top",                                       "m"          },
+  {  91, -1, 0, "C_T_LK",    "&",                                                         "1"          },
+  {  92, -1, 0, "GAMSO_LK",  "&",                                                         "m-1"        },
+  {  93, -1, 0, "DP_BS_LK",  "&",                                                         "m"          },
+  {  94, -1, 0, "H_B1_LK",   "&",                                                         "m"          },
+  {  95, -1, 0, "H_ML_LK",   "&",                                                         "m"          },
+  {  96, -1, 0, "DEPTH_LK",  "lake depth",                                                "m"          },
+  {  97, -1, 0, "FETCH_LK",  "wind fetch over lake",                                      "m"          },
+  {  99, -1, 0, "QRS",       "precipitation water (water loading)",                       "1"          },
+  { 100, -1, 0, "PRR_GSP",   "mass flux density of large scale rainfall",                 "kg m-2 s-1" },
+  { 101, -1, 0, "PRS_GSP",   "mass flux density of large scale snowfall",                 "kg m-2 s-1" },
+  { 102, -1, 0, "RAIN_GSP",  "large scale rainfall",                                      "kg m-2"     },
+  { 111, -1, 0, "PRR_CON",   "mass flux density of convective rainfall",                  "kg m-2 s-1" },
+  { 112, -1, 0, "PRS_CON",   "mass flux density of convective snowfall",                  "kg m-2 s-1" },
+  { 113, -1, 0, "RAIN_CON",  "convective rainfall",                                       "kg m-2"     },
+  { 129, -1, 0, "FRESHSNW",  "freshness of snow",                                         "undefined"  },
+  { 131, -1, 0, "PRG_GSP",   "mass flux density of large scale graupel",                  "kg m-2 s-1" },
+  { 132, -1, 0, "GRAU_GSP",  "large scale graupel",                                       "kg m-2"     },
+  { 133, -1, 0, "RHO_SNOW",  "density of snow",                                           "kg m-3"     },
+  { 139, -1, 0, "PP",        "deviation from reference pressure",                         "Pa"         },
+  { 140, -1, 0, "RCLD",      "standard deviation of saturation deficit",                  "undefined"  },
+  { 143, -1, 0, "CAPE_MU",   "cape of most unstable parcel",                              "J kg-1"     },
+  { 144, -1, 0, "CIN_MU",    "convective inhibition of most unstable parcel",             "J kg-1"     },
+  { 145, -1, 0, "CAPE_ML",   "cape of mean surface layer parcel",                         "J kg-1"     },
+  { 146, -1, 0, "CIN_ML",    "convective inhibition of mean surface layer parcel",        "J kg-1"     },
+  { 147, -1, 0, "TKE_CON",   "convective turbulent kinetic energy",                       "undefined"  },
+  { 148, -1, 0, "TKETENS",   "tendency of turbulent kinetic energy",                      "undefined"  },
+  { 152, -1, 0, "TKE",       "turbulent kinetic energy",                                  "m2 s-2"     },
+  { 153, -1, 0, "TKVM",      "diffusion coefficient of momentum",                         "m2 s-1"     },
+  { 154, -1, 0, "TKVH",      "diffusion coefficient of heat",                             "m2 s-1"     },
+  { 170, -1, 0, "TCM",       "drag coefficient of momentum",                              "1"          },
+  { 171, -1, 0, "TCH",       "drag coefficient of heat",                                  "1"          },
+  { 187, -1, 0, "VMAX",      "maximum turbulent wind gust in 10m",                        "m s-1"      },
+  { 190, -1, 0, "TSOIL",     "&",                                                         "K"          },
+  { 191, -1, 0, "TSOIL",     "&",                                                         "K"          },
+  { 192, -1, 0, "TSOIL",     "&",                                                         "K"          },
+  { 193, -1, 0, "TSOIL",     "mixed layer temperature",                                   "K"          },
+  { 194, -1, 0, "TSOIL",     "mean temperature of water column",                          "K"          },
+  { 197, -1, 0, "TSOIL",     "soil temperature",                                          "K"          },
+  { 198, -1, 0, "W_SO",      "soil water content",                                        "m"          },
+  { 199, -1, 0, "W_SO_ICE",  "soil frozen water content",                                 "m"          },
+  { 200, -1, 0, "W_I",       "canopy water amount",                                       "m"          },
+  { 203, -1, 0, "TSOIL",     "snow surface temperature",                                  "K"          },
+  { 215, -1, 0, "TSOIL",     "temperature of ice upper surface",                          "K"          },
+  { 230, -1, 0, "dBZ",       "unattenuated radar reflectivity in Rayleigh approximation", "1"          },
+  { 240, -1, 0, "MFLX_CON",  "convective mass flux density",                              "kg m-2 s-1" },
+  { 241, -1, 0, "CAPE_CON",  "&",                                                         "J kg-1"     },
+  { 243, -1, 0, "QCVG_CON",  "&",                                                         "s-1"        },
 };
 
-static const PAR cosmo202[] = {
-  {  46, 0, "SSO_STDH",  "standard deviation of subgrid scale height",                "m"         },
-  {  47, 0, "SSO_GAMMA", "anisotropy of topography",                                  "-"         },
-  {  48, 0, "SSO_THETA", "angle between principal axis of orography and global east", "-"         },
-  {  49, 0, "SSO_SIGMA", "mean slope of subgrid scale orography",                     "-"         },
-  {  55, 0, "FR_LAKE",   "fraction of inland lake water",                             "1"         },
-  {  57, 0, "SOILTYP",   "soil type",                                                 "1"         },
-  {  61, 0, "LAI",       "leaf area index",                                           "1"         },
-  {  62, 0, "ROOTDP",    "root depth",                                                "m"         },
-  {  64, 0, "HMO3",      "air pressure at ozone maximum",                             "Pa"        },
-  {  65, 0, "VIO3",      "vertical integrated ozone amount",                          "Pa"        },
-  {  67, 0, "PLCOV_MX",  "vegetation area fraction maximum",                          "1"         },
-  {  68, 0, "PLCOV_MN",  "vegetation area fraction minimum",                          "1"         },
-  {  69, 0, "LAI_MX",    "leaf area index maximum",                                   "1"         },
-  {  70, 0, "LAI_MN",    "leaf area index minimum",                                   "1"         },
-  {  75, 0, "FOR_E",     "ground fraction covered by evergreen forest",               "-"         },
-  {  76, 0, "FOR_D",     "ground fraction covered by deciduous forest",               "-"         },
-  { 104, 0, "DQVDT",     "tendency of water vapor",                                   "s-1"       },
-  { 105, 0, "QVSFLX",    "surface flux of water vapour",                              "s-1m-2"    },
-  { 113, 0, "FC",        "coriolis parameter",                                        "s-1"       },
-  { 114, 0, "RLAT",      "latitude",                                                  "radian"    },
-  { 115, 0, "RLON",      "longitude",                                                 "radian"    },
-  { 121, 0, "ZTD",       "integrated total atmospheric refractivity",                 "undefined" },
-  { 122, 0, "ZWD",       "integrated wet atmospheric refractivity",                   "undefined" },
-  { 123, 0, "ZHD",       "integrated dry atmospheric refractivity",                   "undefined" },
-  { 180, 0, "O3",        "ozone mass mixing ratio",                                   "kg kg-1"   },
-  { 200, 0, "I131a",     "undefined",                                                 "undefined" },
-  { 201, 0, "I131a_DD",  "undefined",                                                 "undefined" },
-  { 202, 0, "I131a_WD",  "undefined",                                                 "undefined" },
-  { 203, 0, "Cs137",     "undefined",                                                 "undefined" },
-  { 204, 0, "Cs137_DD",  "undefined",                                                 "undefined" },
-  { 205, 0, "Cs137_WD",  "undefined",                                                 "undefined" },
-  { 206, 0, "Te132",     "undefined",                                                 "undefined" },
-  { 207, 0, "Te132_DD",  "undefined",                                                 "undefined" },
-  { 208, 0, "Te132_WD",  "undefined",                                                 "undefined" },
-  { 209, 0, "Zr95",      "undefined",                                                 "undefined" },
-  { 210, 0, "Zr95_DD",   "undefined",                                                 "undefined" },
-  { 211, 0, "Zr95_WD",   "undefined",                                                 "undefined" },
-  { 212, 0, "Kr85",      "undefined",                                                 "undefined" },
-  { 213, 0, "Kr85_DD",   "undefined",                                                 "undefined" },
-  { 214, 0, "Kr85_WD",   "undefined",                                                 "undefined" },
-  { 215, 0, "TRACER",    "undefined",                                                 "undefined" },
-  { 216, 0, "TRACER_DD", "undefined",                                                 "undefined" },
-  { 217, 0, "TRACER_WD", "undefined",                                                 "undefined" },
-  { 218, 0, "Xe133",     "undefined",                                                 "undefined" },
-  { 219, 0, "Xe133_DD",  "undefined",                                                 "undefined" },
-  { 220, 0, "Xe133_WD",  "undefined",                                                 "undefined" },
-  { 221, 0, "I131g",     "undefined",                                                 "undefined" },
-  { 222, 0, "I131g_DD",  "undefined",                                                 "undefined" },
-  { 223, 0, "I131g_WD",  "undefined",                                                 "undefined" },
-  { 224, 0, "I131o",     "undefined",                                                 "undefined" },
-  { 225, 0, "I131o_DD",  "undefined",                                                 "undefined" },
-  { 226, 0, "I131o_WD",  "undefined",                                                 "undefined" },
-  { 227, 0, "Ba140",     "undefined",                                                 "undefined" },
-  { 228, 0, "Ba140_DD",  "undefined",                                                 "undefined" },
-  { 229, 0, "Ba140_WD",  "undefined",                                                 "undefined" },
-  { 230, 0, "Sr90",      "undefined",                                                 "undefined" },
-  { 231, 0, "Sr90_DD",   "undefined",                                                 "undefined" },
-  { 232, 0, "Sr90_WD",   "undefined",                                                 "undefined" },
-  { 233, 0, "Ru103",     "undefined",                                                 "undefined" },
-  { 234, 0, "Ru103_DD",  "undefined",                                                 "undefined" },
-  { 235, 0, "Ru103_WD",  "undefined",                                                 "undefined" },
+static const param_type cosmo202[] = {
+  {  46, -1, 0, "SSO_STDH",  "standard deviation of subgrid scale height",                "m"         },
+  {  47, -1, 0, "SSO_GAMMA", "anisotropy of topography",                                  "-"         },
+  {  48, -1, 0, "SSO_THETA", "angle between principal axis of orography and global east", "-"         },
+  {  49, -1, 0, "SSO_SIGMA", "mean slope of subgrid scale orography",                     "-"         },
+  {  55, -1, 0, "FR_LAKE",   "fraction of inland lake water",                             "1"         },
+  {  57, -1, 0, "SOILTYP",   "soil type",                                                 "1"         },
+  {  61, -1, 0, "LAI",       "leaf area index",                                           "1"         },
+  {  62, -1, 0, "ROOTDP",    "root depth",                                                "m"         },
+  {  64, -1, 0, "HMO3",      "air pressure at ozone maximum",                             "Pa"        },
+  {  65, -1, 0, "VIO3",      "vertical integrated ozone amount",                          "Pa"        },
+  {  67, -1, 0, "PLCOV_MX",  "vegetation area fraction maximum",                          "1"         },
+  {  68, -1, 0, "PLCOV_MN",  "vegetation area fraction minimum",                          "1"         },
+  {  69, -1, 0, "LAI_MX",    "leaf area index maximum",                                   "1"         },
+  {  70, -1, 0, "LAI_MN",    "leaf area index minimum",                                   "1"         },
+  {  75, -1, 0, "FOR_E",     "ground fraction covered by evergreen forest",               "-"         },
+  {  76, -1, 0, "FOR_D",     "ground fraction covered by deciduous forest",               "-"         },
+  { 104, -1, 0, "DQVDT",     "tendency of water vapor",                                   "s-1"       },
+  { 105, -1, 0, "QVSFLX",    "surface flux of water vapour",                              "s-1m-2"    },
+  { 113, -1, 0, "FC",        "coriolis parameter",                                        "s-1"       },
+  { 114, -1, 0, "RLAT",      "latitude",                                                  "radian"    },
+  { 115, -1, 0, "RLON",      "longitude",                                                 "radian"    },
+  { 121, -1, 0, "ZTD",       "integrated total atmospheric refractivity",                 "undefined" },
+  { 122, -1, 0, "ZWD",       "integrated wet atmospheric refractivity",                   "undefined" },
+  { 123, -1, 0, "ZHD",       "integrated dry atmospheric refractivity",                   "undefined" },
+  { 180, -1, 0, "O3",        "ozone mass mixing ratio",                                   "kg kg-1"   },
+  { 200, -1, 0, "I131a",     "undefined",                                                 "undefined" },
+  { 201, -1, 0, "I131a_DD",  "undefined",                                                 "undefined" },
+  { 202, -1, 0, "I131a_WD",  "undefined",                                                 "undefined" },
+  { 203, -1, 0, "Cs137",     "undefined",                                                 "undefined" },
+  { 204, -1, 0, "Cs137_DD",  "undefined",                                                 "undefined" },
+  { 205, -1, 0, "Cs137_WD",  "undefined",                                                 "undefined" },
+  { 206, -1, 0, "Te132",     "undefined",                                                 "undefined" },
+  { 207, -1, 0, "Te132_DD",  "undefined",                                                 "undefined" },
+  { 208, -1, 0, "Te132_WD",  "undefined",                                                 "undefined" },
+  { 209, -1, 0, "Zr95",      "undefined",                                                 "undefined" },
+  { 210, -1, 0, "Zr95_DD",   "undefined",                                                 "undefined" },
+  { 211, -1, 0, "Zr95_WD",   "undefined",                                                 "undefined" },
+  { 212, -1, 0, "Kr85",      "undefined",                                                 "undefined" },
+  { 213, -1, 0, "Kr85_DD",   "undefined",                                                 "undefined" },
+  { 214, -1, 0, "Kr85_WD",   "undefined",                                                 "undefined" },
+  { 215, -1, 0, "TRACER",    "undefined",                                                 "undefined" },
+  { 216, -1, 0, "TRACER_DD", "undefined",                                                 "undefined" },
+  { 217, -1, 0, "TRACER_WD", "undefined",                                                 "undefined" },
+  { 218, -1, 0, "Xe133",     "undefined",                                                 "undefined" },
+  { 219, -1, 0, "Xe133_DD",  "undefined",                                                 "undefined" },
+  { 220, -1, 0, "Xe133_WD",  "undefined",                                                 "undefined" },
+  { 221, -1, 0, "I131g",     "undefined",                                                 "undefined" },
+  { 222, -1, 0, "I131g_DD",  "undefined",                                                 "undefined" },
+  { 223, -1, 0, "I131g_WD",  "undefined",                                                 "undefined" },
+  { 224, -1, 0, "I131o",     "undefined",                                                 "undefined" },
+  { 225, -1, 0, "I131o_DD",  "undefined",                                                 "undefined" },
+  { 226, -1, 0, "I131o_WD",  "undefined",                                                 "undefined" },
+  { 227, -1, 0, "Ba140",     "undefined",                                                 "undefined" },
+  { 228, -1, 0, "Ba140_DD",  "undefined",                                                 "undefined" },
+  { 229, -1, 0, "Ba140_WD",  "undefined",                                                 "undefined" },
+  { 230, -1, 0, "Sr90",      "undefined",                                                 "undefined" },
+  { 231, -1, 0, "Sr90_DD",   "undefined",                                                 "undefined" },
+  { 232, -1, 0, "Sr90_WD",   "undefined",                                                 "undefined" },
+  { 233, -1, 0, "Ru103",     "undefined",                                                 "undefined" },
+  { 234, -1, 0, "Ru103_DD",  "undefined",                                                 "undefined" },
+  { 235, -1, 0, "Ru103_WD",  "undefined",                                                 "undefined" },
 };
 
-static const PAR cosmo203[] = {
-  { 135, 0, "LCL_ML",   "undefined",                  "undefined" },
-  { 136, 0, "LFC_ML",   "undefined",                  "undefined" },
-  { 137, 0, "CAPE_3KM", "undefined",                  "undefined" },
-  { 138, 0, "SWISS00",  "swiss00 index",              "1"         },
-  { 139, 0, "SWISS12",  "swiss12 index",              "1"         },
-  { 147, 0, "SLI",      "surface lifted index",       "K"         },
-  { 149, 0, "SI",       "showalter index",            "K"         },
-  { 155, 0, "BRN",      "undefined",                  "undefined" },
-  { 156, 0, "HPBL",     "undefined",                  "undefined" },
-  { 203, 0, "CLDEPTH",  "normalized cloud depth",     "1"         },
-  { 204, 0, "CLCT_MOD", "modified_total_cloud_cover", "1"         },
+static const param_type cosmo203[] = {
+  { 135, -1, 0, "LCL_ML",   "undefined",                  "undefined" },
+  { 136, -1, 0, "LFC_ML",   "undefined",                  "undefined" },
+  { 137, -1, 0, "CAPE_3KM", "undefined",                  "undefined" },
+  { 138, -1, 0, "SWISS00",  "swiss00 index",              "1"         },
+  { 139, -1, 0, "SWISS12",  "swiss12 index",              "1"         },
+  { 147, -1, 0, "SLI",      "surface lifted index",       "K"         },
+  { 149, -1, 0, "SI",       "showalter index",            "K"         },
+  { 155, -1, 0, "BRN",      "undefined",                  "undefined" },
+  { 156, -1, 0, "HPBL",     "undefined",                  "undefined" },
+  { 203, -1, 0, "CLDEPTH",  "normalized cloud depth",     "1"         },
+  { 204, -1, 0, "CLCT_MOD", "modified_total_cloud_cover", "1"         },
 };
 
-static const PAR cosmo205[] = {
-  {   1, 0, "SYNME5", "synthetic satellite images Meteosat5", "-" },
-  {   2, 0, "SYNME6", "synthetic satellite images Meteosat6", "-" },
-  {   3, 0, "SYNME7", "synthetic satellite images Meteosat7", "-" },
-  {   4, 0, "SYNMSG", "synthetic satellite images MSG",       "-" },
+static const param_type cosmo205[] = {
+  {   1, -1, 0, "SYNME5", "synthetic satellite images Meteosat5", "-" },
+  {   2, -1, 0, "SYNME6", "synthetic satellite images Meteosat6", "-" },
+  {   3, -1, 0, "SYNME7", "synthetic satellite images Meteosat7", "-" },
+  {   4, -1, 0, "SYNMSG", "synthetic satellite images MSG",       "-" },
 };
 
-static const PAR cosmo250[] = {
-  {   1, 0, "QNH",       "sea level air pressure",                                         "hPa"                                },
-  {  11, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
-  {  12, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
-  {  13, 0, "D_T_2M_K",  "kalman correction to 2m temperature",                            "K"                                  },
-  {  14, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
-  {  15, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
-  {  16, 0, "RH_ICE",    "relative humidity over ice",                                     "%"                                  },
-  {  17, 0, "TD",        "dew point temperature",                                          "K"                                  },
-  {  18, 0, "D_TD",      "dew point depression",                                           "K"                                  },
-  {  19, 0, "THETAE",    "equivalent potential temperature",                               "K"                                  },
-  {  20, 0, "TD_2M_K",   "2m dew point temperature",                                       "K"                                  },
-  {  21, 0, "D_TD_2M_K", "kalman correction to 2m dew point temperature",                  "K"                                  },
-  {  22, 0, "TD_2M_OLD", "2m dew point temperature",                                       "K"                                  },
-  {  23, 0, "TD_2M_BUZ", "2m dew point temperature",                                       "K"                                  },
-  {  24, 0, "HI",        "heat index",                                                     "Fahrenheit"                         },
-  {  25, 0, "DURSUN_M",  "maximum duration of sunshine",                                   "s"                                  },
-  {  26, 0, "DURSUN_R",  "relative duration of sunshine",                                  "%"                                  },
-  {  52, 0, "RH_2M_K",   "2m relative humidity",                                           "%"                                  },
-  {  53, 0, "D_RH_2M_K", "kalman correction to 2m relative humidity",                      "%"                                  },
-  {  58, 0, "CLI_RATIO", "cloud ice ratio (Qi/Qc+Qi)",                                     "%"                                  },
-  {  61, 0, "TOT_SNOW",  "total precipitation in snow",                                    "kg/m**2"                            },
-  {  62, 0, "TOT_RAIN",  "total precipitation in rain",                                    "kg/m**2"                            },
-  {  63, 0, "TOT_CON",   "total convective precipitation",                                 "kg/m**2"                            },
-  {  64, 0, "TOT_GSP",   "total large scale precipitation",                                "kg/m**2"                            },
-  {  65, 0, "SNOW_%",    "percentage of precipitation in snow",                            "%"                                  },
-  {  66, 0, "CONV_%",    "percentage of convective precipitation",                         "%"                                  },
-  {  67, 0, "VORTP_ABS", "absolute",                                                       "VORTP_ABS 67 -1 absolute vorticity" },
-  {  68, 0, "VORTP_REL", "relative",                                                       "VORTP_REL 68 -1 relative vorticity" },
-  {  70, 0, "PDIFF_CON", "pressure difference between cloud base and cloud top",           "Pa"                                 },
-  {  71, 0, "TTOP_CON",  "temperature at cloud top",                                       "K"                                  },
-  {  80, 0, "GEM",       "emissivity of the ground",                                       "%"                                  },
-  {  82, 0, "Z0LOC",     "local surface roughness length",                                 "m"                                  },
-  { 110, 0, "LUM",       "luminosity",                                                     "klux"                               },
-  { 111, 0, "GLOB",      "global shortwave radiation at surface",                          "W/m**2"                             },
-  { 112, 0, "LW_IN_TG",  "incoming longwave radiation at surface",                         "W/m**2"                             },
-  { 113, 0, "LW_IN_TS",  "incoming longwave radiation at surface",                         "W/m**2"                             },
-  { 114, 0, "LW_IN_T2M", "incoming longwave radiation at surface",                         "W/m**2"                             },
-  { 115, 0, "SWISS_WE",  "Swiss",                                                          "SWISS_WE 115 1 Swiss coordinates"   },
-  { 116, 0, "SWISS_SN",  "Swiss",                                                          "SWISS_SN 116 1 Swiss coordinates"   },
-  { 150, 0, "KOINDEX",   "KO index",                                                       "K"                                  },
-  { 151, 0, "TTINDEX",   "total-totals index",                                             "K"                                  },
-  { 152, 0, "DCI",       "deep convection index",                                          "K"                                  },
-  { 153, 0, "SWEAT",     "severe weather thread index",                                    "undefined"                          },
-  { 154, 0, "ADEDO2",    "adedokun 2 index",                                               "K"                                  },
-  { 160, 0, "C_TSTORM",  "thunderstorm index using AdaBoost classifier",                   "undefined"                          },
-  { 161, 0, "CN_TSTORM", "thunderstorm probabilty using AdaBoost classifier",              "%"                                  },
-  { 200, 0, "WSHEARL",   "wind shear between surface and 3 km asl",                        "1/s"                                },
-  { 201, 0, "WSHEARM",   "wind shear between surface and 6 km asl",                        "1/s"                                },
-  { 202, 0, "WSHEARU",   "wind shear between 3 km (or surface) and 6 km asl",              "1/s"                                },
-  { 211, 0, "VWIN",      "maximum OLD turbulent wind gust in 10m",                         "m s-1"                              },
-  { 212, 0, "VW10M_20",  "maximum 10m wind speed",                                         "m s-1"                              },
-  { 213, 0, "VW10M_25",  "duration of VWIN_10M above 25 knots",                            "s"                                  },
-  { 214, 0, "VW10M_30",  "duration of VWIN_10M above 30 knots",                            "s"                                  },
-  { 215, 0, "VW10M_35",  "duration of VWIN_10M above 35 knots",                            "s"                                  },
-  { 216, 0, "VW10M_40",  "duration of VWIN_10M above 40 knots",                            "s"                                  },
-  { 217, 0, "VW10M_45",  "duration of VWIN_10M above 45 knots",                            "s"                                  },
-  { 218, 0, "VW10M_50",  "duration of VWIN_10M above 50 knots",                            "s"                                  },
-  { 219, 0, "VOLD",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
-  { 220, 0, "VJPS",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
-  { 221, 0, "VBRA",      "maximum Brasseur turbulent wind gust in 10m",                    "m s-1"                              },
-  { 222, 0, "VB10M_20",  "duration of VBRA_10M above 20 knots",                            "s"                                  },
-  { 223, 0, "VB10M_25",  "duration of VBRA_10M above 25 knots",                            "s"                                  },
-  { 224, 0, "VB10M_30",  "duration of VBRA_10M above 30 knots",                            "s"                                  },
-  { 225, 0, "VB10M_35",  "duration of VBRA_10M above 35 knots",                            "s"                                  },
-  { 226, 0, "VB10M_40",  "duration of VBRA_10M above 40 knots",                            "s"                                  },
-  { 227, 0, "VB10M_45",  "duration of VBRA_10M above 45 knots",                            "s"                                  },
-  { 228, 0, "VB10M_50",  "duration of VBRA_10M above 50 knots",                            "s"                                  },
-  { 231, 0, "VCON",      "maximum convective wind gust in 10m",                            "m s-1"                              },
-  { 232, 0, "VC10M_20",  "duration of VCON_10M above 20 knots",                            "s"                                  },
-  { 233, 0, "VC10M_25",  "duration of VCON_10M above 25 knots",                            "s"                                  },
-  { 234, 0, "VC10M_30",  "duration of VCON_10M above 30 knots",                            "s"                                  },
-  { 235, 0, "VC10M_35",  "duration of VCON_10M above 35 knots",                            "s"                                  },
-  { 236, 0, "VC10M_40",  "duration of VCON_10M above 40 knots",                            "s"                                  },
-  { 237, 0, "VC10M_45",  "duration of VCON_10M above 45 knots",                            "s"                                  },
-  { 238, 0, "VC10M_50",  "duration of VCON_10M above 50 knots",                            "s"                                  },
-  { 241, 0, "FMAX",      "maximum wind speed at k=ke",                                     "m s-1"                              },
-  { 242, 0, "USTARMAX",  "maximal u*=SQRT(Drag_coef)*fmax_10m",                            "m s-1"                              },
-  { 243, 0, "GLOB_DIF",  "global diffuse shortwave radiation at the surface",              "W/m**2"                             },
-  { 244, 0, "GLOB_DIR",  "global direct (beam) shortwave radiation at the surface",        "W/m**2"                             },
-  { 245, 0, "GLOB_vE",   "global shortwave radiation on a vertical surface facing east",   "W/m**2"                             },
-  { 246, 0, "GLOB_vS",   "global shortwave radiation on a vertical surface facing south",  "W/m**2"                             },
-  { 247, 0, "GLOB_vW",   "global shortwave radiation on a vertical surface facing west",   "W/m**2"                             },
-  { 248, 0, "GLOB_vN",   "global shortwave radiation on a vertical surface facing north",  "W/m**2"                             },
-  { 249, 0, "LW_TG_vS",  "incoming longwave radiation on a vertical surface facing south", "W/m**2"                             },
-  { 250, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
-  { 251, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
-  { 252, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
-  { 253, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
-  { 254, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
-  { 255, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
+static const param_type cosmo250[] = {
+  {   1, -1, 0, "QNH",       "sea level air pressure",                                         "hPa"                                },
+  {  11, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
+  {  12, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
+  {  13, -1, 0, "D_T_2M_K",  "kalman correction to 2m temperature",                            "K"                                  },
+  {  14, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
+  {  15, -1, 0, "TSOIL",     "2m temperature",                                                 "K"                                  },
+  {  16, -1, 0, "RH_ICE",    "relative humidity over ice",                                     "%"                                  },
+  {  17, -1, 0, "TD",        "dew point temperature",                                          "K"                                  },
+  {  18, -1, 0, "D_TD",      "dew point depression",                                           "K"                                  },
+  {  19, -1, 0, "THETAE",    "equivalent potential temperature",                               "K"                                  },
+  {  20, -1, 0, "TD_2M_K",   "2m dew point temperature",                                       "K"                                  },
+  {  21, -1, 0, "D_TD_2M_K", "kalman correction to 2m dew point temperature",                  "K"                                  },
+  {  22, -1, 0, "TD_2M_OLD", "2m dew point temperature",                                       "K"                                  },
+  {  23, -1, 0, "TD_2M_BUZ", "2m dew point temperature",                                       "K"                                  },
+  {  24, -1, 0, "HI",        "heat index",                                                     "Fahrenheit"                         },
+  {  25, -1, 0, "DURSUN_M",  "maximum duration of sunshine",                                   "s"                                  },
+  {  26, -1, 0, "DURSUN_R",  "relative duration of sunshine",                                  "%"                                  },
+  {  52, -1, 0, "RH_2M_K",   "2m relative humidity",                                           "%"                                  },
+  {  53, -1, 0, "D_RH_2M_K", "kalman correction to 2m relative humidity",                      "%"                                  },
+  {  58, -1, 0, "CLI_RATIO", "cloud ice ratio (Qi/Qc+Qi)",                                     "%"                                  },
+  {  61, -1, 0, "TOT_SNOW",  "total precipitation in snow",                                    "kg/m**2"                            },
+  {  62, -1, 0, "TOT_RAIN",  "total precipitation in rain",                                    "kg/m**2"                            },
+  {  63, -1, 0, "TOT_CON",   "total convective precipitation",                                 "kg/m**2"                            },
+  {  64, -1, 0, "TOT_GSP",   "total large scale precipitation",                                "kg/m**2"                            },
+  {  65, -1, 0, "SNOW_%",    "percentage of precipitation in snow",                            "%"                                  },
+  {  66, -1, 0, "CONV_%",    "percentage of convective precipitation",                         "%"                                  },
+  {  67, -1, 0, "VORTP_ABS", "absolute",                                                       "VORTP_ABS 67 -1 absolute vorticity" },
+  {  68, -1, 0, "VORTP_REL", "relative",                                                       "VORTP_REL 68 -1 relative vorticity" },
+  {  70, -1, 0, "PDIFF_CON", "pressure difference between cloud base and cloud top",           "Pa"                                 },
+  {  71, -1, 0, "TTOP_CON",  "temperature at cloud top",                                       "K"                                  },
+  {  80, -1, 0, "GEM",       "emissivity of the ground",                                       "%"                                  },
+  {  82, -1, 0, "Z0LOC",     "local surface roughness length",                                 "m"                                  },
+  { 110, -1, 0, "LUM",       "luminosity",                                                     "klux"                               },
+  { 111, -1, 0, "GLOB",      "global shortwave radiation at surface",                          "W/m**2"                             },
+  { 112, -1, 0, "LW_IN_TG",  "incoming longwave radiation at surface",                         "W/m**2"                             },
+  { 113, -1, 0, "LW_IN_TS",  "incoming longwave radiation at surface",                         "W/m**2"                             },
+  { 114, -1, 0, "LW_IN_T2M", "incoming longwave radiation at surface",                         "W/m**2"                             },
+  { 115, -1, 0, "SWISS_WE",  "Swiss",                                                          "SWISS_WE 115 1 Swiss coordinates"   },
+  { 116, -1, 0, "SWISS_SN",  "Swiss",                                                          "SWISS_SN 116 1 Swiss coordinates"   },
+  { 150, -1, 0, "KOINDEX",   "KO index",                                                       "K"                                  },
+  { 151, -1, 0, "TTINDEX",   "total-totals index",                                             "K"                                  },
+  { 152, -1, 0, "DCI",       "deep convection index",                                          "K"                                  },
+  { 153, -1, 0, "SWEAT",     "severe weather thread index",                                    "undefined"                          },
+  { 154, -1, 0, "ADEDO2",    "adedokun 2 index",                                               "K"                                  },
+  { 160, -1, 0, "C_TSTORM",  "thunderstorm index using AdaBoost classifier",                   "undefined"                          },
+  { 161, -1, 0, "CN_TSTORM", "thunderstorm probabilty using AdaBoost classifier",              "%"                                  },
+  { 200, -1, 0, "WSHEARL",   "wind shear between surface and 3 km asl",                        "1/s"                                },
+  { 201, -1, 0, "WSHEARM",   "wind shear between surface and 6 km asl",                        "1/s"                                },
+  { 202, -1, 0, "WSHEARU",   "wind shear between 3 km (or surface) and 6 km asl",              "1/s"                                },
+  { 211, -1, 0, "VWIN",      "maximum OLD turbulent wind gust in 10m",                         "m s-1"                              },
+  { 212, -1, 0, "VW10M_20",  "maximum 10m wind speed",                                         "m s-1"                              },
+  { 213, -1, 0, "VW10M_25",  "duration of VWIN_10M above 25 knots",                            "s"                                  },
+  { 214, -1, 0, "VW10M_30",  "duration of VWIN_10M above 30 knots",                            "s"                                  },
+  { 215, -1, 0, "VW10M_35",  "duration of VWIN_10M above 35 knots",                            "s"                                  },
+  { 216, -1, 0, "VW10M_40",  "duration of VWIN_10M above 40 knots",                            "s"                                  },
+  { 217, -1, 0, "VW10M_45",  "duration of VWIN_10M above 45 knots",                            "s"                                  },
+  { 218, -1, 0, "VW10M_50",  "duration of VWIN_10M above 50 knots",                            "s"                                  },
+  { 219, -1, 0, "VOLD",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
+  { 220, -1, 0, "VJPS",      "maximum turbulent wind gust in 10m",                             "m s-1"                              },
+  { 221, -1, 0, "VBRA",      "maximum Brasseur turbulent wind gust in 10m",                    "m s-1"                              },
+  { 222, -1, 0, "VB10M_20",  "duration of VBRA_10M above 20 knots",                            "s"                                  },
+  { 223, -1, 0, "VB10M_25",  "duration of VBRA_10M above 25 knots",                            "s"                                  },
+  { 224, -1, 0, "VB10M_30",  "duration of VBRA_10M above 30 knots",                            "s"                                  },
+  { 225, -1, 0, "VB10M_35",  "duration of VBRA_10M above 35 knots",                            "s"                                  },
+  { 226, -1, 0, "VB10M_40",  "duration of VBRA_10M above 40 knots",                            "s"                                  },
+  { 227, -1, 0, "VB10M_45",  "duration of VBRA_10M above 45 knots",                            "s"                                  },
+  { 228, -1, 0, "VB10M_50",  "duration of VBRA_10M above 50 knots",                            "s"                                  },
+  { 231, -1, 0, "VCON",      "maximum convective wind gust in 10m",                            "m s-1"                              },
+  { 232, -1, 0, "VC10M_20",  "duration of VCON_10M above 20 knots",                            "s"                                  },
+  { 233, -1, 0, "VC10M_25",  "duration of VCON_10M above 25 knots",                            "s"                                  },
+  { 234, -1, 0, "VC10M_30",  "duration of VCON_10M above 30 knots",                            "s"                                  },
+  { 235, -1, 0, "VC10M_35",  "duration of VCON_10M above 35 knots",                            "s"                                  },
+  { 236, -1, 0, "VC10M_40",  "duration of VCON_10M above 40 knots",                            "s"                                  },
+  { 237, -1, 0, "VC10M_45",  "duration of VCON_10M above 45 knots",                            "s"                                  },
+  { 238, -1, 0, "VC10M_50",  "duration of VCON_10M above 50 knots",                            "s"                                  },
+  { 241, -1, 0, "FMAX",      "maximum wind speed at k=ke",                                     "m s-1"                              },
+  { 242, -1, 0, "USTARMAX",  "maximal u*=SQRT(Drag_coef)*fmax_10m",                            "m s-1"                              },
+  { 243, -1, 0, "GLOB_DIF",  "global diffuse shortwave radiation at the surface",              "W/m**2"                             },
+  { 244, -1, 0, "GLOB_DIR",  "global direct (beam) shortwave radiation at the surface",        "W/m**2"                             },
+  { 245, -1, 0, "GLOB_vE",   "global shortwave radiation on a vertical surface facing east",   "W/m**2"                             },
+  { 246, -1, 0, "GLOB_vS",   "global shortwave radiation on a vertical surface facing south",  "W/m**2"                             },
+  { 247, -1, 0, "GLOB_vW",   "global shortwave radiation on a vertical surface facing west",   "W/m**2"                             },
+  { 248, -1, 0, "GLOB_vN",   "global shortwave radiation on a vertical surface facing north",  "W/m**2"                             },
+  { 249, -1, 0, "LW_TG_vS",  "incoming longwave radiation on a vertical surface facing south", "W/m**2"                             },
+  { 250, -1, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
+  { 251, -1, 0, "ENTH",      "enthalpy",                                                       "kJ/kg"                              },
+  { 252, -1, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
+  { 253, -1, 0, "MIXRAT",    "mixing ratio",                                                   "g/kg"                               },
+  { 254, -1, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
+  { 255, -1, 0, "TW",        "wet bulb temperature",                                           "degC"                               },
 };
 
 
 static
 void tableDefault(void)
 {
-  int tableID, instID, modelID;
 
+  // define table : echam4
+  {
+    int instID  = institutInq(98, 255, "MPIMET", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(98, 255, "MPIMET", NULL);
 
-  /*
-   *  define table : echam4
-   */
-
-  instID  = institutInq(98, 255, "MPIMET", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(98, 255, "MPIMET", NULL);
-
-  modelID = modelInq(instID, 0, "ECHAM4");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "ECHAM4");
-
-  tableID = tableDef(modelID, 128, "echam4");
-
-  tableLink(tableID, echam4, sizeof(echam4) / sizeof(PAR));
-
-  /*
-   *  define table : echam5
-   */
-
-  instID  = institutInq(0, 0, "MPIMET", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MPIMET", NULL);
-
-  modelID = modelInq(instID, 0, "ECHAM5");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "ECHAM5");
-
-  tableID = tableDef(modelID, 128, "echam5");
-
-  tableLink(tableID, echam5, sizeof(echam5) / sizeof(PAR));
-
-  /*
-   *  define table : echam6
-   */
-
-  instID  = institutInq(0, 0, "MPIMET", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MPIMET", NULL);
-
-  modelID = modelInq(instID, 0, "ECHAM6");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "ECHAM6");
-
-  tableID = tableDef(modelID, 128, "echam6");
+    int modelID = modelInq(instID, 0, "ECHAM4");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "ECHAM4");
 
-  tableLink(tableID, echam6, sizeof(echam6) / sizeof(PAR));
+    int tableID = tableDef(modelID, 128, "echam4");
 
-  /*
-   *  define table : mpiom1
-   */
+    tableLink(tableID, echam4, sizeof(echam4) / sizeof(param_type));
+  }
 
-  instID  = institutInq(0, 0, "MPIMET", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MPIMET", NULL);
+  // define table : echam5
+  {
+    int instID  = institutInq(0, 0, "MPIMET", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MPIMET", NULL);
 
-  modelID = modelInq(instID, 0, "MPIOM1");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "MPIOM1");
+    int modelID = modelInq(instID, 0, "ECHAM5");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "ECHAM5");
 
-  tableID = tableDef(modelID, 128, "mpiom1");
+    int tableID = tableDef(modelID, 128, "echam5");
 
-  tableLink(tableID, mpiom1, sizeof(mpiom1) / sizeof(PAR));
+    tableLink(tableID, echam5, sizeof(echam5) / sizeof(param_type));
+  }
 
-  /*
-   *  define table : ecmwf
-   */
+  // define table : echam6
+  {
+    int instID  = institutInq(0, 0, "MPIMET", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MPIMET", NULL);
 
-  instID  = institutInq(0, 0, "ECMWF", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "ECMWF", NULL);
+    int modelID = modelInq(instID, 0, "ECHAM6");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "ECHAM6");
 
-  modelID = modelInq(instID, 0, "");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "");
+    int tableID = tableDef(modelID, 128, "echam6");
 
-  tableID = tableDef(modelID, 128, "ecmwf");
+    tableLink(tableID, echam6, sizeof(echam6) / sizeof(param_type));
+  }
 
-  tableLink(tableID, ecmwf, sizeof(ecmwf) / sizeof(PAR));
+  // define table : mpiom1
+  {
+    int instID  = institutInq(0, 0, "MPIMET", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MPIMET", NULL);
 
-  /*
-   *  define table : remo
-   */
+    int modelID = modelInq(instID, 0, "MPIOM1");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "MPIOM1");
 
-  instID  = institutInq(0, 0, "MPIMET", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MPIMET", NULL);
+    int tableID = tableDef(modelID, 128, "mpiom1");
 
-  modelID = modelInq(instID, 0, "REMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "REMO");
+    tableLink(tableID, mpiom1, sizeof(mpiom1) / sizeof(param_type));
+  }
 
-  tableID = tableDef(modelID, 128, "remo");
+  // define table : ecmwf
+  {
+    int instID  = institutInq(0, 0, "ECMWF", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "ECMWF", NULL);
 
-  tableLink(tableID, remo, sizeof(remo) / sizeof(PAR));
+    int modelID = modelInq(instID, 0, "");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "");
 
-  /*
-   *  define table : cosmo002
-   */
+    int tableID = tableDef(modelID, 128, "ecmwf");
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+    tableLink(tableID, ecmwf, sizeof(ecmwf) / sizeof(param_type));
+  }
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+  // define table : remo
+  {
+    int instID  = institutInq(0, 0, "MPIMET", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MPIMET", NULL);
 
-  tableID = tableDef(modelID, 002, "cosmo002");
+    int modelID = modelInq(instID, 0, "REMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "REMO");
 
-  tableLink(tableID, cosmo002, sizeof(cosmo002) / sizeof(PAR));
+    int tableID = tableDef(modelID, 128, "remo");
 
-  /*
-   *  define table : cosmo201
-   */
+    tableLink(tableID, remo, sizeof(remo) / sizeof(param_type));
+  }
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+  // define table : cosmo002
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  tableID = tableDef(modelID, 201, "cosmo201");
+    int tableID = tableDef(modelID, 002, "cosmo002");
 
-  tableLink(tableID, cosmo201, sizeof(cosmo201) / sizeof(PAR));
+    tableLink(tableID, cosmo002, sizeof(cosmo002) / sizeof(param_type));
+  }
 
-  /*
-   *  define table : cosmo202
-   */
+  // define table : cosmo201
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+    int tableID = tableDef(modelID, 201, "cosmo201");
 
-  tableID = tableDef(modelID, 202, "cosmo202");
+    tableLink(tableID, cosmo201, sizeof(cosmo201) / sizeof(param_type));
+  }
 
-  tableLink(tableID, cosmo202, sizeof(cosmo202) / sizeof(PAR));
+  // define table : cosmo202
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  /*
-   *  define table : cosmo203
-   */
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+    int tableID = tableDef(modelID, 202, "cosmo202");
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+    tableLink(tableID, cosmo202, sizeof(cosmo202) / sizeof(param_type));
+  }
 
-  tableID = tableDef(modelID, 203, "cosmo203");
+  // define table : cosmo203
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  tableLink(tableID, cosmo203, sizeof(cosmo203) / sizeof(PAR));
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  /*
-   *  define table : cosmo205
-   */
+    int tableID = tableDef(modelID, 203, "cosmo203");
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+    tableLink(tableID, cosmo203, sizeof(cosmo203) / sizeof(param_type));
+  }
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+  // define table : cosmo205
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  tableID = tableDef(modelID, 205, "cosmo205");
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  tableLink(tableID, cosmo205, sizeof(cosmo205) / sizeof(PAR));
+    int tableID = tableDef(modelID, 205, "cosmo205");
 
-  /*
-   *  define table : cosmo250
-   */
+    tableLink(tableID, cosmo205, sizeof(cosmo205) / sizeof(param_type));
+  }
 
-  instID  = institutInq(0, 0, "MCH", NULL);
-  if ( instID == -1 )
-    instID  = institutDef(0, 0, "MCH", NULL);
+  // define table : cosmo250
+  {
+    int instID  = institutInq(0, 0, "MCH", NULL);
+    if ( instID == -1 )
+      instID  = institutDef(0, 0, "MCH", NULL);
 
-  modelID = modelInq(instID, 0, "COSMO");
-  if ( modelID == -1 )
-    modelID = modelDef(instID, 0, "COSMO");
+    int modelID = modelInq(instID, 0, "COSMO");
+    if ( modelID == -1 )
+      modelID = modelDef(instID, 0, "COSMO");
 
-  tableID = tableDef(modelID, 250, "cosmo250");
+    int tableID = tableDef(modelID, 250, "cosmo250");
 
-  tableLink(tableID, cosmo250, sizeof(cosmo250) / sizeof(PAR));
+    tableLink(tableID, cosmo250, sizeof(cosmo250) / sizeof(param_type));
+  }
 }
 
-#endif  /* _TABLE_H */
+#endif  /* TABLE_H */
 #if defined (HAVE_CONFIG_H)
 #endif
 
@@ -59293,8 +59358,6 @@ void tableDefault(void)
 #include <string.h>
 
 
-#undef  UNDEFID
-#define UNDEFID -1
 
 /*int TableDefine = 0; */ /* Define new table also if the entry already exist */
                           /* This is needed for createtable */
@@ -59305,16 +59368,16 @@ void tableDefault(void)
 
 typedef struct
 {
-  int    used;
+  bool   used;
   int    npars;
-  PAR   *pars;
   int    modelID;
   int    number;
   char  *name;
+  param_type *pars;
 }
-PARTAB;
+paramtab_type;
 
-static PARTAB parTable[MAX_TABLE];
+static paramtab_type parTable[MAX_TABLE];
 static int  parTableSize = MAX_TABLE;
 static int  parTableNum  = 0;
 static int  ParTableInit = 0;
@@ -59324,16 +59387,16 @@ static char *tablePath = NULL;
 static void tableDefModelID(int tableID, int modelID);
 static void tableDefNum(int tableID, int tablenum);
 
-
-void tableDefEntry(int tableID, int id, const char *name,
+static
+void tableDefEntry(int tableID, int id, int ltype, const char *name,
 		   const char *longname, const char *units)
 {
-  int item;
-
   if ( tableID >= 0 && tableID < MAX_TABLE && parTable[tableID].used) { } else
     Error("Invalid table ID %d", tableID);
-  item = parTable[tableID].npars++;
+
+  int item = parTable[tableID].npars++;
   parTable[tableID].pars[item].id       = id;
+  parTable[tableID].pars[item].ltype    = ltype;
   parTable[tableID].pars[item].dupflags = 0;
   parTable[tableID].pars[item].name     = NULL;
   parTable[tableID].pars[item].longname = NULL;
@@ -59356,13 +59419,12 @@ void tableDefEntry(int tableID, int id, const char *name,
     }
 }
 
-static void tableLink(int tableID, const PAR *pars, int npars)
+static void tableLink(int tableID, const param_type *pars, int npars)
 {
-  int item;
-
-  for ( item = 0; item < npars; item++ )
+  for ( int item = 0; item < npars; item++ )
     {
       parTable[tableID].pars[item].id       = pars[item].id;
+      parTable[tableID].pars[item].ltype    = pars[item].ltype;
       parTable[tableID].pars[item].dupflags = 0;
       parTable[tableID].pars[item].name     = pars[item].name;
       parTable[tableID].pars[item].longname = pars[item].longname;
@@ -59374,19 +59436,17 @@ static void tableLink(int tableID, const PAR *pars, int npars)
 
 static void parTableInitEntry(int tableID)
 {
-  parTable[tableID].used    = 0;
+  parTable[tableID].used    = false;
   parTable[tableID].pars    = NULL;
   parTable[tableID].npars   = 0;
-  parTable[tableID].modelID = UNDEFID;
-  parTable[tableID].number  = UNDEFID;
+  parTable[tableID].modelID = CDI_UNDEFID;
+  parTable[tableID].number  = CDI_UNDEFID;
   parTable[tableID].name    = NULL;
 }
 
 static void tableGetPath(void)
 {
-  char *path;
-
-  path = getenv("TABLEPATH");
+  char *path = getenv("TABLEPATH");
 
   if ( path ) tablePath = strdupx(path);
   /*
@@ -59448,10 +59508,10 @@ static int tableNewEntry()
   if ( tableID == parTableSize )
     Error("no more entries!");
 
-  parTable[tableID].used = 1;
+  parTable[tableID].used = true;
   parTableNum++;
 
-  return (tableID);
+  return tableID;
 }
 
 static int
@@ -59472,9 +59532,9 @@ decodeForm1(char *pline, char *name, char *longname, char *units)
       name[len] = 0;
     }
   else
-    return (0);
+    return 0;
 
-  if ( pline[0] == 0 ) return (0);
+  if ( pline[0] == 0 ) return 0;
 
   /* Format 1 : code name add mult longname [units] */
   /* FIXME: successful parse isn't verified */
@@ -59511,7 +59571,7 @@ decodeForm1(char *pline, char *name, char *longname, char *units)
 	  pstart++;
 	  while ( isspace((int) *pstart) ) pstart++;
 	  pend = strchr(pstart, ']');
-	  if ( ! pend ) return (0);
+	  if ( ! pend ) return 0;
 	  pend--;
 	  while ( isspace((int) *pend) ) pend--;
 	  len = (size_t)(pend - pstart + 1);
@@ -59523,7 +59583,7 @@ decodeForm1(char *pline, char *name, char *longname, char *units)
 	}
     }
 
-  return (0);
+  return 0;
 }
 
 static int
@@ -59549,7 +59609,7 @@ decodeForm2(char *pline, char *name, char *longname, char *units)
               memcpy(name, pline, len);
               name[len] = 0;
             }
-          return (0);
+          return 0;
         }
       else
         {
@@ -59597,24 +59657,22 @@ decodeForm2(char *pline, char *name, char *longname, char *units)
       units[len] = 0;
     }
 
-  return (0);
+  return 0;
 }
 
+
 int tableRead(const char *tablefile)
 {
   char line[1024], *pline;
   int lnr = 0;
-  int id;
   char name[256], longname[256], units[256];
-  int tableID = UNDEFID;
   int err;
-  char *tablename;
-  FILE *tablefp;
+  int tableID = CDI_UNDEFID;
 
-  tablefp = fopen(tablefile, "r");
-  if ( tablefp == NULL ) return (tableID);
+  FILE *tablefp = fopen(tablefile, "r");
+  if ( tablefp == NULL ) return tableID;
 
-  tablename = (char* )strrchr(tablefile, '/');
+  char *tablename = (char* )strrchr(tablefile, '/');
   if ( tablename == 0 ) tablename = (char *) tablefile;
   else                  tablename++;
 
@@ -59625,7 +59683,8 @@ int tableRead(const char *tablefile)
       size_t len = strlen(line);
       if ( line[len-1] == '\n' ) line[len-1] = '\0';
       lnr++;
-      id       = CDI_UNDEFID;
+      int id      = CDI_UNDEFID;
+      int ltype   = CDI_UNDEFID;
       name[0]     = 0;
       longname[0] = 0;
       units[0]    = 0;
@@ -59643,6 +59702,21 @@ int tableRead(const char *tablefile)
 
       while ( isdigit((int) *pline) ) pline++;
 
+      if ( *pline == ';' || *pline == ':' )
+        {
+          pline++;
+          ltype = atoi(pline);
+          while ( isdigit((int) *pline) ) pline++;
+
+          if ( *pline == ';' || *pline == ':' )
+            {
+              pline++;
+              while ( isdigit((int) *pline) ) pline++;
+            }
+        }
+
+      while ( isdigit((int) *pline) ) pline++;
+
       if ( strchr(pline, '|') )
 	err = decodeForm2(pline, name, longname, units);
       else
@@ -59652,86 +59726,67 @@ int tableRead(const char *tablefile)
 
       if ( name[0] == 0 ) sprintf(name, "var%d", id);
 
-      tableDefEntry(tableID, id, name, longname, units);
+      tableDefEntry(tableID, id, ltype, name, longname, units);
     }
 
-  return (tableID);
+  return tableID;
 }
 
+
 static int tableFromEnv(int modelID, int tablenum)
 {
-  int tableID = UNDEFID;
   char tablename[256] = {'\0'};
-  int tablenamefound = 0;
+  size_t tablenameLen = 0;
+  int instID;
 
-  const char *modelName;
-  if ( (modelName = modelInqNamePtr(modelID)) )
-    {
-      strcpy(tablename, modelName);
-      if ( tablenum )
-	{
-	  size_t len = strlen(tablename);
-	  sprintf(tablename+len, "_%03d", tablenum);
-	}
-      tablenamefound = 1;
+  const char *name2Use;
+  {
+    const char *modelName, *instName;
+    if ( (modelName = modelInqNamePtr(modelID)) )
+      name2Use = modelName;
+    else if ( (instID = modelInqInstitut(modelID)) != CDI_UNDEFID
+              && (instName = institutInqNamePtr(instID)) )
+      name2Use = instName;
+    else
+      return CDI_UNDEFID;
+  }
+  tablenameLen = strlen(name2Use);
+  memcpy(tablename, name2Use, tablenameLen);
+  if ( tablenum )
+    tablenameLen
+      += (size_t)(sprintf(tablename+tablenameLen, "_%03d", tablenum));
+  size_t lenp = 0, lenf = tablenameLen;
+  if ( tablePath )
+    lenp = strlen(tablePath);
+  /* if (tablePath) printf("tablePath = %s\n", tablePath); */
+  /* if (tablename) printf("tableName = %s\n", tablename); */
+  char *tablefile = (char *) Malloc(lenp+lenf+3);
+  if ( tablePath )
+    {
+      strcpy(tablefile, tablePath);
+      strcat(tablefile, "/");
     }
   else
-    {
-      int instID = modelInqInstitut(modelID);
-      if ( instID != UNDEFID )
-	{
-          const char *instName;
-	  if ( (instName = institutInqNamePtr(instID)) )
-	    {
-	      strcpy(tablename, instName);
-	      if ( tablenum )
-		{
-		  size_t len = strlen(tablename);
-		  sprintf(tablename+len, "_%03d", tablenum);
-		}
-	      tablenamefound = 1;
-	    }
-	}
-    }
+    tablefile[0] = '\0';
+  strcat(tablefile, tablename);
+  /* if (tablefile) printf("tableFile = %s\n", tablefile); */
 
-  if ( tablenamefound )
+  int tableID = tableRead(tablefile);
+  if ( tableID != CDI_UNDEFID )
     {
-      size_t lenp = 0, lenf;
-      char *tablefile = NULL;
-      if ( tablePath )
-	lenp = strlen(tablePath);
-      lenf = strlen(tablename);
-      /* if (tablePath) printf("tablePath = %s\n", tablePath); */
-      /* if (tablename) printf("tableName = %s\n", tablename); */
-      tablefile = (char *) Malloc(lenp+lenf+3);
-      if ( tablePath )
-	{
-	  strcpy(tablefile, tablePath);
-	  strcat(tablefile, "/");
-	}
-      else
-	tablefile[0] = '\0';
-      strcat(tablefile, tablename);
-      /* if (tablefile) printf("tableFile = %s\n", tablefile); */
-
-      tableID = tableRead(tablefile);
-      if ( tableID != UNDEFID )
-	{
-	  tableDefModelID(tableID, modelID);
-	  tableDefNum(tableID, tablenum);
-	}
-      /* printf("tableID = %d %s\n", tableID, tablefile); */
-
-      Free(tablefile);
+      tableDefModelID(tableID, modelID);
+      tableDefNum(tableID, tablenum);
     }
+  /* printf("tableID = %d %s\n", tableID, tablefile); */
+  Free(tablefile);
 
-  return (tableID);
+  return tableID;
 }
 
 int tableInq(int modelID, int tablenum, const char *tablename)
 {
-  int tableID = UNDEFID;
-  int modelID2 = UNDEFID;
+  int tableID = CDI_UNDEFID;
+  int modelID2 = CDI_UNDEFID;
   char tablefile[256] = {'\0'};
 
   if ( ! ParTableInit ) parTableInit();
@@ -59753,7 +59808,7 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 	      if ( memcmp(parTable[tableID].name, tablename, len) == 0 ) break;
 	    }
 	}
-      if ( tableID == MAX_TABLE ) tableID = UNDEFID;
+      if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
       if ( CDI_Debug )
 	Message("tableID = %d tablename = %s", tableID, tablename);
     }
@@ -59768,11 +59823,11 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 	    }
 	}
 
-      if ( tableID == MAX_TABLE ) tableID = UNDEFID;
+      if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
 
-      if ( tableID == UNDEFID )
+      if ( tableID == CDI_UNDEFID )
 	{
-	  if ( modelID != UNDEFID )
+	  if ( modelID != CDI_UNDEFID )
 	    {
               const char *modelName;
 	      if ( (modelName = modelInqNamePtr(modelID)) )
@@ -59784,7 +59839,7 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 		  modelID2 = modelInq(-1, 0, tablefile);
 		}
 	    }
-	  if ( modelID2 != UNDEFID )
+	  if ( modelID2 != CDI_UNDEFID )
 	    for ( tableID = 0; tableID < MAX_TABLE; tableID++ )
 	      {
 		if ( parTable[tableID].used )
@@ -59795,9 +59850,9 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 	      }
 	}
 
-      if ( tableID == MAX_TABLE ) tableID = UNDEFID;
+      if ( tableID == MAX_TABLE ) tableID = CDI_UNDEFID;
 
-      if ( tableID == UNDEFID && modelID != UNDEFID )
+      if ( tableID == CDI_UNDEFID && modelID != CDI_UNDEFID )
 	tableID = tableFromEnv(modelID, tablenum);
 
       if ( CDI_Debug )
@@ -59805,19 +59860,19 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 	  Message("tableID = %d tablename = %s", tableID, tablename);
     }
 
-  return (tableID);
+  return tableID;
 }
 
 int tableDef(int modelID, int tablenum, const char *tablename)
 {
-  int tableID = UNDEFID;
+  int tableID = CDI_UNDEFID;
 
   if ( ! ParTableInit ) parTableInit();
   /*
-  if ( ! (modelID == UNDEFID && tablenum == 0) )
+  if ( ! (modelID == CDI_UNDEFID && tablenum == 0) )
     tableID = tableInq(modelID, tablenum, tablename);
     */
-  if ( tableID == UNDEFID )
+  if ( tableID == CDI_UNDEFID )
     {
       tableID = tableNewEntry();
 
@@ -59826,22 +59881,25 @@ int tableDef(int modelID, int tablenum, const char *tablename)
       if ( tablename )
 	parTable[tableID].name = strdupx(tablename);
 
-      parTable[tableID].pars = (PAR *) Malloc(MAX_PARS * sizeof(PAR));
+      parTable[tableID].pars = (param_type *) Malloc(MAX_PARS * sizeof(param_type));
     }
 
-  return (tableID);
+  return tableID;
 }
 
-static void tableDefModelID(int tableID, int modelID)
+static
+void tableDefModelID(int tableID, int modelID)
 {
   parTable[tableID].modelID = modelID;
 }
 
-static void tableDefNum(int tableID, int tablenum)
+static
+void tableDefNum(int tableID, int tablenum)
 {
   parTable[tableID].number  = tablenum;
 }
 
+
 int tableInqNum(int tableID)
 {
   int number = 0;
@@ -59849,9 +59907,10 @@ int tableInqNum(int tableID)
   if ( tableID >= 0 && tableID < MAX_TABLE )
     number = parTable[tableID].number;
 
-  return (number);
+  return number;
 }
 
+
 int tableInqModel(int tableID)
 {
   int modelID = -1;
@@ -59859,9 +59918,10 @@ int tableInqModel(int tableID)
   if ( tableID >= 0 && tableID < MAX_TABLE )
     modelID = parTable[tableID].modelID;
 
-  return (modelID);
+  return modelID;
 }
 
+
 static void partabCheckID(int item)
 {
   if ( item < 0 || item >= parTableSize )
@@ -59871,6 +59931,7 @@ static void partabCheckID(int item)
     Error("item %d name undefined!", item);
 }
 
+
 const char *tableInqNamePtr(int tableID)
 {
   const char *tablename = NULL;
@@ -59884,22 +59945,21 @@ const char *tableInqNamePtr(int tableID)
     if ( parTable[tableID].name )
       tablename = parTable[tableID].name;
 
-  return (tablename);
+  return tablename;
 }
 
+
 void tableWrite(const char *ptfile, int tableID)
 {
-  int item, npars;
   size_t maxname = 4, maxlname = 10, maxunits = 2;
-  FILE *ptfp;
-  int tablenum, modelID, instID = CDI_UNDEFID;
+  int instID = CDI_UNDEFID;
   int center = 0, subcenter = 0;
   const char *instnameptr = NULL, *modelnameptr = NULL;
 
   if ( CDI_Debug )
     Message("write parameter table %d to %s", tableID, ptfile);
 
-  if ( tableID == UNDEFID )
+  if ( tableID == CDI_UNDEFID )
     {
       Warning("parameter table ID undefined");
       return;
@@ -59907,11 +59967,11 @@ void tableWrite(const char *ptfile, int tableID)
 
   partabCheckID(tableID);
 
-  ptfp = fopen(ptfile, "w");
+  FILE *ptfp = fopen(ptfile, "w");
 
-  npars = parTable[tableID].npars;
+  int npars = parTable[tableID].npars;
 
-  for ( item = 0; item < npars; item++)
+  for ( int item = 0; item < npars; item++)
     {
       if ( parTable[tableID].pars[item].name )
 	{
@@ -59932,8 +59992,8 @@ void tableWrite(const char *ptfile, int tableID)
 	}
     }
 
-  tablenum = tableInqNum(tableID);
-  modelID = parTable[tableID].modelID;
+  int tablenum = tableInqNum(tableID);
+  int modelID = parTable[tableID].modelID;
   if ( modelID != CDI_UNDEFID )
     {
       modelnameptr = modelInqNamePtr(modelID);
@@ -59972,8 +60032,8 @@ void tableWrite(const char *ptfile, int tableID)
 	  (int)maxname,  "name",
 	  (int)maxlname, "title",
 	  (int)maxunits, "units");
-	  
-  for ( item = 0; item < npars; item++)
+
+  for ( int item = 0; item < npars; item++)
     {
       const char *name = parTable[tableID].pars[item].name,
         *longname = parTable[tableID].pars[item].longname,
@@ -59992,26 +60052,14 @@ void tableWrite(const char *ptfile, int tableID)
 }
 
 
-void tableWriteC(const char *filename, int tableID)
-{
-  FILE *ptfp = fopen(filename, "w");
-  if (!ptfp)
-    Error("failed to open file \"%s\"!", filename);
-  if ( CDI_Debug )
-    Message("write parameter table %d to %s", tableID, filename);
-  tableFWriteC(ptfp, tableID);
-  fclose(ptfp);
-}
-
 void tableFWriteC(FILE *ptfp, int tableID)
 {
   const char chelp[] = "";
-  int item, npars;
   size_t maxname = 0, maxlname = 0, maxunits = 0;
   char tablename[256];
 
 
-  if ( tableID == UNDEFID )
+  if ( tableID == CDI_UNDEFID )
     {
       Warning("parameter table ID undefined");
       return;
@@ -60019,9 +60067,9 @@ void tableFWriteC(FILE *ptfp, int tableID)
 
   partabCheckID(tableID);
 
-  npars = parTable[tableID].npars;
+  int npars = parTable[tableID].npars;
 
-  for ( item = 0; item < npars; item++)
+  for ( int item = 0; item < npars; item++)
     {
       if ( parTable[tableID].pars[item].name )
 	{
@@ -60049,16 +60097,16 @@ void tableFWriteC(FILE *ptfp, int tableID)
     for (size_t i = 0; i < len; i++ )
       if ( tablename[i] == '.' ) tablename[i] = '_';
   }
-  fprintf(ptfp, "static const PAR %s[] = {\n", tablename);
+  fprintf(ptfp, "static const param_type %s[] = {\n", tablename);
 
-  for ( item = 0; item < npars; item++ )
+  for ( int item = 0; item < npars; item++ )
     {
       size_t len = strlen(parTable[tableID].pars[item].name),
         llen = parTable[tableID].pars[item].longname
         ? strlen(parTable[tableID].pars[item].longname) : 0,
         ulen = parTable[tableID].pars[item].units
         ? strlen(parTable[tableID].pars[item].units) : 0;
-      fprintf(ptfp, "  {%4d, 0, \"%s\", %-*s%c%s%s, %-*s%c%s%s %-*s},\n",
+      fprintf(ptfp, "  {%4d, -1, 0, \"%s\", %-*s%c%s%s, %-*s%c%s%s %-*s},\n",
 	      parTable[tableID].pars[item].id,
 	      parTable[tableID].pars[item].name, (int)(maxname-len), chelp,
               llen?'"':' ',
@@ -60075,200 +60123,62 @@ void tableFWriteC(FILE *ptfp, int tableID)
 }
 
 
-int tableInqParCode(int tableID, char *varname, int *code)
-{
-  int err = 1;
-
-  if ( tableID != UNDEFID && varname != NULL )
-    {
-      int npars = parTable[tableID].npars;
-      for ( int item = 0; item < npars; item++ )
-	{
-	  if ( parTable[tableID].pars[item].name
-               && strcmp(parTable[tableID].pars[item].name, varname) == 0 )
-            {
-              *code = parTable[tableID].pars[item].id;
-              err = 0;
-              break;
-            }
-	}
-    }
-
-  return (err);
-}
-
-
-int tableInqParName(int tableID, int code, char *varname)
-{
-  int err = 1;
-
-  if ( tableID >= 0 && tableID < MAX_TABLE )
-    {
-      int npars = parTable[tableID].npars;
-      for ( int item = 0; item < npars; item++ )
-	{
-	  if ( parTable[tableID].pars[item].id == code )
-	    {
-	      if ( parTable[tableID].pars[item].name )
-		strcpy(varname, parTable[tableID].pars[item].name);     //FIXME: This may overrun the supplied buffer!
-              err = 0;
-	      break;
-	    }
-	}
-    }
-  else if ( tableID == UNDEFID )
-    { }
-  else
-    Error("Invalid table ID %d", tableID);
-
-  return (err);
-}
-
-
-const char *tableInqParNamePtr(int tableID, int code)
-{
-  const char *name = NULL;
-
-  if ( tableID != UNDEFID )
-    {
-      int npars = parTable[tableID].npars;
-      for ( int item = 0; item < npars; item++ )
-	{
-	  if ( parTable[tableID].pars[item].id == code )
-	    {
-	      name = parTable[tableID].pars[item].name;
-	      break;
-	    }
-	}
-    }
-
-  return (name);
-}
-
-
-const char *tableInqParLongnamePtr(int tableID, int code)
-{
-  const char *longname = NULL;
-
-  if ( tableID != UNDEFID )
-    {
-      int npars = parTable[tableID].npars;
-      for ( int item = 0; item < npars; item++ )
-	{
-	  if ( parTable[tableID].pars[item].id == code )
-	    {
-	      longname = parTable[tableID].pars[item].longname;
-	      break;
-	    }
-	}
-    }
-
-  return (longname);
-}
-
-
-const char *tableInqParUnitsPtr(int tableID, int code)
-{
-  const char *units = NULL;
-
-  if ( tableID != UNDEFID )
-    {
-      int npars = parTable[tableID].npars;
-      for ( int item = 0; item < npars; item++ )
-	{
-	  if ( parTable[tableID].pars[item].id == code )
-	    {
-	      units = parTable[tableID].pars[item].units;
-	      break;
-	    }
-	}
-    }
-
-  return (units);
-}
-
-
-int tableInqParLongname(int tableID, int code, char *longname)
+void tableInqEntry(int tableID, int id, int ltype, char *name, char *longname, char *units)
 {
-  if ( ((tableID >= 0) & (tableID < MAX_TABLE)) | (tableID == UNDEFID) ) { } else
+  if ( ((tableID >= 0) & (tableID < MAX_TABLE)) | (tableID == CDI_UNDEFID) ) { } else
     Error("Invalid table ID %d", tableID);
 
-  int err = 1;
-
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
 	{
-	  if ( parTable[tableID].pars[item].id == code )
+	  if ( parTable[tableID].pars[item].id == id &&
+               (parTable[tableID].pars[item].ltype == -1 || ltype == -1 ||
+                parTable[tableID].pars[item].ltype == ltype) )
 	    {
-	      if ( parTable[tableID].pars[item].longname )
+	      if ( name && parTable[tableID].pars[item].name )
+		strcpy(name, parTable[tableID].pars[item].name);
+	      if ( longname && parTable[tableID].pars[item].longname )
 		strcpy(longname, parTable[tableID].pars[item].longname);
-              err = 0;
+	      if ( units && parTable[tableID].pars[item].units )
+		strcpy(units, parTable[tableID].pars[item].units);
+
 	      break;
 	    }
 	}
     }
-
-  return (err);
 }
 
 
-int tableInqParUnits(int tableID, int code, char *units)
+int tableInqParCode(int tableID, char *varname, int *code)
 {
-
-  if ( ((tableID >= 0) & (tableID < MAX_TABLE)) | (tableID == UNDEFID) ) { } else
-    Error("Invalid table ID %d", tableID);
-
   int err = 1;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID && varname != NULL )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
 	{
-	  if ( parTable[tableID].pars[item].id == code )
-	    {
-	      if ( parTable[tableID].pars[item].units )
-		strcpy(units, parTable[tableID].pars[item].units);
+	  if ( parTable[tableID].pars[item].name
+               && strcmp(parTable[tableID].pars[item].name, varname) == 0 )
+            {
+              *code = parTable[tableID].pars[item].id;
               err = 0;
-	      break;
-	    }
+              break;
+            }
 	}
     }
 
-  return (err);
+  return err;
 }
 
 
-void tableInqPar(int tableID, int code, char *name, char *longname, char *units)
-{
-
-  if ( ((tableID >= 0) & (tableID < MAX_TABLE)) | (tableID == UNDEFID) ) { } else
-    Error("Invalid table ID %d", tableID);
-
-  int npars = parTable[tableID].npars;
-
-  for ( int item = 0; item < npars; item++ )
-    {
-      if ( parTable[tableID].pars[item].id == code )
-	{
-	  if ( parTable[tableID].pars[item].name )
-	    strcpy(name, parTable[tableID].pars[item].name);
-	  if ( parTable[tableID].pars[item].longname )
-	    strcpy(longname, parTable[tableID].pars[item].longname);
-	  if ( parTable[tableID].pars[item].units )
-	    strcpy(units, parTable[tableID].pars[item].units);
-	  break;
-	}
-    }
-}
-
 int tableInqNumber(void)
 {
   if ( ! ParTableInit ) parTableInit();
 
-  return (parTableNum);
+  return parTableNum;
 }
 /*
  * Local Variables:
@@ -60283,7 +60193,7 @@ int tableInqNumber(void)
 #endif
 
 #include <stddef.h>
-#include <string.h>
+
 
 
 static int DefaultTimeType = TAXIS_ABSOLUTE;
@@ -60373,24 +60283,15 @@ static int  TAXIS_Debug = 0;   /* If set to 1, debugging */
 
 const char *tunitNamePtr(int unitID)
 {
-  const char *name;
   int size = sizeof(Timeunits)/sizeof(*Timeunits);
-
-  if ( unitID > 0 && unitID < size )
-    name = Timeunits[unitID];
-  else
-    name = Timeunits[0];
-
-  return (name);
+  return (unitID > 0 && unitID < size) ? Timeunits[unitID] : Timeunits[0];
 }
 
 #if 0
 static
 void taxis_defaults(void)
 {
-  char *timeunit;
-
-  timeunit = getenv("TIMEUNIT");
+  char *timeunit = getenv("TIMEUNIT");
   if ( timeunit )
     {
       if ( strcmp(timeunit, "minutes") == 0 )
@@ -60419,7 +60320,8 @@ static
 void taxisDefaultValue(taxis_t* taxisptr)
 {
   taxisptr->self        = CDI_UNDEFID;
-  taxisptr->used        = FALSE;
+  taxisptr->used        = false;
+  taxisptr->datatype    = CDI_DATATYPE_FLT64;
   taxisptr->type        = DefaultTimeType;
   taxisptr->vdate       = 0;
   taxisptr->vtime       = 0;
@@ -60430,8 +60332,8 @@ void taxisDefaultValue(taxis_t* taxisptr)
   taxisptr->calendar    = cdiDefaultCalendar;
   taxisptr->unit        = DefaultTimeUnit;
   taxisptr->numavg      = 0;
-  taxisptr->climatology = FALSE;
-  taxisptr->has_bounds  = FALSE;
+  taxisptr->climatology = false;
+  taxisptr->has_bounds  = false;
   taxisptr->vdate_lb    = 0;
   taxisptr->vtime_lb    = 0;
   taxisptr->vdate_ub    = 0;
@@ -60440,6 +60342,7 @@ void taxisDefaultValue(taxis_t* taxisptr)
   taxisptr->fc_period   = 0;
   taxisptr->name        = NULL;
   taxisptr->longname    = NULL;
+  taxisptr->units       = NULL;
 }
 
 static taxis_t *
@@ -60456,33 +60359,22 @@ taxisNewEntry(cdiResH resH)
       reshReplace(resH, taxisptr, &taxisOps);
     }
 
-  return (taxisptr);
+  return taxisptr;
 }
 
 static
-void taxisInit (void)
+void taxisInit(void)
 {
-  static int taxisInitialized = 0;
-  char *env;
+  static bool taxisInitialized = false;
 
   if ( taxisInitialized ) return;
 
-  taxisInitialized = 1;
+  taxisInitialized = true;
 
-  env = getenv("TAXIS_DEBUG");
+  char *env = getenv("TAXIS_DEBUG");
   if ( env ) TAXIS_Debug = atoi(env);
 }
 
-#if 0
-static
-void taxis_copy(taxis_t *taxisptr2, taxis_t *taxisptr1)
-{
-  int taxisID2 = taxisptr2->self;
-  memcpy(taxisptr2, taxisptr1, sizeof(taxis_t));
-  taxisptr2->self = taxisID2;
-}
-#endif
-
 /*
 @Function  taxisCreate
 @Title     Create a Time axis
@@ -60516,8 +60408,7 @@ taxisDefRtime(taxisID, 120000);
 */
 int taxisCreate(int taxistype)
 {
-  if ( CDI_Debug )
-    Message("taxistype: %d", taxistype);
+  if ( CDI_Debug ) Message("taxistype: %d", taxistype);
 
   taxisInit ();
 
@@ -60526,16 +60417,16 @@ int taxisCreate(int taxistype)
 
   int taxisID = taxisptr->self;
 
-  if ( CDI_Debug )
-    Message("taxisID: %d", taxisID);
+  if ( CDI_Debug ) Message("taxisID: %d", taxisID);
 
-  return (taxisID);
+  return taxisID;
 }
 
 void taxisDestroyKernel(taxis_t *taxisptr)
 {
   delete_refcount_string(taxisptr->name);
   delete_refcount_string(taxisptr->longname);
+  delete_refcount_string(taxisptr->units);
 }
 
 /*
@@ -60571,21 +60462,26 @@ int taxisDuplicate(int taxisID1)
 
   int taxisID2 = taxisptr2->self;
 
-  if ( CDI_Debug )
-    Message("taxisID2: %d", taxisID2);
+  if ( CDI_Debug ) Message("taxisID2: %d", taxisID2);
 
   ptaxisCopy(taxisptr2, taxisptr1);
-  return (taxisID2);
+
+  return taxisID2;
 }
 
 
 void taxisDefType(int taxisID, int type)
 {
-  taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
+  taxis_t *taxisptr = (taxis_t *) reshGetVal(taxisID, &taxisOps);
 
-  if (taxisptr->type != type)
+  if ( taxisptr->type != type )
     {
       taxisptr->type = type;
+      if ( taxisptr->units )
+        {
+          delete_refcount_string(taxisptr->units);
+          taxisptr->units = NULL;
+        }
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60661,6 +60557,12 @@ void taxisDefRdate(int taxisID, int rdate)
   if (taxisptr->rdate != rdate)
     {
       taxisptr->rdate = rdate;
+
+      if ( taxisptr->units )
+        {
+          delete_refcount_string(taxisptr->units);
+          taxisptr->units = NULL;
+        }
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60686,6 +60588,11 @@ void taxisDefRtime(int taxisID, int rtime)
   if (taxisptr->rtime != rtime)
     {
       taxisptr->rtime = rtime;
+      if ( taxisptr->units )
+        {
+          delete_refcount_string(taxisptr->units);
+          taxisptr->units = NULL;
+        }
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60775,6 +60682,11 @@ void taxisDefTunit(int taxisID, int unit)
   if (taxisptr->unit != unit)
     {
       taxisptr->unit = unit;
+      if ( taxisptr->units )
+        {
+          delete_refcount_string(taxisptr->units);
+          taxisptr->units = NULL;
+        }
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60822,16 +60734,26 @@ The valid CDI time types are TAXIS_ABSOLUTE and TAXIS_RELATIVE.
 int taxisInqType(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
-
-  return (taxisptr->type);
+  return taxisptr->type;
 }
 
 
 int taxisHasBounds(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
+  return taxisptr->has_bounds;
+}
+
 
-  return (taxisptr->has_bounds);
+void taxisWithBounds(int taxisID)
+{
+  taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
+
+  if ( taxisptr->has_bounds == false )
+    {
+      taxisptr->has_bounds = true;
+      reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
+    }
 }
 
 
@@ -60839,9 +60761,9 @@ void taxisDeleteBounds(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  if (taxisptr->has_bounds != FALSE)
+  if ( taxisptr->has_bounds )
     {
-      taxisptr->has_bounds = FALSE;
+      taxisptr->has_bounds = false;
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60850,7 +60772,7 @@ void taxisDeleteBounds(int taxisID)
 void taxisCopyTimestep(int taxisID2, int taxisID1)
 {
   taxis_t *taxisptr1 = (taxis_t *)reshGetVal(taxisID1, &taxisOps),
-    *taxisptr2 = (taxis_t *)reshGetVal(taxisID2, &taxisOps);
+          *taxisptr2 = (taxis_t *)reshGetVal(taxisID2, &taxisOps);
 
   reshLock();
 
@@ -60897,8 +60819,7 @@ The function @func{taxisInqVdate} returns the verification date of a Time axis.
 int taxisInqVdate(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
-
-  return (taxisptr->vdate);
+  return taxisptr->vdate;
 }
 
 
@@ -60915,13 +60836,13 @@ void taxisDefVdateBounds(int taxisID, int vdate_lb, int vdate_ub)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  if (taxisptr->vdate_lb != vdate_lb
-      || taxisptr->vdate_ub != vdate_ub
-      || taxisptr->has_bounds != TRUE)
+  if ( taxisptr->vdate_lb != vdate_lb
+       || taxisptr->vdate_ub != vdate_ub
+       || taxisptr->has_bounds == false )
     {
       taxisptr->vdate_lb = vdate_lb;
       taxisptr->vdate_ub = vdate_ub;
-      taxisptr->has_bounds = TRUE;
+      taxisptr->has_bounds = true;
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -60945,8 +60866,7 @@ The function @func{taxisInqVtime} returns the verification time of a Time axis.
 int taxisInqVtime(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
-
-  return (taxisptr->vtime);
+  return taxisptr->vtime;
 }
 
 
@@ -60963,13 +60883,13 @@ void taxisDefVtimeBounds(int taxisID, int vtime_lb, int vtime_ub)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  if (taxisptr->vtime_lb != vtime_lb
-      || taxisptr->vtime_ub != vtime_ub
-      || taxisptr->has_bounds != TRUE)
+  if ( taxisptr->vtime_lb != vtime_lb
+       || taxisptr->vtime_ub != vtime_ub
+       || taxisptr->has_bounds == false )
     {
       taxisptr->vtime_lb = vtime_lb;
       taxisptr->vtime_ub = vtime_ub;
-      taxisptr->has_bounds = TRUE;
+      taxisptr->has_bounds = true;
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -61001,7 +60921,7 @@ int taxisInqRdate(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rdate);
+  return taxisptr->rdate;
 }
 
 /*
@@ -61031,7 +60951,7 @@ int taxisInqRtime(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rtime);
+  return taxisptr->rtime;
 }
 
 /*
@@ -61060,7 +60980,7 @@ int taxisInqFdate(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->fdate);
+  return taxisptr->fdate;
 }
 
 /*
@@ -61089,7 +61009,7 @@ int taxisInqFtime(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->ftime);
+  return taxisptr->ftime;
 }
 
 /*
@@ -61113,55 +61033,55 @@ The valid CDI calendar types are @func{CALENDAR_STANDARD}, @func{CALENDAR_PROLEP
 */
 int taxisInqCalendar(int taxisID)
 {
-  taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-
-  return (taxisptr->calendar);
+  taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
+  return taxisptr->calendar;
 }
 
 
 int taxisInqTunit(int taxisID)
 {
-  taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-
-  return (taxisptr->unit);
+  taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
+  return taxisptr->unit;
 }
 
 
 int taxisInqForecastTunit(int taxisID)
 {
-  taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-
-  return (taxisptr->fc_unit);
+  taxis_t *taxisptr = (taxis_t *) reshGetVal ( taxisID, &taxisOps );
+  return taxisptr->fc_unit;
 }
 
 
 double taxisInqForecastPeriod(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-
-  return (taxisptr->fc_period);
+  return taxisptr->fc_period;
 }
 
 
 int taxisInqNumavg(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
-
-  return (taxisptr->numavg);
+  return taxisptr->numavg;
 }
 
 
 taxis_t *taxisPtr(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
+  return taxisptr;
+}
 
-  return (taxisptr);
+
+void ptaxisDefDatatype(taxis_t *taxisptr, int datatype)
+{
+  taxisptr->datatype = datatype;
 }
 
-void
-ptaxisDefName(taxis_t *taxisptr, const char *name)
+
+void ptaxisDefName(taxis_t *taxisptr, const char *name)
 {
-  if (name)
+  if ( name )
     {
       size_t len = strlen(name);
       delete_refcount_string(taxisptr->name);
@@ -61170,10 +61090,10 @@ ptaxisDefName(taxis_t *taxisptr, const char *name)
     }
 }
 
-void
-ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
+
+void ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
 {
-  if (longname)
+  if ( longname )
     {
       size_t len = strlen(longname);
       delete_refcount_string(taxisptr->longname);
@@ -61183,11 +61103,21 @@ ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
 }
 
 
+void ptaxisDefUnits(taxis_t *taxisptr, const char *units)
+{
+  if ( units )
+    {
+      size_t len = strlen(units);
+      delete_refcount_string(taxisptr->units);
+      char *taxisunits = taxisptr->units = new_refcount_string(len);
+      strcpy(taxisunits, units);
+    }
+}
+
+
 static void
 cdiDecodeTimevalue(int timeunit, double timevalue, int *days, int *secs)
 {
-  static int lwarn = TRUE;
-
   *days = 0;
   *secs = 0;
 
@@ -61232,10 +61162,11 @@ cdiDecodeTimevalue(int timeunit, double timevalue, int *days, int *secs)
     }
   else
     {
+      static bool lwarn = true;
       if ( lwarn )
 	{
 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
-	  lwarn = FALSE;
+	  lwarn = false;
 	}
     }
 }
@@ -61243,8 +61174,6 @@ cdiDecodeTimevalue(int timeunit, double timevalue, int *days, int *secs)
 static
 void cdiEncodeTimevalue(int days, int secs, int timeunit, double *timevalue)
 {
-  static int lwarn = TRUE;
-
   if ( timeunit == TUNIT_SECOND )
     {
       *timevalue = days*86400. + secs;
@@ -61268,10 +61197,11 @@ void cdiEncodeTimevalue(int days, int secs, int timeunit, double *timevalue)
     }
   else
     {
+      static bool lwarn = true;
       if ( lwarn )
 	{
 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
-	  lwarn = FALSE;
+	  lwarn = false;
 	}
     }
 }
@@ -61335,28 +61265,24 @@ void timeval2vtime(double timevalue, taxis_t *taxis, int *vdate, int *vtime)
 
 double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
 {
-  int ryear, rmonth;
-  int year, month, day, hour, minute, second;
-  int rdate, rtime;
   double value = 0;
-  int timeunit;
-  int timeunit0;
-  int calendar;
   int julday1, secofday1, julday2, secofday2, days, secs;
 
-  timeunit = (*taxis).unit;
-  calendar = (*taxis).calendar;
+  int timeunit = (*taxis).unit;
+  int calendar = (*taxis).calendar;
 
-  rdate = (*taxis).rdate;
-  rtime = (*taxis).rtime;
+  int rdate = (*taxis).rdate;
+  int rtime = (*taxis).rtime;
   if ( rdate == -1 )
     {
-      rdate  = (*taxis).vdate;
-      rtime  = (*taxis).vtime;
+      rdate = (*taxis).vdate;
+      rtime = (*taxis).vtime;
     }
 
-  if ( rdate == 0 && rtime == 0 && vdate == 0 && vtime == 0 ) return(value);
+  if ( rdate == 0 && rtime == 0 && vdate == 0 && vtime == 0 ) return value;
 
+  int ryear, rmonth;
+  int year, month, day, hour, minute, second;
   cdiDecodeDate(rdate, &ryear, &rmonth, &day);
   cdiDecodeTime(rtime, &hour, &minute, &second);
 
@@ -61365,7 +61291,7 @@ double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
   cdiDecodeDate(vdate, &year, &month, &day);
   cdiDecodeTime(vtime, &hour, &minute, &second);
 
-  timeunit0 = timeunit;
+  int timeunit0 = timeunit;
 
   if ( timeunit == TUNIT_MONTH && calendar == CALENDAR_360DAYS )
     {
@@ -61374,17 +61300,15 @@ double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
 
   if ( timeunit == TUNIT_MONTH || timeunit == TUNIT_YEAR )
     {
-      int nmonth, dpm;
-
       value = (year-ryear)*12 - rmonth + month;
 
-      nmonth = (int) value;
+      int nmonth = (int) value;
       month -= nmonth;
 
       while ( month > 12 ) { month -= 12; year++; }
       while ( month <  1 ) { month += 12; year--; }
 
-      dpm = days_per_month(calendar, year, month);
+      int dpm = days_per_month(calendar, year, month);
 
       encode_caldaysec(calendar, year, month, day, hour, minute, second, &julday2, &secofday2);
 
@@ -61408,39 +61332,35 @@ double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
       value /= 30;
     }
 
-  return (value);
+  return value;
 }
 
 
-static void conv_timeval(double timevalue, int *rvdate, int *rvtime)
+static
+void conv_timeval(double timevalue, int *rvdate, int *rvtime)
 {
-  int vdate = 0, vtime = 0;
-  int hour, minute, second;
   int daysec;
 
-  vdate = (int) timevalue;
+  int vdate = (int) timevalue;
   if ( vdate < 0 )
     daysec = (int) (-(timevalue - vdate)*86400 + 0.01);
   else
     daysec = (int) ( (timevalue - vdate)*86400 + 0.01);
 
-  hour   =  daysec / 3600;
-  minute = (daysec - hour*3600)/60;
-  second =  daysec - hour*3600 - minute*60;
-  vtime  = cdiEncodeTime(hour, minute, second);
+  int hour   =  daysec / 3600;
+  int minute = (daysec - hour*3600)/60;
+  int second =  daysec - hour*3600 - minute*60;
+  int vtime  = cdiEncodeTime(hour, minute, second);
 
   *rvdate = vdate;
   *rvtime = vtime;
 }
 
 
-static void
-splitTimevalue(double timevalue, int timeunit, int *date, int *time)
+static
+void splitTimevalue(double timevalue, int timeunit, int *date, int *time)
 {
   int vdate = 0, vtime = 0;
-  int hour, minute, second;
-  int year, month, day;
-  static int lwarn = TRUE;
 
   if ( timeunit == TUNIT_SECOND )
     {
@@ -61480,16 +61400,19 @@ splitTimevalue(double timevalue, int timeunit, int *date, int *time)
     }
   else
     {
+      static bool lwarn = true;
       if ( lwarn )
 	{
 	  Warning("timeunit %s unsupported!", tunitNamePtr(timeunit));
-	  lwarn = FALSE;
+	  lwarn = false;
 	}
     }
 
   /* verify date and time */
 
+  int year, month, day;
   cdiDecodeDate(vdate, &year, &month, &day);
+  int hour, minute, second;
   cdiDecodeTime(vtime, &hour, &minute, &second);
 
   if ( month > 17 || day > 31 || hour > 23 || minute > 59 || second > 59 )
@@ -61504,9 +61427,10 @@ splitTimevalue(double timevalue, int timeunit, int *date, int *time)
       vdate = cdiEncodeDate(year, month, day);
       vtime = cdiEncodeTime(hour, minute, second);
 
+      static bool lwarn = true;
       if ( lwarn )
         {
-          lwarn = FALSE;
+          lwarn = false;
           Warning("Reset wrong date/time to %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d!",
                   year, month, day, hour, minute, second);
         }
@@ -61519,22 +61443,19 @@ splitTimevalue(double timevalue, int timeunit, int *date, int *time)
 
 void cdiSetForecastPeriod(double timevalue, taxis_t *taxis)
 {
-  int year, month, day, hour, minute, second;
-  int vdate, vtime;
-  int timeunit;
-  int calendar;
   int julday, secofday, days, secs;
 
   (*taxis).fc_period = timevalue;
 
-  timeunit = (*taxis).fc_unit;
-  calendar = (*taxis).calendar;
+  int timeunit = (*taxis).fc_unit;
+  int calendar = (*taxis).calendar;
 
-  vdate  = (*taxis).vdate;
-  vtime  = (*taxis).vtime;
+  int vdate = (*taxis).vdate;
+  int vtime = (*taxis).vtime;
 
   if ( vdate == 0 && vtime == 0 && DBL_IS_EQUAL(timevalue, 0.) ) return;
 
+  int year, month, day, hour, minute, second;
   cdiDecodeDate(vdate, &year, &month, &day);
   cdiDecodeTime(vtime, &hour, &minute, &second);
 
@@ -61603,27 +61524,21 @@ double cdiEncodeTimeval(int date, int time, taxis_t *taxis)
 	{
 	  int year, month, day;
 	  cdiDecodeDate(date, &year, &month, &day);
-          timevalue = date/100;
-	  if ( day != 0 )
-            {
-              if ( date < 0 ) timevalue -= 0.5;
-              else            timevalue += 0.5;
-            }
+          timevalue = date/100
+            + copysign((double)(day != 0) * 0.5, (double)date);
         }
       else
 	{
 	  int hour, minute, second;
 	  cdiDecodeTime(time, &hour, &minute, &second);
-	  if ( date < 0 )
-	    timevalue = -(-date + (hour*3600 + minute*60 + second)/86400.);
-	  else
-	    timevalue =    date + (hour*3600 + minute*60 + second)/86400.;
+          timevalue = copysign(1.0, (double)date)
+            * (fabs((double)date) + (hour*3600 + minute*60 + second)/86400.);
 	}
     }
   else
     timevalue = vtime2timeval(date, time, taxis);
 
-  return (timevalue);
+  return timevalue;
 }
 
 
@@ -61639,6 +61554,7 @@ void ptaxisCopy(taxis_t *dest, taxis_t *source)
 
   /* memcpy(dest, source, sizeof(taxis_t)); */
   dest->used        = source->used;
+  dest->datatype    = source->datatype;
   dest->type        = source->type;
   dest->vdate       = source->vdate;
   dest->vtime       = source->vtime;
@@ -61661,10 +61577,13 @@ void ptaxisCopy(taxis_t *dest, taxis_t *source)
   dest->climatology = source->climatology;
   delete_refcount_string(dest->name);
   delete_refcount_string(dest->longname);
+  delete_refcount_string(dest->units);
   dest->name = dup_refcount_string(source->name);
   dest->longname = dup_refcount_string(source->longname);
+  dest->units = dup_refcount_string(source->units);
   if (dest->self != CDI_UNDEFID)
     reshSetStatus(dest->self, &taxisOps, RESH_DESYNC_IN_USE);
+
   reshUnlock ();
 }
 
@@ -61703,13 +61622,13 @@ taxisPrintKernel(taxis_t * taxisptr, FILE * fp)
           "fc_unit     = %d\n"
           "fc_period   = %g\n"
           "\n", taxisptr->self, taxisptr->self,
-          taxisptr->used, taxisptr->type,
+          (int)taxisptr->used, taxisptr->type,
           taxisptr->vdate, taxisptr->vtime,
           taxisptr->rdate, taxisptr->rtime,
           taxisptr->fdate, taxisptr->ftime,
           taxisptr->calendar, taxisptr->unit,
-          taxisptr->numavg, taxisptr->climatology,
-          taxisptr->has_bounds,
+          taxisptr->numavg, (int)taxisptr->climatology,
+          (int) taxisptr->has_bounds,
           vdate_lb, vtime_lb, vdate_ub, vtime_ub,
           taxisptr->fc_unit, taxisptr->fc_period );
 }
@@ -61749,20 +61668,21 @@ taxisTxCode ( void )
   return TAXIS;
 }
 
-enum { taxisNint = 21 };
+enum { taxisNint = 22 };
 
 static int
 taxisGetPackSize(void *p, void *context)
 {
   taxis_t *taxisptr = (taxis_t*) p;
   int packBufferSize
-    = serializeGetSize(taxisNint, DATATYPE_INT, context)
-    + serializeGetSize(1, DATATYPE_UINT32, context)
+    = serializeGetSize(taxisNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(1, CDI_DATATYPE_UINT32, context)
     + (taxisptr->name ?
-       serializeGetSize((int)strlen(taxisptr->name), DATATYPE_TXT, context) : 0)
+       serializeGetSize((int)strlen(taxisptr->name), CDI_DATATYPE_TXT, context) : 0)
     + (taxisptr->longname ?
-       serializeGetSize((int)strlen(taxisptr->longname), DATATYPE_TXT,
-                        context) : 0);
+       serializeGetSize((int)strlen(taxisptr->longname), CDI_DATATYPE_TXT, context) : 0)
+    + (taxisptr->units ?
+       serializeGetSize((int)strlen(taxisptr->units), CDI_DATATYPE_TXT, context) : 0);
   return packBufferSize;
 }
 
@@ -61776,11 +61696,11 @@ taxisUnpack(char * unpackBuffer, int unpackBufferSize, int * unpackBufferPos,
   int idx = 0;
 
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  intBuffer, taxisNint, DATATYPE_INT, context);
+                  intBuffer, taxisNint, CDI_DATATYPE_INT, context);
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
+                  &d, 1, CDI_DATATYPE_UINT32, context);
 
-  xassert(cdiCheckSum(DATATYPE_INT, taxisNint, intBuffer) == d);
+  xassert(cdiCheckSum(CDI_DATATYPE_INT, taxisNint, intBuffer) == d);
 
   taxisInit();
 
@@ -61813,7 +61733,7 @@ taxisUnpack(char * unpackBuffer, int unpackBufferSize, int * unpackBufferPos,
       int len = intBuffer[idx];
       char *name = new_refcount_string((size_t)len);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      name, len, DATATYPE_TXT, context);
+                      name, len, CDI_DATATYPE_TXT, context);
       name[len] = '\0';
       taxisP->name = name;
     }
@@ -61823,10 +61743,19 @@ taxisUnpack(char * unpackBuffer, int unpackBufferSize, int * unpackBufferPos,
       int len = intBuffer[idx];
       char *longname = new_refcount_string((size_t)len);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      longname, len, DATATYPE_TXT, context);
+                      longname, len, CDI_DATATYPE_TXT, context);
       longname[len] = '\0';
       taxisP->longname = longname;
     }
+  if (intBuffer[idx])
+    {
+      int len = intBuffer[idx];
+      char *units = new_refcount_string((size_t)len);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      units, len, CDI_DATATYPE_TXT, context);
+      units[len] = '\0';
+      taxisP->units = units;
+    }
 
   reshSetStatus(taxisP->self, &taxisOps,
                 reshGetStatus(taxisP->self, &taxisOps) & ~RESH_SYNC_BIT);
@@ -61865,17 +61794,21 @@ taxisPack(void * voidP, void * packBuffer, int packBufferSize, int * packBufferP
   intBuffer[idx++] = taxisP->vtime_ub;
   intBuffer[idx++] = taxisP->name ? (int)strlen(taxisP->name) : 0;
   intBuffer[idx++] = taxisP->longname ? (int)strlen(taxisP->longname) : 0;
+  intBuffer[idx++] = taxisP->units ? (int)strlen(taxisP->units) : 0;
 
-  serializePack(intBuffer, taxisNint, DATATYPE_INT,
+  serializePack(intBuffer, taxisNint, CDI_DATATYPE_INT,
                 packBuffer, packBufferSize, packBufferPos, context);
-  d = cdiCheckSum(DATATYPE_INT, taxisNint, intBuffer);
-  serializePack(&d, 1, DATATYPE_UINT32,
+  d = cdiCheckSum(CDI_DATATYPE_INT, taxisNint, intBuffer);
+  serializePack(&d, 1, CDI_DATATYPE_UINT32,
                 packBuffer, packBufferSize, packBufferPos, context);
   if (taxisP->name)
-    serializePack(taxisP->name, intBuffer[15], DATATYPE_TXT,
+    serializePack(taxisP->name, intBuffer[15], CDI_DATATYPE_TXT,
                   packBuffer, packBufferSize, packBufferPos, context);
   if (taxisP->longname)
-    serializePack(taxisP->longname, intBuffer[16], DATATYPE_TXT,
+    serializePack(taxisP->longname, intBuffer[16], CDI_DATATYPE_TXT,
+                  packBuffer, packBufferSize, packBufferPos, context);
+  if (taxisP->units)
+    serializePack(taxisP->units, intBuffer[16], CDI_DATATYPE_TXT,
                   packBuffer, packBufferSize, packBufferPos, context);
 
 }
@@ -61906,7 +61839,7 @@ void decode_julday(int calendar,
   double b = floor((a - 1867216.25)/36524.25);
   double c = a + b - floor(b/4) + 1525;
 
-  if ( calendar == CALENDAR_STANDARD )
+  if ( calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN )
     if ( a < 2299161 ) c = a + 1524;
 
   double d = floor((c - 122.1)/365.25);
@@ -61943,7 +61876,7 @@ int encode_julday(int calendar, int year, int month, int day)
   else
     ib = (int)(iy/400) - (int)(iy/100);
 
-  if ( calendar == CALENDAR_STANDARD )
+  if ( calendar == CALENDAR_STANDARD || calendar == CALENDAR_GREGORIAN )
     {
       if ( year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15))) )
 	{
@@ -62274,7 +62207,7 @@ int tstepsNewEntry(stream_t *streamptr)
 
   tstepsInitEntry(streamptr, tsID);
 
-  streamptr->tsteps[tsID].taxis.used = TRUE;
+  streamptr->tsteps[tsID].taxis.used = true;
 
   return (int)tsID;
 }
@@ -62282,24 +62215,20 @@ int tstepsNewEntry(stream_t *streamptr)
 
 void cdiCreateTimesteps(stream_t *streamptr)
 {
-  long ntsteps;
-  long tsID;
-
   if ( streamptr->ntsteps < 0 || streamptr->tstepsTableSize > 0 )
     return;
 
-  if ( streamptr->ntsteps == 0 ) ntsteps = 1;    /* <<<<<-------- */
-  else ntsteps = streamptr->ntsteps;
+  long ntsteps = (streamptr->ntsteps == 0) ? 1 : streamptr->ntsteps;
 
   streamptr->tsteps = (tsteps_t *) Malloc((size_t)ntsteps*sizeof(tsteps_t));
 
   streamptr->tstepsTableSize = (int)ntsteps;
   streamptr->tstepsNextID    = (int)ntsteps;
 
-  for ( tsID = 0; tsID < ntsteps; tsID++ )
+  for ( long tsID = 0; tsID < ntsteps; tsID++ )
     {
       tstepsInitEntry(streamptr, (size_t)tsID);
-      streamptr->tsteps[tsID].taxis.used = TRUE;
+      streamptr->tsteps[tsID].taxis.used = true;
     }
 }
 /*
@@ -62326,47 +62255,6 @@ void cdiCreateTimesteps(stream_t *streamptr)
 
 
 
-void cdiPrintDatatypes(void)
-{
-#define XSTRING(x)	#x
-#define STRING(x)	XSTRING(x)
-  fprintf (stderr, "+-------------+-------+\n"
-           "| types       | bytes |\n"
-           "+-------------+-------+\n"
-           "| void *      |   %3d |\n"
-           "+-------------+-------+\n"
-           "| char        |   %3d |\n"
-           "+-------------+-------+\n"
-           "| short       |   %3d |\n"
-           "| int         |   %3d |\n"
-           "| long        |   %3d |\n"
-           "| long long   |   %3d |\n"
-           "| size_t      |   %3d |\n"
-           "| off_t       |   %3d |\n"
-           "+-------------+-------+\n"
-           "| float       |   %3d |\n"
-           "| double      |   %3d |\n"
-           "| long double |   %3d |\n"
-           "+-------------+-------+\n\n"
-           "+-------------+-----------+\n"
-           "| INT32       | %-9s |\n"
-           "| INT64       | %-9s |\n"
-           "| FLT32       | %-9s |\n"
-           "| FLT64       | %-9s |\n"
-           "+-------------+-----------+\n"
-           "\n  byte ordering is %s\n\n",
-           (int) sizeof(void *), (int) sizeof(char),
-           (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), (int) sizeof(long long),
-           (int) sizeof(size_t), (int) sizeof(off_t),
-           (int) sizeof(float), (int) sizeof(double), (int) sizeof(long double),
-           STRING(INT32), STRING(INT64), STRING(FLT32), STRING(FLT64),
-           ((HOST_ENDIANNESS == CDI_BIGENDIAN) ? "BIGENDIAN"
-            : ((HOST_ENDIANNESS == CDI_LITTLEENDIAN) ? "LITTLEENDIAN"
-               : "Unhandled endianness!")));
-#undef STRING
-#undef XSTRING
-}
-
 static const char uuidFmt[] = "%02hhx%02hhx%02hhx%02hhx-"
   "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-"
   "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx";
@@ -62457,7 +62345,7 @@ char* cdiUnescapeSpaces(const char* string, const char** outStringEnd)
   return result;
 }
 
-#ifdef HAVE_DECL_UUID_GENERATE
+#if defined (HAVE_DECL_UUID_GENERATE) && defined (HAVE_UUID_UUID_H)
 #include <sys/time.h>
 #include <uuid/uuid.h>
 void cdiCreateUUID(unsigned char *uuid)
@@ -62484,7 +62372,7 @@ void cdiCreateUUID(unsigned char *uuid)
   uuid_generate(uuid);
   setstate(caller_rand_state);
 }
-#elif defined (HAVE_DECL_UUID_CREATE)
+#elif defined (HAVE_DECL_UUID_CREATE) && defined (HAVE_UUID_H)
 typedef uint8_t u_int8_t;
 typedef uint16_t u_int16_t;
 typedef uint32_t u_int32_t;
@@ -62504,8 +62392,8 @@ void cdiCreateUUID(unsigned char *uuid)
 void cdiCreateUUID(unsigned char *uuid)
 {
   static int uuid_seeded = 0;
-  static char uuid_rand_state[31 * sizeof (long)];
 #ifndef _SX
+  static char uuid_rand_state[31 * sizeof (long)];
   char *caller_rand_state;
   if (uuid_seeded)
     caller_rand_state = setstate(uuid_rand_state);
@@ -62526,6 +62414,27 @@ void cdiCreateUUID(unsigned char *uuid)
   for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
     uuid[i] = (unsigned char)random();
 #else
+  unsigned short caller_rand_state[3];
+  {
+    static unsigned short our_rand_state[3];
+    if (!uuid_seeded)
+      {
+        struct timeval tv;
+        int status = gettimeofday(&tv, NULL);
+        if (status != 0)
+          {
+            perror("failed seed generation!");
+            exit(1);
+          }
+        unsigned seed = tv.tv_sec ^ tv.tv_usec;
+        our_rand_state[0] = 0x330E;
+        our_rand_state[1] = (unsigned short)(seed & 0xFFFFU);
+        our_rand_state[2] = (unsigned short)((seed >> 16) & 0xFFFFU);
+      }
+    unsigned short *p = seed48(our_rand_state);
+    uuid_seeded = 1;
+    memcpy(caller_rand_state, p, sizeof (caller_rand_state));
+  }
   for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
     uuid[i] = (unsigned char)lrand48();
 #endif
@@ -62535,6 +62444,8 @@ void cdiCreateUUID(unsigned char *uuid)
   uuid[7] = (unsigned char)((uuid[7] & 0x0f) | (4 << 4));
 #ifndef _SX
   setstate(caller_rand_state);
+#else
+  seed48(caller_rand_state);
 #endif
 }
 #endif
@@ -62551,14 +62462,8 @@ void cdiCreateUUID(unsigned char *uuid)
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <stdbool.h>
-#include <string.h>
-#include <math.h>
-
 
 
-#undef  UNDEFID
-#define UNDEFID -1
 
 static size_t Vctsize = 0;
 static double *Vct = NULL;
@@ -62590,6 +62495,7 @@ typedef struct
 
 typedef struct
 {
+  int            varID;
   int            param;
   int            prec;
   int            tsteptype;
@@ -62613,7 +62519,7 @@ typedef struct
   int            comptype;       // compression type
   int            complevel;      // compression level
   short          timave;
-  short          lmissval;
+  bool           lmissval;
   double         missval;
   char          *name;
   char          *stdname;
@@ -62635,18 +62541,18 @@ vartable_t;
 
 static vartable_t *vartable;
 static unsigned varTablesize = 0;
-static unsigned nvars = 0;
-
+static unsigned varTableUsed = 0;
 
-static void
-paramInitEntry(unsigned varID, int param)
+static
+void paramInitEntry(unsigned varID, int param)
 {
+  vartable[varID].varID          = (int)varID;
   vartable[varID].param          = param;
   vartable[varID].prec           = 0;
   vartable[varID].tsteptype      = TSTEP_INSTANT;
   vartable[varID].timave         = 0;
   vartable[varID].timaccu        = 0;
-  vartable[varID].gridID         = UNDEFID;
+  vartable[varID].gridID         = CDI_UNDEFID;
   vartable[varID].zaxistype      = 0;
   vartable[varID].ltype1         = 0;
   vartable[varID].ltype2         = -1;
@@ -62656,14 +62562,14 @@ paramInitEntry(unsigned varID, int param)
   vartable[varID].recordTable    = NULL;
   vartable[varID].nsubtypes_alloc= 0;
   vartable[varID].nsubtypes      = 0;
-  vartable[varID].instID         = UNDEFID;
-  vartable[varID].modelID        = UNDEFID;
-  vartable[varID].tableID        = UNDEFID;
-  vartable[varID].typeOfGeneratingProcess   = UNDEFID;
-  vartable[varID].productDefinitionTemplate = UNDEFID;
-  vartable[varID].comptype       = COMPRESS_NONE;
+  vartable[varID].instID         = CDI_UNDEFID;
+  vartable[varID].modelID        = CDI_UNDEFID;
+  vartable[varID].tableID        = CDI_UNDEFID;
+  vartable[varID].typeOfGeneratingProcess   = CDI_UNDEFID;
+  vartable[varID].productDefinitionTemplate = CDI_UNDEFID;
+  vartable[varID].comptype       = CDI_COMPRESS_NONE;
   vartable[varID].complevel      = 1;
-  vartable[varID].lmissval       = 0;
+  vartable[varID].lmissval       = false;
   vartable[varID].missval        = 0;
   vartable[varID].name           = NULL;
   vartable[varID].stdname        = NULL;
@@ -62682,7 +62588,7 @@ varGetEntry(int param, int zaxistype, int ltype1, int tsteptype, const char *nam
     {
       /* testing for "param" implicitly checks if we are beyond the
        * current vartable size: */
-      if (vartable[varID].param == param)
+      if ( vartable[varID].param == param )
         {
           int no_of_tiles = -1;
           if ( tiles ) no_of_tiles = tiles->numberOfTiles;
@@ -62697,11 +62603,11 @@ varGetEntry(int param, int zaxistype, int ltype1, int tsteptype, const char *nam
             {
               if ( name && name[0] && vartable[varID].name && vartable[varID].name[0] )
                 {
-                  if ( strcmp(name, vartable[varID].name) == 0 ) return (varID);
+                  if ( strcmp(name, vartable[varID].name) == 0 ) return varID;
                 }
               else
                 {
-                  return (varID);
+                  return varID;
                 }
             }
         }
@@ -62715,7 +62621,7 @@ void varFree(void)
 {
   if ( CDI_Debug ) Message("call to varFree");
 
-  for ( unsigned varID = 0; varID < nvars; varID++ )
+  for ( size_t varID = 0; varID < varTableUsed; varID++ )
     {
       if ( vartable[varID].recordTable )
         {
@@ -62749,7 +62655,7 @@ void varFree(void)
 
   vartable = NULL;
   varTablesize = 0;
-  nvars = 0;
+  varTableUsed = 0;
 
   if ( Vct )
     Free(Vct);
@@ -62837,24 +62743,24 @@ static int levelNewEntry(unsigned varID, int level1, int level2, int tileID)
       levelTable = (leveltable_t *) Malloc((size_t)levelTableSize
                                            * sizeof (leveltable_t));
       for ( int i = 0; i < levelTableSize; i++ )
-        levelTable[i].recID = UNDEFID;
+        levelTable[i].recID = CDI_UNDEFID;
     }
   else
     {
       while( levelID < levelTableSize
-             && levelTable[levelID].recID != UNDEFID )
+             && levelTable[levelID].recID != CDI_UNDEFID )
         ++levelID;
     }
   /*
     If the table overflows, double its size.
   */
-  if( levelID == levelTableSize )
+  if ( levelID == levelTableSize )
     {
       levelTable = (leveltable_t *) Realloc(levelTable,
                                             (size_t)(levelTableSize *= 2)
                                             * sizeof (leveltable_t));
       for( int i = levelID; i < levelTableSize; i++ )
-        levelTable[i].recID = UNDEFID;
+        levelTable[i].recID = CDI_UNDEFID;
     }
 
   levelTable[levelID].level1   = level1;
@@ -62865,7 +62771,7 @@ static int levelNewEntry(unsigned varID, int level1, int level2, int tileID)
   vartable[varID].recordTable[tileID].levelTableSize = levelTableSize;
   vartable[varID].recordTable[tileID].levelTable     = levelTable;
 
-  return (levelID);
+  return levelID;
 }
 
 #define  UNDEF_PARAM  -4711
@@ -62913,7 +62819,7 @@ paramNewEntry(int param)
     {
       vartable = (vartable_t *) Realloc(vartable, (size_t)(varTablesize *= 2)
                                         * sizeof (vartable_t));
-      for( unsigned i = varID; i < varTablesize; i++ )
+      for ( size_t i = varID; i < varTablesize; i++ )
         {
           vartable[i].param = UNDEF_PARAM;
           vartable[i].opt_grib_kvpair      = NULL;
@@ -62924,7 +62830,7 @@ paramNewEntry(int param)
 
   paramInitEntry(varID, param);
 
-  return (varID);
+  return varID;
 }
 
 
@@ -62961,6 +62867,7 @@ int varInsertTileSubtype(vartable_t *vptr, const var_tile_t *tiles)
     subtypeDestroyPtr(subtype_ptr);
     return vptr->tiles->nentries - 1;
   }
+
   return CDI_UNDEFID;
 }
 
@@ -62972,11 +62879,11 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
                   const var_tile_t *tiles, int *tile_index)
 {
   unsigned varID = (cdiSplitLtype105 != 1 || zaxistype != ZAXIS_HEIGHT) ?
-    varGetEntry(param, zaxistype, ltype1, tsteptype, name, tiles) : (unsigned)UNDEFID;
+    varGetEntry(param, zaxistype, ltype1, tsteptype, name, tiles) : (unsigned) CDI_UNDEFID;
 
-  if ( varID == (unsigned)UNDEFID )
+  if ( varID == (unsigned) CDI_UNDEFID )
     {
-      nvars++;
+      varTableUsed++;
       varID = paramNewEntry(param);
       vartable[varID].gridID     = gridID;
       vartable[varID].zaxistype  = zaxistype;
@@ -62989,10 +62896,10 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
 
       if ( numavg ) vartable[varID].timave = 1;
 
-      if ( name )     if ( name[0] )     vartable[varID].name     = strdup(name);
-      if ( stdname )  if ( stdname[0] )  vartable[varID].stdname  = strdup(stdname);
-      if ( longname ) if ( longname[0] ) vartable[varID].longname = strdup(longname);
-      if ( units )    if ( units[0] )    vartable[varID].units    = strdup(units);
+      if ( name && name[0] )         vartable[varID].name     = strdup(name);
+      if ( stdname && stdname[0] )   vartable[varID].stdname  = strdup(stdname);
+      if ( longname && longname[0] ) vartable[varID].longname = strdup(longname);
+      if ( units && units[0] )       vartable[varID].units    = strdup(units);
     }
   else
     {
@@ -63017,11 +62924,12 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
   int this_tile = varInsertTileSubtype(&vartable[varID], tiles);
   int tileID = tileGetEntry(varID, this_tile);
   if ( tile_index ) (*tile_index) = this_tile;
-  if (tileID == CDI_UNDEFID) {
-    tileID = tileNewEntry((int)varID);
-    vartable[varID].recordTable[tileID].subtypeIndex = this_tile;
-    vartable[varID].nsubtypes++;
-  }
+  if ( tileID == CDI_UNDEFID )
+    {
+      tileID = tileNewEntry((int)varID);
+      vartable[varID].recordTable[tileID].subtypeIndex = this_tile;
+      vartable[varID].nsubtypes++;
+    }
 
   /* append current level to level table info */
   int levelID = levelNewEntry(varID, level1, level2, tileID);
@@ -63044,131 +62952,138 @@ int dblcmp(const void *s1, const void *s2)
   if      ( *((double *) s1) < *((double *) s2) ) cmp = -1;
   else if ( *((double *) s1) > *((double *) s2) ) cmp =  1;
 
-  return (cmp);
+  return cmp;
 }
 */
 static
 int cmpLevelTable(const void* s1, const void* s2)
 {
   int cmp = 0;
-  const leveltable_t* x = (const leveltable_t*) s1;
-  const leveltable_t* y = (const leveltable_t*) s2;
+  const leveltable_t *x = (const leveltable_t*) s1;
+  const leveltable_t *y = (const leveltable_t*) s2;
   /*
   printf("%g %g  %d %d\n", x->leve11, y->level1, x, y);
   */
   if      ( x->level1 < y->level1 ) cmp = -1;
   else if ( x->level1 > y->level1 ) cmp =  1;
 
-  return (cmp);
+  return cmp;
 }
 
 static
 int cmpLevelTableInv(const void* s1, const void* s2)
 {
   int cmp = 0;
-  const leveltable_t* x = (const leveltable_t*) s1;
-  const leveltable_t* y = (const leveltable_t*) s2;
+  const leveltable_t *x = (const leveltable_t*) s1;
+  const leveltable_t *y = (const leveltable_t*) s2;
   /*
   printf("%g %g  %d %d\n", x->leve11, y->level1, x, y);
   */
   if      ( x->level1 < y->level1 ) cmp =  1;
   else if ( x->level1 > y->level1 ) cmp = -1;
 
-  return (cmp);
+  return cmp;
 }
 
 
-typedef struct
+struct paraminfo
 {
-  int      varid;
-  int      param;
-  int      ltype;
-}
-param_t;
-
+  int varid, param, ltype;
+};
 
 static
-int cmpparam(const void* s1, const void* s2)
+int cmp_param(const void* s1, const void* s2)
 {
-  const param_t* x = (const param_t*) s1;
-  const param_t* y = (const param_t*) s2;
+  const struct paraminfo *x = (const struct paraminfo*) s1;
+  const struct paraminfo *y = (const struct paraminfo*) s2;
 
   int cmp = (( x->param > y->param ) - ( x->param < y->param )) * 2
            + ( x->ltype > y->ltype ) - ( x->ltype < y->ltype );
 
-  return (cmp);
+  return cmp;
+}
+
+struct varinfo
+{
+  int        varid;
+  const char *name;
+};
+/*
+static
+int cmp_varname(const void *s1, const void *s2)
+{
+  const struct varinfo *x = (const struct varinfo *)s1,
+                       *y = (const struct varinfo *)s2;
+  return strcmp(x->name, y->name);
+}
+*/
+static
+int cmp_varname(const void *s1, const void *s2)
+{
+  const vartable_t *x = (const vartable_t *)s1,
+                   *y = (const vartable_t *)s2;
+  return strcmp(x->name, y->name);
 }
 
 
 void cdi_generate_vars(stream_t *streamptr)
 {
-  int gridID, zaxisID;
-
-  int instID, modelID, tableID;
-  int param, zaxistype, ltype1, ltype2;
-  int prec;
-  int tsteptype;
-  int timave, timaccu;
-  int lbounds;
-  int comptype;
-  char name[CDI_MAX_NAME], longname[CDI_MAX_NAME], units[CDI_MAX_NAME];
-  double *dlevels = NULL;
-  double *dlevels1 = NULL;
-  double *dlevels2 = NULL;
-  double level_sf = 1;
   int vlistID = streamptr->vlistID;
 
-  int *varids = (int *) Malloc(nvars*sizeof(int));
-  for ( unsigned varID = 0; varID < nvars; varID++ ) varids[varID] = (int)varID;
-
-  if ( streamptr->sortname )
+  int *varids = (int *) Malloc(varTableUsed*sizeof(int));
+  for ( size_t varID = 0; varID < varTableUsed; varID++ ) varids[varID] = (int)varID;
+  /*
+  if ( streamptr->sortparam )
     {
-      param_t *varInfo = (param_t *) Malloc((size_t)nvars * sizeof (param_t));
+      struct paraminfo *varInfo = (struct paraminfo *) Malloc((size_t)varTableUsed * sizeof(struct paraminfo));
 
-      for ( unsigned varID = 0; varID < nvars; varID++ )
+      for ( unsigned varID = 0; varID < varTableUsed; varID++ )
 	{
 	  varInfo[varID].varid = varids[varID];
 	  varInfo[varID].param = vartable[varID].param;
 	  varInfo[varID].ltype = vartable[varID].ltype1;
 	}
-      qsort(varInfo, (size_t)nvars, sizeof(param_t), cmpparam);
-      for ( unsigned varID = 0; varID < nvars; varID++ )
+      qsort(varInfo, (size_t)varTableUsed, sizeof(struct paraminfo), cmp_param);
+      for ( unsigned varID = 0; varID < varTableUsed; varID++ )
 	{
 	  varids[varID] = varInfo[varID].varid;
 	}
       Free(varInfo);
     }
 
-  for ( unsigned index = 0; index < nvars; index++ )
+  if ( streamptr->sortname )
+    {
+      qsort(vartable, (size_t)varTableUsed, sizeof(vartable_t), cmp_varname);
+    }
+  */
+  for ( size_t index = 0; index < varTableUsed; index++ )
     {
       int varid      = varids[index];
 
-      gridID     = vartable[varid].gridID;
-      param      = vartable[varid].param;
-      ltype1     = vartable[varid].ltype1;
-      ltype2     = vartable[varid].ltype2;
-      zaxistype = vartable[varid].zaxistype;
+      int gridID     = vartable[varid].gridID;
+      int param      = vartable[varid].param;
+      int ltype1     = vartable[varid].ltype1;
+      int ltype2     = vartable[varid].ltype2;
+      int zaxistype  = vartable[varid].zaxistype;
       if ( ltype1 == 0 && zaxistype == ZAXIS_GENERIC && cdiDefaultLeveltype != -1 )
 	zaxistype = cdiDefaultLeveltype;
-      lbounds    = vartable[varid].lbounds;
-      prec       = vartable[varid].prec;
-      instID     = vartable[varid].instID;
-      modelID    = vartable[varid].modelID;
-      tableID    = vartable[varid].tableID;
-      tsteptype  = vartable[varid].tsteptype;
-      timave     = vartable[varid].timave;
-      timaccu    = vartable[varid].timaccu;
-      comptype   = vartable[varid].comptype;
-
-      level_sf  = 1;
+      int lbounds    = vartable[varid].lbounds;
+      int prec       = vartable[varid].prec;
+      int instID     = vartable[varid].instID;
+      int modelID    = vartable[varid].modelID;
+      int tableID    = vartable[varid].tableID;
+      int tsteptype  = vartable[varid].tsteptype;
+      int timave     = vartable[varid].timave;
+      int timaccu    = vartable[varid].timaccu;
+      int comptype   = vartable[varid].comptype;
+
+      double level_sf = 1;
       if ( vartable[varid].level_sf != 0 ) level_sf = 1./vartable[varid].level_sf;
 
-      zaxisID = UNDEFID;
-
       /* consistency check: test if all subtypes have the same levels: */
       unsigned nlevels = vartable[varid].recordTable[0].nlevels;
-      for (int isub=1; isub<vartable[varid].nsubtypes; isub++) {
-        if (vartable[varid].recordTable[isub].nlevels != nlevels)
+      for ( int isub = 1; isub < vartable[varid].nsubtypes; isub++ ) {
+        if ( vartable[varid].recordTable[isub].nlevels != nlevels )
           {
             fprintf(stderr, "var \"%s\": isub = %d / %d :: "
                     "nlevels = %d, vartable[varid].recordTable[isub].nlevels = %d\n",
@@ -63179,7 +63094,7 @@ void cdi_generate_vars(stream_t *streamptr)
 
         leveltable_t *t1 = vartable[varid].recordTable[isub-1].levelTable;
         leveltable_t *t2 = vartable[varid].recordTable[isub  ].levelTable;
-        for (unsigned ilev=0; ilev<nlevels; ilev++)
+        for ( unsigned ilev = 0; ilev < nlevels; ilev++ )
           if ((t1[ilev].level1 != t2[ilev].level1)  ||
               (t1[ilev].level2 != t2[ilev].level2)  ||
               (t1[ilev].lindex != t2[ilev].lindex))
@@ -63188,32 +63103,31 @@ void cdi_generate_vars(stream_t *streamptr)
                       "nlevels = %d, vartable[varid].recordTable[isub].nlevels = %d\n",
                       vartable[varid].name, varid, isub, vartable[varid].nsubtypes,
                       nlevels, vartable[varid].recordTable[isub].nlevels);
-              Message("t1[ilev].level1=%d / t2[ilev].level1=%d",t1[ilev].level1, t2[ilev].level1);
-              Message("t1[ilev].level2=%d / t2[ilev].level2=%d",t1[ilev].level2, t2[ilev].level2);
-              Message("t1[ilev].lindex=%d / t2[ilev].lindex=%d",t1[ilev].lindex, t2[ilev].lindex);
+              Message("t1[ilev].level1=%d / t2[ilev].level1=%d", t1[ilev].level1, t2[ilev].level1);
+              Message("t1[ilev].level2=%d / t2[ilev].level2=%d", t1[ilev].level2, t2[ilev].level2);
+              Message("t1[ilev].lindex=%d / t2[ilev].lindex=%d", t1[ilev].lindex, t2[ilev].lindex);
               Error("zaxis type must not change for same parameter!");
             }
       }
       leveltable_t *levelTable = vartable[varid].recordTable[0].levelTable;
 
-      if ( ltype1 == 0 && zaxistype == ZAXIS_GENERIC && nlevels == 1 &&
-	   levelTable[0].level1 == 0 )
+      if ( ltype1 == 0 && zaxistype == ZAXIS_GENERIC && nlevels == 1 && levelTable[0].level1 == 0 )
 	zaxistype = ZAXIS_SURFACE;
 
-      dlevels = (double *) Malloc(nlevels*sizeof(double));
+      double *dlevels = (double *) Malloc(nlevels*sizeof(double));
 
       if ( lbounds && zaxistype != ZAXIS_HYBRID && zaxistype != ZAXIS_HYBRID_HALF )
-	for (unsigned levelID = 0; levelID < nlevels; levelID++ )
+	for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
 	  dlevels[levelID] = (level_sf*levelTable[levelID].level1 +
 	                      level_sf*levelTable[levelID].level2)/2;
       else
-	for (unsigned levelID = 0; levelID < nlevels; levelID++ )
+	for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
 	  dlevels[levelID] = level_sf*levelTable[levelID].level1;
 
       if ( nlevels > 1 )
 	{
           bool linc = true, ldec = true, lsort = false;
-          for (unsigned levelID = 1; levelID < nlevels; levelID++ )
+          for ( unsigned levelID = 1; levelID < nlevels; levelID++ )
             {
               /* check increasing of levels */
               linc &= (dlevels[levelID] > dlevels[levelID-1]);
@@ -63225,7 +63139,7 @@ void cdi_generate_vars(stream_t *streamptr)
            * levelTable[levelID1].level1 < levelTable[levelID2].level1 <=> levelID1 > levelID2
            * unless already sorted in decreasing order
            */
-          if ( !ldec && zaxistype == ZAXIS_PRESSURE )
+          if ( (!linc && !ldec) && zaxistype == ZAXIS_PRESSURE )
             {
               qsort(levelTable, nlevels, sizeof(leveltable_t), cmpLevelTableInv);
               lsort = true;
@@ -63246,33 +63160,35 @@ void cdi_generate_vars(stream_t *streamptr)
           if ( lsort )
             {
               if ( lbounds && zaxistype != ZAXIS_HYBRID && zaxistype != ZAXIS_HYBRID_HALF )
-                for (unsigned levelID = 0; levelID < nlevels; levelID++ )
+                for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
                   dlevels[levelID] = (level_sf*levelTable[levelID].level1 +
                                       level_sf*levelTable[levelID].level2)/2.;
               else
-                for (unsigned levelID = 0; levelID < nlevels; levelID++ )
+                for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
                   dlevels[levelID] = level_sf*levelTable[levelID].level1;
             }
 	}
 
+      double *dlevels1 = NULL;
+      double *dlevels2 = NULL;
       if ( lbounds )
 	{
 	  dlevels1 = (double *) Malloc(nlevels*sizeof(double));
-	  for (unsigned levelID = 0; levelID < nlevels; levelID++)
+	  for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
 	    dlevels1[levelID] = level_sf*levelTable[levelID].level1;
 	  dlevels2 = (double *) Malloc(nlevels*sizeof(double));
-	  for (unsigned levelID = 0; levelID < nlevels; levelID++)
+	  for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
 	    dlevels2[levelID] = level_sf*levelTable[levelID].level2;
         }
 
+      const char **cvals = NULL;
       const char *unitptr = cdiUnitNamePtr(vartable[varid].level_unit);
-      zaxisID = varDefZaxis(vlistID, zaxistype, (int)nlevels, dlevels, lbounds, dlevels1, dlevels2,
-                            (int)Vctsize, Vct, NULL, NULL, unitptr, 0, 0, ltype1);
+      int zaxisID = varDefZaxis(vlistID, zaxistype, (int)nlevels, dlevels, cvals, 0, lbounds, dlevels1, dlevels2,
+                                (int)Vctsize, Vct, NULL, NULL, unitptr, 0, 0, ltype1);
 
-      if ( ltype1 != ltype2 && ltype2 != -1 )
-        {
-          zaxisDefLtype2(zaxisID, ltype2);
-        }
+      if ( CDI_cmor_mode && nlevels == 1 && zaxistype != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID);
+
+      if ( ltype1 != ltype2 && ltype2 != -1 ) zaxisDefLtype2(zaxisID, ltype2);
 
       if ( zaxisInqType(zaxisID) == ZAXIS_REFERENCE )
         {
@@ -63291,18 +63207,19 @@ void cdi_generate_vars(stream_t *streamptr)
 
       /* generate new variable */
       int varID = stream_new_var(streamptr, gridID, zaxisID, tilesetID);
-      varID = vlistDefVarTiles(vlistID, gridID, zaxisID, tsteptype, tilesetID);
+      varID = vlistDefVarTiles(vlistID, gridID, zaxisID, TIME_VARYING, tilesetID);
 
+      vlistDefVarTsteptype(vlistID, varID, tsteptype);
       vlistDefVarParam(vlistID, varID, param);
       vlistDefVarDatatype(vlistID, varID, prec);
       vlistDefVarTimave(vlistID, varID, timave);
       vlistDefVarTimaccu(vlistID, varID, timaccu);
       vlistDefVarCompType(vlistID, varID, comptype);
 
-      if ( vartable[varid].typeOfGeneratingProcess != UNDEFID )
+      if ( vartable[varid].typeOfGeneratingProcess != CDI_UNDEFID )
         vlistDefVarTypeOfGeneratingProcess(vlistID, varID, vartable[varid].typeOfGeneratingProcess);
 
-      if ( vartable[varid].productDefinitionTemplate != UNDEFID )
+      if ( vartable[varid].productDefinitionTemplate != CDI_UNDEFID )
         vlistDefVarProductDefinitionTemplate(vlistID, varID, vartable[varid].productDefinitionTemplate);
 
       if ( vartable[varid].lmissval ) vlistDefVarMissval(vlistID, varID, vartable[varid].missval);
@@ -63315,10 +63232,8 @@ void cdi_generate_vars(stream_t *streamptr)
 	                                                  vartable[varid].ensdata->ens_count,
 							  vartable[varid].ensdata->forecast_init_type);
 
-      int    i;
-      vlist_t *vlistptr;
-      vlistptr = vlist_to_pointer(vlistID);
-      for (i=0; i<vartable[varid].opt_grib_nentries; i++)
+      vlist_t *vlistptr = vlist_to_pointer(vlistID);
+      for ( int i = 0; i < vartable[varid].opt_grib_nentries; i++ )
         {
           resize_opt_grib_entries(&vlistptr->vars[varID], vlistptr->vars[varID].opt_grib_nentries+1);
           vlistptr->vars[varID].opt_grib_nentries += 1;
@@ -63326,74 +63241,58 @@ void cdi_generate_vars(stream_t *streamptr)
 
           vlistptr->vars[varID].opt_grib_kvpair[idx] = vartable[varid].opt_grib_kvpair[i];
           vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = NULL;
-	  if (vartable[varid].opt_grib_kvpair[i].keyword) 
-	    vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = 
+	  if ( vartable[varid].opt_grib_kvpair[i].keyword )
+	    vlistptr->vars[varID].opt_grib_kvpair[idx].keyword =
 	      strdupx(vartable[varid].opt_grib_kvpair[i].keyword);
-          vlistptr->vars[varID].opt_grib_kvpair[i].update = TRUE;
+          vlistptr->vars[varID].opt_grib_kvpair[i].update = true;
         }
       /* note: if the key is not defined, we do not throw an error! */
 
-      if ( cdiDefaultTableID != UNDEFID )
+      if ( cdiDefaultTableID != CDI_UNDEFID )
 	{
 	  int pdis, pcat, pnum;
 	  cdiDecodeParam(param, &pnum, &pcat, &pdis);
-	  if ( tableInqParNamePtr(cdiDefaultTableID, pnum) )
+          char name[CDI_MAX_NAME]; name[0] = 0;
+          char longname[CDI_MAX_NAME]; longname[0] = 0;
+          char units[CDI_MAX_NAME]; units[0] = 0;
+          tableInqEntry(cdiDefaultTableID, pnum, -1, name, longname, units);
+	  if ( name[0] )
 	    {
-	      if ( tableID != UNDEFID )
+	      if ( tableID != CDI_UNDEFID )
 		{
-		  strcpy(name, tableInqParNamePtr(cdiDefaultTableID, pnum));
 		  vlistDefVarName(vlistID, varID, name);
-		  if ( tableInqParLongnamePtr(cdiDefaultTableID, pnum) )
-		    {
-		      strcpy(longname, tableInqParLongnamePtr(cdiDefaultTableID, pnum));
-		      vlistDefVarLongname(vlistID, varID, longname);
-		    }
-		  if ( tableInqParUnitsPtr(cdiDefaultTableID, pnum) )
-		    {
-		      strcpy(units, tableInqParUnitsPtr(cdiDefaultTableID, pnum));
-		      vlistDefVarUnits(vlistID, varID, units);
-		    }
-		}
+                  if ( longname[0] ) vlistDefVarLongname(vlistID, varID, longname);
+                  if ( units[0] ) vlistDefVarUnits(vlistID, varID, units);
+                }
 	      else
 		tableID = cdiDefaultTableID;
 	    }
-	  if ( cdiDefaultModelID != UNDEFID ) modelID = cdiDefaultModelID;
-	  if ( cdiDefaultInstID  != UNDEFID )  instID = cdiDefaultInstID;
+	  if ( cdiDefaultModelID != CDI_UNDEFID ) modelID = cdiDefaultModelID;
+	  if ( cdiDefaultInstID  != CDI_UNDEFID )  instID = cdiDefaultInstID;
 	}
 
-      if ( instID  != UNDEFID ) vlistDefVarInstitut(vlistID, varID, instID);
-      if ( modelID != UNDEFID ) vlistDefVarModel(vlistID, varID, modelID);
-      if ( tableID != UNDEFID ) vlistDefVarTable(vlistID, varID, tableID);
+      if ( instID  != CDI_UNDEFID ) vlistDefVarInstitut(vlistID, varID, instID);
+      if ( modelID != CDI_UNDEFID ) vlistDefVarModel(vlistID, varID, modelID);
+      if ( tableID != CDI_UNDEFID ) vlistDefVarTable(vlistID, varID, tableID);
     }
 
-  for ( unsigned index = 0; index < nvars; index++ )
+  for ( size_t index = 0; index < varTableUsed; index++ )
     {
       int varid = varids[index];
       unsigned nlevels = vartable[varid].recordTable[0].nlevels;
 
-      /*
-      for ( levelID = 0; levelID < nlevels; levelID++ )
-	{
-	  printf("%d %d %d %d %d\n", varid, levelID,
-		 vartable[varid].levelTable[levelID].lindex,
-		 vartable[varid].levelTable[levelID].recID,
-		 vartable[varid].levelTable[levelID].level1);
-	}
-      */
-      unsigned nsub = vartable[varid].nsubtypes >= 0
-        ? (unsigned)vartable[varid].nsubtypes : 0U;
-      for (size_t isub=0; isub < nsub; isub++)
+      unsigned nsub = vartable[varid].nsubtypes >= 0 ? (unsigned)vartable[varid].nsubtypes : 0U;
+      for ( size_t isub = 0; isub < nsub; isub++ )
         {
           sleveltable_t *restrict streamRecordTable
             = streamptr->vars[index].recordTable + isub;
           leveltable_t *restrict vartableLevelTable
             = vartable[varid].recordTable[isub].levelTable;
-          for (unsigned levelID = 0; levelID < nlevels; levelID++)
+          for ( unsigned levelID = 0; levelID < nlevels; levelID++ )
             {
-              streamRecordTable->recordID[levelID]
-                = vartableLevelTable[levelID].recID;
+              streamRecordTable->recordID[levelID] = vartableLevelTable[levelID].recID;
               unsigned lindex;
-              for (lindex = 0; lindex < nlevels; lindex++ )
+              for ( lindex = 0; lindex < nlevels; lindex++ )
                 if ( levelID == (unsigned)vartableLevelTable[lindex].lindex )
                   break;
               if ( lindex == nlevels )
@@ -63428,50 +63327,48 @@ void varDefZAxisReference(int nhlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZ
 }
 
 
-int zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype1)
+bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype1)
 {
-  int differ = 1;
-  int levelID;
-  int zlbounds = 0;
-  int ltype_is_equal = FALSE;
+  bool differ = true;
 
-  if ( ltype1 == zaxisInqLtype(zaxisID) ) ltype_is_equal = TRUE;
+  bool ltype_is_equal = (ltype1 == zaxisInqLtype(zaxisID));
 
   if ( ltype_is_equal && (zaxistype == zaxisInqType(zaxisID) || zaxistype == ZAXIS_GENERIC) )
     {
-      if ( zaxisInqLbounds(zaxisID, NULL) > 0 ) zlbounds = 1;
+      bool zlbounds = (zaxisInqLbounds(zaxisID, NULL) > 0);
       if ( nlevels == zaxisInqSize(zaxisID) && zlbounds == lbounds )
 	{
-	  const double *dlevels;
-	  char zlongname[CDI_MAX_NAME];
-	  char zunits[CDI_MAX_NAME];
-
-	  dlevels = zaxisInqLevelsPtr(zaxisID);
-	  for ( levelID = 0; levelID < nlevels; levelID++ )
-	    {
-	      if ( fabs(dlevels[levelID] - levels[levelID]) > 1.e-9 )
-		break;
-	    }
-
-	  if ( levelID == nlevels ) differ = 0;
+	  const double *dlevels = zaxisInqLevelsPtr(zaxisID);
+          if ( dlevels && levels )
+            {
+              int levelID;
+              for ( levelID = 0; levelID < nlevels; levelID++ )
+                {
+                  if ( fabs(dlevels[levelID] - levels[levelID]) > 1.e-9 )
+                    break;
+                }
+              if ( levelID == nlevels ) differ = false;
+            }
 
 	  if ( ! differ )
 	    {
-	      zaxisInqLongname(zaxisID, zlongname);
-	      zaxisInqUnits(zaxisID, zunits);
-	      if ( longname && zlongname[0] )
-		{
-		  if ( strcmp(longname, zlongname) != 0 ) differ = 1;
-		}
-	      if ( units && zunits[0] )
-		{
-		  if ( strcmp(units, zunits) != 0 ) differ = 1;
-		}
-	    }
+              if ( longname && longname[0] )
+                {
+                  char zlongname[CDI_MAX_NAME]; zlongname[0] = 0;
+                  zaxisInqLongname(zaxisID, zlongname);
+                  if ( zlongname[0] && (strcmp(longname, zlongname) != 0) ) differ = true;
+                }
+              if ( units && units[0] )
+                {
+                  char zunits[CDI_MAX_NAME]; zunits[0] = 0;
+                  zaxisInqUnits(zaxisID, zunits);
+                  if ( zunits[0] && (strcmp(units, zunits) != 0) ) differ = true;
+                }
+            }
 	}
     }
 
-  return (differ);
+  return differ;
 }
 
 struct varDefZAxisSearchState
@@ -63479,7 +63376,7 @@ struct varDefZAxisSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
   const char *longname;
   const char *units;
@@ -63491,9 +63388,9 @@ varDefZAxisSearch(int id, void *res, void *data)
 {
   struct varDefZAxisSearchState *state = (struct varDefZAxisSearchState *)data;
   (void)res;
-  if (zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
-                   state->levels, state->longname, state->units, state->ltype)
-      == 0)
+  if ( zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
+                    state->levels, state->longname, state->units, state->ltype)
+      == false)
     {
       state->resIDValue = id;
       return CDI_APPLY_STOP;
@@ -63503,17 +63400,17 @@ varDefZAxisSearch(int id, void *res, void *data)
 }
 
 
-int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
-		const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
+int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, const char **cvals, size_t clength, bool lbounds,
+                const double *levels1, const double *levels2, int vctsize, const double *vct, char *name,
 		const char *longname, const char *units, int prec, int mode, int ltype1)
 {
   /*
     mode: 0 search in vlist and zaxis table
           1 search in zaxis table
    */
-  int zaxisdefined = 0;
-  int zaxisID = UNDEFID;
-  int zaxisglobdefined = 0;
+  int zaxisID = CDI_UNDEFID;
+  bool zaxisdefined = false;
+  bool zaxisglobdefined = false;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
   int nzaxis = vlistptr->nzaxis;
 
@@ -63522,9 +63419,9 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
       {
 	zaxisID = vlistptr->zaxisIDs[index];
 
-	if ( zaxisCompare(zaxisID, zaxistype, nlevels, lbounds, levels, longname, units, ltype1) == 0 )
+	if ( !zaxisCompare(zaxisID, zaxistype, nlevels, lbounds, levels, longname, units, ltype1) )
 	  {
-	    zaxisdefined = 1;
+	    zaxisdefined = true;
 	    break;
 	  }
       }
@@ -63549,7 +63446,7 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
 	for (int index = 0; index < nzaxis; index++ )
 	  if ( vlistptr->zaxisIDs[index] == zaxisID )
 	    {
-	      zaxisglobdefined = FALSE;
+	      zaxisglobdefined = false;
 	      break;
 	    }
     }
@@ -63559,20 +63456,24 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
       if ( ! zaxisglobdefined )
 	{
 	  zaxisID = zaxisCreate(zaxistype, nlevels);
-	  zaxisDefLevels(zaxisID, levels);
+	  if ( levels ) zaxisDefLevels(zaxisID, levels);
 	  if ( lbounds )
 	    {
 	      zaxisDefLbounds(zaxisID, levels1);
 	      zaxisDefUbounds(zaxisID, levels2);
 	    }
 
+          if ( cvals != NULL && nlevels != 0 && clength != 0 ) zaxisDefCvals(zaxisID, cvals, (int)clength);
+
 	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
             zaxisDefVct(zaxisID, vctsize, vct);
 
-	  zaxisDefName(zaxisID, name);
-	  zaxisDefLongname(zaxisID, longname);
-	  zaxisDefUnits(zaxisID, units);
-	  zaxisDefPrec(zaxisID, prec);
+	  if ( name && name[0] ) zaxisDefName(zaxisID, name);
+	  if ( longname && longname[0] ) zaxisDefLongname(zaxisID, longname);
+          else                           zaxisDefLongname(zaxisID, "");
+	  if ( units && units[0] ) zaxisDefUnits(zaxisID, units);
+          else                     zaxisDefUnits(zaxisID, "");
+	  zaxisDefDatatype(zaxisID, prec);
 	  zaxisDefLtype(zaxisID, ltype1);
 	}
 
@@ -63580,20 +63481,20 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
       vlistptr->nzaxis++;
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
 void varDefMissval(int varID, double missval)
 {
-  vartable[varID].lmissval = 1;
+  vartable[varID].lmissval = true;
   vartable[varID].missval = missval;
 }
 
 
 void varDefCompType(int varID, int comptype)
 {
-  if ( vartable[varID].comptype == COMPRESS_NONE )
+  if ( vartable[varID].comptype == CDI_COMPRESS_NONE )
     vartable[varID].comptype = comptype;
 }
 
@@ -63606,7 +63507,7 @@ void varDefCompLevel(int varID, int complevel)
 
 int varInqInst(int varID)
 {
-  return (vartable[varID].instID);
+  return vartable[varID].instID;
 }
 
 
@@ -63618,7 +63519,7 @@ void varDefInst(int varID, int instID)
 
 int varInqModel(int varID)
 {
-  return (vartable[varID].modelID);
+  return vartable[varID].modelID;
 }
 
 
@@ -63630,7 +63531,7 @@ void varDefModel(int varID, int modelID)
 
 int varInqTable(int varID)
 {
-  return (vartable[varID].tableID);
+  return vartable[varID].tableID;
 }
 
 
@@ -63664,10 +63565,10 @@ void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate)
 
 #if  defined  (HAVE_LIBGRIB_API)
 /* Resizes and initializes opt_grib_kvpair data structure. */
-static 
+static
 void resize_vartable_opt_grib_entries(vartable_t *var, int nentries)
 {
-  if (var->opt_grib_kvpair_size >= nentries) 
+  if (var->opt_grib_kvpair_size >= nentries)
     {
       return;   /* nothing to do; array is still large enough */
     }
@@ -63687,7 +63588,7 @@ void resize_vartable_opt_grib_entries(vartable_t *var, int nentries)
       for (i=var->opt_grib_kvpair_size; i<new_size; i++) {
         tmp[i].int_val =     0;
         tmp[i].dbl_val =     0;
-        tmp[i].update  = FALSE;
+        tmp[i].update  = false;
         tmp[i].keyword =  NULL;
       } // for
       var->opt_grib_kvpair_size = new_size;
@@ -63740,7 +63641,7 @@ void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keywor
         idx = i;
     }
 
-  if (idx == -1) 
+  if (idx == -1)
     {
       resize_vartable_opt_grib_entries(&vartable[varID], vartable[varID].opt_grib_nentries+1);
       vartable[varID].opt_grib_nentries += 1;
@@ -63762,9 +63663,8 @@ void varDefOptGribDbl(int varID, int tile_index, double dval, const char *keywor
 #if  defined  (HAVE_LIBGRIB_API)
 int varOptGribNentries(int varID)
 {
-  int nentries = 0;
-  nentries = vartable[varID].opt_grib_nentries;
-  return (nentries);
+  int nentries = vartable[varID].opt_grib_nentries;
+  return nentries;
 }
 #endif
 
@@ -63777,65 +63677,6 @@ int varOptGribNentries(int varID)
  * require-trailing-newline: t
  * End:
  */
-#ifndef VLIST_VAR_H
-#define VLIST_VAR_H
-
-#ifdef HAVE_CONFIG_H
-#endif
-
-#ifndef _VLIST_H
-#endif
-
-int  vlistVarGetPackSize(vlist_t *p, int varID, void *context);
-void vlistVarPack(vlist_t *p, int varID,
-                  char * buffer, int bufferSize, int * pos, void *context);
-void vlistVarUnpack(int vlistID,
-                    char * buf, int size, int *position, int, void *context);
-int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB);
-void vlistDefVarIOrank    ( int, int, int );
-int  vlistInqVarIOrank    ( int, int );
-
-void cdiVlistCreateVarLevInfo(vlist_t *vlistptr, int varID);
-
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef VLIST_ATT_H
-#define VLIST_ATT_H
-
-#ifdef HAVE_CONFIG_H
-#endif
-
-int
-vlistAttsGetSize(vlist_t *p, int varID, void *context);
-
-void
-vlistAttsPack(vlist_t *p, int varID,
-              void * buf, int size, int *position, void *context);
-
-void
-vlistAttsUnpack(int vlistID, int varID,
-                void * buf, int size, int *position, void *context);
-
-
-#endif
-
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
 #if defined (HAVE_CONFIG_H)
 #endif
 
@@ -63861,7 +63702,7 @@ static pthread_once_t  _vlist_init_thread = PTHREAD_ONCE_INIT;
 
 #else
 
-static int vlistIsInitialized = 0;
+static bool vlistIsInitialized = false;
 
 #  define VLIST_INIT()               \
   if ( !vlistIsInitialized ) vlist_initialize()
@@ -63871,8 +63712,7 @@ static int vlistIsInitialized = 0;
 static int
 vlist_compare(vlist_t *a, vlist_t *b)
 {
-  int diff;
-  diff = (a->nvars != b->nvars) | (a->ngrids != b->ngrids)
+  int diff = (a->nvars != b->nvars) | (a->ngrids != b->ngrids)
     | (a->nzaxis != b->nzaxis) | (a->instID != b->instID)
     | (a->modelID != b->modelID) | (a->tableID != b->tableID)
     | (a->ntsteps != b->ntsteps) | (a->atts.nelems != b->atts.nelems);
@@ -63881,7 +63721,7 @@ vlist_compare(vlist_t *a, vlist_t *b)
     diff |= vlistVarCompare(a, varID, b, varID);
   size_t natts = a->atts.nelems;
   for (size_t attID = 0; attID < natts; ++attID)
-    diff |= vlist_att_compare(a, CDI_GLOBAL, b, CDI_GLOBAL, (int)attID);
+    diff |= cdi_att_compare(a, CDI_GLOBAL, b, CDI_GLOBAL, (int)attID);
   return diff;
 }
 
@@ -63901,8 +63741,8 @@ const
 resOps vlistOps = {
   (valCompareFunc)vlist_compare,
   (valDestroyFunc)vlist_delete,
-  (valPrintFunc)vlistPrintKernel
-  , vlistGetSizeP,
+  (valPrintFunc)vlistPrintKernel,
+  vlistGetSizeP,
   vlistPackP,
   vlistTxCode
 };
@@ -63911,7 +63751,7 @@ resOps vlistOps = {
 vlist_t *vlist_to_pointer(int vlistID)
 {
   VLIST_INIT();
-  return (vlist_t*) reshGetVal(vlistID, &vlistOps );
+  return (vlist_t*) reshGetVal(vlistID, &vlistOps);
 }
 
 static
@@ -63933,7 +63773,7 @@ void vlist_init_entry(vlist_t *vlistptr)
   vlistptr->atts.nalloc    = MAX_ATTRIBUTES;
   vlistptr->atts.nelems    = 0;
   vlistptr->nsubtypes      = 0;
-  for (int i=0; i<MAX_SUBTYPES_PS; i++)
+  for ( int i = 0; i < MAX_SUBTYPES_PS; i++ )
     vlistptr->subtypeIDs[i] = CDI_UNDEFID;
 }
 
@@ -63949,15 +63789,13 @@ vlist_t *vlist_new_entry(cdiResH resH)
       vlistptr->self = resH;
       reshReplace(resH, vlistptr, &vlistOps);
     }
-  return (vlistptr);
+  return vlistptr;
 }
 
 static
 void vlist_delete_entry(vlist_t *vlistptr)
 {
-  int idx;
-
-  idx = vlistptr->self;
+  int idx = vlistptr->self;
 
   reshRemove(idx, &vlistOps );
 
@@ -63970,12 +63808,10 @@ void vlist_delete_entry(vlist_t *vlistptr)
 static
 void vlist_initialize(void)
 {
-  char *env;
-
-  env = getenv("VLIST_DEBUG");
+  char *env = getenv("VLIST_DEBUG");
   if ( env ) VLIST_Debug = atoi(env);
 #ifndef HAVE_LIBPTHREAD
-  vlistIsInitialized = TRUE;
+  vlistIsInitialized = true;
 #endif
 }
 
@@ -64033,7 +63869,7 @@ int vlistCreate(void)
 
   vlist_t *vlistptr = vlist_new_entry(CDI_UNDEFID);
   if ( CDI_Debug ) Message("create vlistID = %d", vlistptr->self);
-  return (vlistptr->self);
+  return vlistptr->self;
 }
 
 static void
@@ -64042,7 +63878,7 @@ vlist_delete(vlist_t *vlistptr)
   int vlistID = vlistptr->self;
   if ( CDI_Debug ) Message("call to vlist_delete, vlistID = %d", vlistID);
 
-  vlistDelAtts(vlistID, CDI_GLOBAL);
+  cdiDelAtts(vlistID, CDI_GLOBAL);
 
   int nvars = vlistptr->nvars;
   var_t *vars = vlistptr->vars;
@@ -64058,17 +63894,18 @@ vlist_delete(vlist_t *vlistptr)
 
       if ( vlistptr->vars[varID].opt_grib_kvpair )
         {
-          for (int i=0; i<vlistptr->vars[varID].opt_grib_nentries; i++) {
-            if ( vlistptr->vars[varID].opt_grib_kvpair[i].keyword )
-              Free(vlistptr->vars[varID].opt_grib_kvpair[i].keyword);
-          }
+          for ( int i = 0; i<vlistptr->vars[varID].opt_grib_nentries; i++ )
+            {
+              if ( vlistptr->vars[varID].opt_grib_kvpair[i].keyword )
+                Free(vlistptr->vars[varID].opt_grib_kvpair[i].keyword);
+            }
           Free(vlistptr->vars[varID].opt_grib_kvpair);
         }
       vlistptr->vars[varID].opt_grib_nentries    = 0;
       vlistptr->vars[varID].opt_grib_kvpair_size = 0;
       vlistptr->vars[varID].opt_grib_kvpair      = NULL;
 
-      vlistDelAtts(vlistID, varID);
+      cdiDelAtts(vlistID, varID);
     }
 
   if ( vars ) Free(vars);
@@ -64138,7 +63975,7 @@ void var_copy_entries(var_t *var2, var_t *var1)
     if ( var1->opt_grib_kvpair[i].keyword != NULL ) {
       var2->opt_grib_kvpair[i]         = var1->opt_grib_kvpair[i];
       var2->opt_grib_kvpair[i].keyword = strdupx(var1->opt_grib_kvpair[i].keyword);
-      var2->opt_grib_kvpair[i].update  = TRUE;
+      var2->opt_grib_kvpair[i].update  = true;
       if ( CDI_Debug )  Message("done.");
     }
     else {
@@ -64171,7 +64008,7 @@ void vlistCopy(int vlistID2, int vlistID1)
   var_t *vars2 = vlistptr2->vars;
   vlist_copy(vlistptr2, vlistptr1);
 
-  vlistCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
+  cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
 
   if ( vars1 )
     {
@@ -64188,7 +64025,7 @@ void vlistCopy(int vlistID2, int vlistID1)
           var_copy_entries(&vars2[varID], &vars1[varID]);
 
           vlistptr2->vars[varID].atts.nelems = 0;
-	  vlistCopyVarAtts(vlistID1, varID, vlistID2, varID);
+	  cdiCopyAtts(vlistID1, varID, vlistID2, varID);
 
           if ( vars1[varID].levinfo )
             {
@@ -64222,23 +64059,22 @@ int vlistDuplicate(int vlistID)
 
   int vlistIDnew = vlistCreate();
   vlistCopy(vlistIDnew, vlistID);
-  return (vlistIDnew);
+  return vlistIDnew;
 }
 
 
 void vlistClearFlag(int vlistID)
 {
-  int varID, levID;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  for ( varID = 0; varID < vlistptr->nvars; varID++ )
+  for ( int varID = 0; varID < vlistptr->nvars; varID++ )
     {
-      vlistptr->vars[varID].flag = FALSE;
+      vlistptr->vars[varID].flag = false;
       if ( vlistptr->vars[varID].levinfo )
         {
           int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
-          for ( levID = 0; levID < nlevs; levID++ )
-            vlistptr->vars[varID].levinfo[levID].flag = FALSE;
+          for ( int levID = 0; levID < nlevs; levID++ )
+            vlistptr->vars[varID].levinfo[levID].flag = false;
         }
     }
 }
@@ -64249,7 +64085,7 @@ struct vgzSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
 };
 
@@ -64260,7 +64096,7 @@ vgzZAxisSearch(int id, void *res, void *data)
   (void)res;
   if (zaxisCompare(id, state->zaxistype, state->nlevels, state->lbounds,
                    state->levels, NULL, NULL, 0)
-      == 0)
+      == false)
     {
       state->resIDValue = id;
       return CDI_APPLY_STOP;
@@ -64269,27 +64105,27 @@ vgzZAxisSearch(int id, void *res, void *data)
     return CDI_APPLY_GO_ON;
 }
 
-
 static
 int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *levels,
-                         const double *lbounds, const double *ubounds, int vctsize, const double *vct)
+                         const double *lbounds, const double *ubounds, int vctsize, const double *vct,
+                         const char **cvals, size_t clen)
 {
   int zaxisID = CDI_UNDEFID;
-  int zaxisglobdefined = 0;
-  int has_bounds = FALSE;
+  bool zaxisdefined = false;
+  bool zaxisglobdefined = false;
+  bool has_bounds = false;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  int zaxisdefined = 0;
   int nzaxis = vlistptr->nzaxis;
 
-  if ( lbounds && ubounds ) has_bounds = TRUE;
+  if ( lbounds && ubounds ) has_bounds = true;
 
   for ( int index = 0; index < nzaxis; ++index )
     {
       zaxisID = vlistptr->zaxisIDs[index];
 
-      if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0) == 0 )
+      if ( zaxisCompare(zaxisID, zaxistype, nlevels, has_bounds, levels, NULL, NULL, 0) == false )
         {
-          zaxisdefined = 1;
+          zaxisdefined = true;
           break;
         }
     }
@@ -64314,6 +64150,10 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
 	{
 	  zaxisID = zaxisCreate(zaxistype, nlevels);
 	  zaxisDefLevels(zaxisID, levels);
+
+          if ( zaxistype == ZAXIS_CHAR )
+            zaxisDefCvals(zaxisID, cvals, (int)clen);
+
 	  if ( has_bounds )
 	    {
 	      zaxisDefLbounds(zaxisID, lbounds);
@@ -64329,7 +64169,7 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
       vlistptr->nzaxis++;
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 /*
@@ -64355,34 +64195,29 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 
   vlist_copy(vlistptr2, vlistptr1);
 
-  vlistCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
+  cdiCopyAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
 
   if ( vlistptr1->vars )
     {
-      int nvars = vlistptr1->nvars;
-      int nvars2 = 0;
-      int varID2;
-
       vlistptr2->ngrids = 0;
       vlistptr2->nzaxis = 0;
 
+      int nvars = vlistptr1->nvars;
+      int nvars2 = 0;
       for ( int varID = 0; varID < nvars; varID++ )
-        nvars2 += (vars1[varID].flag != 0);
+        nvars2 += vars1[varID].flag;
 
       vlistptr2->nvars = nvars2;
       vlistptr2->varsAllocated = nvars2;
-      if ( nvars2 > 0 )
-        vars2 = (var_t *) Malloc((size_t)nvars2*sizeof(var_t));
-      else
-        vars2 = NULL;
+      vars2 = (nvars2 > 0) ? (var_t *) Malloc((size_t)nvars2*sizeof(var_t)) : NULL;
 
       vlistptr2->vars = vars2;
 
-      varID2 = 0;
+      int varID2 = 0;
       for ( int varID = 0; varID < nvars; varID++ )
 	if ( vars1[varID].flag )
 	  {
-	    vlistptr2->vars[varID2].flag = FALSE;
+	    vlistptr2->vars[varID2].flag = false;
 	    int zaxisID   = vlistptr1->vars[varID].zaxisID;
 	    int gridID    = vlistptr1->vars[varID].gridID;
 	    int subtypeID = vlistptr1->vars[varID].subtypeID;
@@ -64397,46 +64232,80 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
             var_copy_entries(&vars2[varID2], &vars1[varID]);
 
 	    vlistptr2->vars[varID2].atts.nelems = 0;
-	    vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);
+	    cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
 
 	    int nlevs  = zaxisInqSize(vars1[varID].zaxisID);
 	    int nlevs2 = 0;
             if ( vars1[varID].levinfo )
               for ( int levID = 0; levID < nlevs; levID++ )
-                nlevs2 += (vars1[varID].levinfo[levID].flag != 0);
+                nlevs2 += vars1[varID].levinfo[levID].flag;
 
 	    vars2[varID2].levinfo = (levinfo_t *) Malloc((size_t)nlevs2 * sizeof(levinfo_t));
 
 	    if ( nlevs != nlevs2 )
 	      {
 		int nvct = 0;
+                double *levels = NULL;
+                char **cvals1 = NULL, **cvals2 = NULL;
+                size_t clen2 = 0;
 		double *lbounds = NULL, *ubounds = NULL;
 		const double *vct = NULL;
                 char ctemp[CDI_MAX_NAME];
 
+                if ( !vars1[varID].levinfo ) cdiVlistCreateVarLevInfo(vlistptr1, varID);
+
 		zaxisID = vars1[varID].zaxisID;
-		double *levels = (double *) Malloc((size_t)nlevs2 * sizeof (double));
-                if ( !vars1[varID].levinfo )
-                  cdiVlistCreateVarLevInfo(vlistptr1, varID);
+                int zaxisType = zaxisInqType(zaxisID);
 
-                {
-                  int levID2 = 0;
-                  for ( int levID = 0; levID < nlevs; ++levID )
-                    if ( vars1[varID].levinfo[levID].flag )
-                      {
-                        vars1[varID].levinfo[levID].flevelID = levID2;
-                        vars1[varID].levinfo[levID].mlevelID = levID2;
+                int levID2 = 0;
+                for ( int levID = 0; levID < nlevs; ++levID )
+                  if ( vars1[varID].levinfo[levID].flag )
+                    {
+                      vars1[varID].levinfo[levID].flevelID = levID2;
+                      vars1[varID].levinfo[levID].mlevelID = levID2;
+                    }
+
+
+                if ( zaxisInqLevels(zaxisID, NULL) )
+                  {
+                    levels = (double *) Malloc((size_t)nlevs2 * sizeof (double));
+
+                    levID2 = 0;
+                    for ( int levID = 0; levID < nlevs; ++levID )
+                      if ( vars1[varID].levinfo[levID].flag )
                         levels[levID2++] = zaxisInqLevel(zaxisID, levID);
-                      }
-                }
+                  }
 
-		int zaxisType = zaxisInqType(zaxisID);
+                if ( zaxisType == ZAXIS_HYBRID )
+                  {
+                    nvct = zaxisInqVctSize(zaxisID);
+                    vct  = zaxisInqVctPtr(zaxisID);
+                  }
 
-		if ( zaxisType == ZAXIS_HYBRID )
-		  {
-		    nvct = zaxisInqVctSize(zaxisID);
-		    vct  = zaxisInqVctPtr(zaxisID);
-		  }
+                if ( zaxisType == ZAXIS_CHAR )
+                  {
+                    cvals1 = zaxisInqCValsPtr(zaxisID);
+                    size_t clen1 = (size_t)zaxisInqCLen(zaxisID);
+                    for ( int levID = 0; levID < nlevs; ++levID )
+                      if ( vars1[varID].levinfo[levID].flag )
+                          {
+                            size_t testlen = clen1;
+                            while ( cvals1[levID][testlen] == ' ' )
+                              testlen--;
+                            if ( clen2 < testlen )
+                              clen2 = testlen;
+                          }
+                    cvals2 = (char **) Malloc((size_t)nlevs2 * sizeof (char *));
+                    levID2 = 0;
+
+                    for ( int levID = 0; levID < nlevs; ++levID )
+                      if ( vars1[varID].levinfo[levID].flag )
+                        {
+                          cvals2[levID2] = Malloc((size_t)(clen2) * sizeof (char));
+                          memcpy(cvals2[levID2], cvals1[levID], clen2*sizeof(char));
+                          levID2++;
+                        }
+                  }
 
                 if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
                   {
@@ -64444,12 +64313,12 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                     ubounds = lbounds + nlevs2;
 
                     double *lbounds1 = (double *) Malloc(2 * (size_t)nlevs * sizeof (double)),
-                      *ubounds1 = lbounds1 + nlevs;
+                           *ubounds1 = lbounds1 + nlevs;
 
                     zaxisInqLbounds(zaxisID, lbounds1);
                     zaxisInqUbounds(zaxisID, ubounds1);
 
-                    int levID2 = 0;
+                    levID2 = 0;
                     for ( int levID = 0; levID < nlevs; ++levID )
                       if ( vars1[varID].levinfo[levID].flag )
                         {
@@ -64461,9 +64330,15 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                     Free(lbounds1);
                   }
 
-		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct);
-		free(levels);
-                Free(lbounds);
+		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct, (const char **)cvals2, clen2);
+		if ( levels )  Free(levels);
+                if ( lbounds ) Free(lbounds);
+                if ( cvals2 )
+                  {
+                    for ( int levID = 0; levID < nlevs2; ++levID )
+                      Free(cvals2[levID]);
+                    Free(cvals2);
+                  }
 
                 zaxisInqName(zaxisID, ctemp);
                 zaxisDefName(zaxisID2, ctemp);
@@ -64471,6 +64346,17 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                 zaxisDefLongname(zaxisID2, ctemp);
                 zaxisInqUnits(zaxisID, ctemp);
                 zaxisDefUnits(zaxisID2, ctemp);
+                zaxisDefDatatype(zaxisID2, zaxisInqDatatype(zaxisID));
+
+                if ( zaxisType == ZAXIS_CHAR )
+                  {
+                    char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
+                    cdiZaxisInqKeyStr(zaxisID, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
+                    if ( dimname[0] == 0 ) { memcpy(dimname, "area_type", 10); dimname[10] = 0; }
+                    cdiZaxisDefKeyStr(zaxisID2, CDI_KEY_DIMNAME, CDI_MAX_NAME, dimname);
+                  }
+
+                if ( zaxisType == ZAXIS_GENERIC ) zaxisDefLtype(zaxisID2, zaxisInqLtype(zaxisID));
 
 		zaxisID = zaxisID2;
 		vars2[varID2].zaxisID = zaxisID2;
@@ -64478,7 +64364,7 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 
 	    for ( int levID = 0; levID < nlevs2; levID++ )
 	      {
-		vars2[varID2].levinfo[levID].flag  = FALSE;
+		vars2[varID2].levinfo[levID].flag  = false;
 		vars2[varID2].levinfo[levID].index = -1;
 	      }
 
@@ -64561,7 +64447,7 @@ void vlistCat(int vlistID2, int vlistID1)
         }
 
       vars2[varID2].atts.nelems = 0;
-      vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);
+      cdiCopyAtts(vlistID1, varID, vlistID2, varID2);
 
       vlistAdd2GridIDs(vlistptr2, vars1[varID].gridID);
       vlistAdd2ZaxisIDs(vlistptr2, vars1[varID].zaxisID);
@@ -64597,8 +64483,8 @@ void vlistMerge(int vlistID2, int vlistID1)
     {
       for ( varID = 0; varID < nvars2; varID++ )
 	{
-          int ngp1 = gridInqSize(vars1[varID].gridID);
-          int ngp2 = gridInqSize(vars2[varID].gridID);
+          size_t ngp1 = gridInqSize(vars1[varID].gridID);
+          size_t ngp2 = gridInqSize(vars2[varID].gridID);
           if ( ngp1 != ngp2 ) break;
 
 	  if ( vars1[varID].name && vars2[varID].name )
@@ -64645,11 +64531,11 @@ void vlistMerge(int vlistID2, int vlistID1)
             vars1[varID].levinfo[levID].mlevelID = nlevs2 + levID;
 	}
 
-      int *lvar = (int *) Calloc((size_t)nvars2, sizeof(int));
+      bool *lvar = (bool *) Calloc((size_t)nvars2, sizeof(bool));
 
       for ( varID = 0; varID < nvars2; varID++ )
         {
-          if ( lvar[varID] == TRUE ) continue;
+          if ( lvar[varID] == true ) continue;
 
           int zaxisID1 = vars1[varID].zaxisID;
           int zaxisID2 = vars2[varID].zaxisID;
@@ -64665,30 +64551,32 @@ void vlistMerge(int vlistID2, int vlistID1)
           int nlevs = nlevs1 + nlevs2;
 
           int zaxisID = zaxisDuplicate(zaxisID2);
-
           zaxisResize(zaxisID, nlevs);
 
-          double *levels = (double *) Malloc((size_t)nlevs1 * sizeof(double));
+          if ( zaxisInqLevels(zaxisID1, NULL) )
+            {
+              double *levels = (double *) Malloc((size_t)nlevs1 * sizeof(double));
 
-          zaxisInqLevels(zaxisID1, levels);
-          /*
-          for ( levID = 0; levID < nlevs1; levID++ )
-            fprintf(stderr, "%d %d %d %d %d %g\n", varID, levID, nlevs1, nlevs2, vars2[varID].nlevs, levels[levID]);
-          */
-          for ( int levID = 0; levID < nlevs1; levID++ )
-            zaxisDefLevel(zaxisID, nlevs2+levID, levels[levID]);
+              zaxisInqLevels(zaxisID1, levels);
+              /*
+                for ( levID = 0; levID < nlevs1; levID++ )
+                fprintf(stderr, "%d %d %d %d %d %g\n", varID, levID, nlevs1, nlevs2, vars2[varID].nlevs, levels[levID]);
+              */
+              for ( int levID = 0; levID < nlevs1; levID++ )
+                zaxisDefLevel(zaxisID, nlevs2+levID, levels[levID]);
 
-          Free(levels);
+              Free(levels);
+            }
 
           for ( int index = 0; index < vlistptr2->nzaxis; index++ )
             if ( vlistptr2->zaxisIDs[index] == zaxisID2 )
               vlistptr2->zaxisIDs[index] = zaxisID;
 
           for ( int varID2 = 0; varID2 < nvars2; varID2++ )
-            if ( lvar[varID2] == FALSE && vars2[varID2].zaxisID == zaxisID2 )
+            if ( lvar[varID2] == false && vars2[varID2].zaxisID == zaxisID2 )
               {
                 vars2[varID2].zaxisID = zaxisID;
-                lvar[varID2] = TRUE;
+                lvar[varID2] = true;
               }
         }
 
@@ -64719,29 +64607,29 @@ The function @func{vlistNvars} returns the number of variables in the variable l
 int vlistNvars(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->nvars);
+  return vlistptr->nvars;
 }
 
 
 int vlistNrecs(int vlistID)
 {
-  int nrecs = 0;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
+  int nrecs = 0;
   for ( int varID = 0; varID < vlistptr->nvars; varID++ )
     nrecs +=  zaxisInqSize(vlistptr->vars[varID].zaxisID);
 
-  return (nrecs);
+  return nrecs;
 }
 
 
 int vlistNumber(int vlistID)
 {
-  int number, number2, datatype;
+  int number, number2;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  datatype = vlistptr->vars[0].datatype;
-  if (  datatype== DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+  int datatype = vlistptr->vars[0].datatype;
+  if (  datatype== CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
     number = CDI_COMP;
   else
     number = CDI_REAL;
@@ -64749,7 +64637,7 @@ int vlistNumber(int vlistID)
   for ( int varID = 1; varID < vlistptr->nvars; varID++ )
     {
       datatype = vlistptr->vars[varID].datatype;
-      if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
+      if ( datatype == CDI_DATATYPE_CPX32 || datatype == CDI_DATATYPE_CPX64 )
         number2 = CDI_COMP;
       else
         number2 = CDI_REAL;
@@ -64761,7 +64649,7 @@ int vlistNumber(int vlistID)
         }
     }
 
-  return (number);
+  return number;
 }
 
 /*
@@ -64784,7 +64672,7 @@ int vlistNgrids(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->ngrids);
+  return vlistptr->ngrids;
 }
 
 /*
@@ -64807,7 +64695,7 @@ int vlistNzaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nzaxis);
+  return vlistptr->nzaxis;
 }
 
 
@@ -64815,7 +64703,7 @@ int vlistNsubtypes(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nsubtypes);
+  return vlistptr->nsubtypes;
 }
 
 
@@ -64823,7 +64711,7 @@ void vlistDefNtsteps(int vlistID, int nts)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if (vlistptr->ntsteps != nts)
+  if ( vlistptr->ntsteps != nts )
     {
       vlistptr->ntsteps = nts;
       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
@@ -64901,7 +64789,8 @@ void vlistPrintKernel(vlist_t *vlistptr, FILE *fp)
               int mlevID = li.mlevelID;
               int index  = li.index;
               int flag   = li.flag;
-              double level  = zaxisInqLevel(zaxisID, levID);
+
+              double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levID) : levID+1;
 
               fprintf(fp, "%6d %6d %6d %6d %6d %6d %6d %6d %5d  %.9g\n",
                       varID, levID, fvarID, flevID, mvarID, mlevID, index,
@@ -64912,7 +64801,7 @@ void vlistPrintKernel(vlist_t *vlistptr, FILE *fp)
       fputs("\n"
             " varID  size iorank\n", fp);
       for ( int varID = 0; varID < nvars; varID++ )
-        fprintf(fp, "%3d %8d %6d\n", varID,
+        fprintf(fp, "%3d %8zu %6d\n", varID,
                 zaxisInqSize(vlistptr->vars[varID].zaxisID)
                 * gridInqSize(vlistptr->vars[varID].gridID),
                 vlistptr->vars[varID].iorank);
@@ -64945,7 +64834,7 @@ void vlistDefTaxis(int vlistID, int taxisID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if (vlistptr->taxisID != taxisID)
+  if ( vlistptr->taxisID != taxisID )
     {
       //FIXME: This code seems to leak a taxis_t object if `vlistptr->taxisID` was valid before the call to vlistDefTaxis.
       vlistptr->taxisID = taxisID;
@@ -64973,7 +64862,7 @@ int vlistInqTaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->taxisID);
+  return vlistptr->taxisID;
 }
 
 
@@ -64981,7 +64870,7 @@ void vlistDefTable(int vlistID, int tableID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if (vlistptr->tableID != tableID)
+  if ( vlistptr->tableID != tableID )
     {
       vlistptr->tableID = tableID;
       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
@@ -64993,7 +64882,7 @@ int vlistInqTable(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->tableID);
+  return vlistptr->tableID;
 }
 
 
@@ -65001,7 +64890,7 @@ void vlistDefInstitut(int vlistID, int instID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if (vlistptr->instID != instID)
+  if ( vlistptr->instID != instID )
     {
       vlistptr->instID = instID;
       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
@@ -65028,7 +64917,7 @@ int vlistInqInstitut(int vlistID)
       vlistDefInstitut(vlistID, instID);
     }
 
-  return (instID);
+  return instID;
 }
 
 
@@ -65036,7 +64925,7 @@ void vlistDefModel(int vlistID, int modelID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  if (vlistptr->modelID != modelID)
+  if ( vlistptr->modelID != modelID )
     {
       vlistptr->modelID = modelID;
       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
@@ -65064,23 +64953,23 @@ int vlistInqModel(int vlistID)
       vlistDefModel(vlistID, modelID);
     }
 
-  return (modelID);
+  return modelID;
 }
 
 
-int vlistGridsizeMax(int vlistID)
+size_t vlistGridsizeMax(int vlistID)
 {
-  int gridsizemax = 0;
+  size_t gridsizemax = 0;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   for ( int index = 0 ; index < vlistptr->ngrids ; index++ )
     {
       int gridID = vlistptr->gridIDs[index];
-      int gridsize = gridInqSize(gridID);
+      size_t gridsize = gridInqSize(gridID);
       if ( gridsize > gridsizemax ) gridsizemax = gridsize;
     }
 
-  return (gridsizemax);
+  return gridsizemax;
 }
 
 
@@ -65092,7 +64981,7 @@ int vlistGrid(int vlistID, int index)
   if ( index < vlistptr->ngrids && index >= 0 )
     gridID = vlistptr->gridIDs[index];
 
-  return (gridID);
+  return gridID;
 }
 
 
@@ -65106,7 +64995,7 @@ int vlistGridIndex(int vlistID, int gridID)
 
   if ( index == vlistptr->ngrids ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -65160,7 +65049,7 @@ int vlistZaxis(int vlistID, int index)
   if ( index < vlistptr->nzaxis && index >= 0 )
     zaxisID = vlistptr->zaxisIDs[index];
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
@@ -65174,7 +65063,7 @@ int vlistZaxisIndex(int vlistID, int zaxisID)
 
   if ( index == vlistptr->nzaxis ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -65268,25 +65157,27 @@ int vlistSubtypeIndex(int vlistID, int subtypeID)
 
 int vlistHasTime(int vlistID)
 {
-  int hastime = FALSE;
+  bool hastime = false;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  for ( int varID = 0; varID <  vlistptr->nvars; varID++ )
-    if ( vlistptr->vars[varID].tsteptype != TSTEP_CONSTANT )
-      {
-        hastime = TRUE;
-        break;
-      }
+  if ( !(CDI_reduce_dim && vlistptr->ntsteps == 1) )
+    {
+      for ( int varID = 0; varID <  vlistptr->nvars; varID++ )
+        if ( vlistptr->vars[varID].timetype != TIME_CONSTANT )
+          {
+            hastime = true;
+            break;
+          }
+    }
 
-  return (hastime);
+  return (int)hastime;
 }
 
 enum {
   vlist_nints=6,
 };
 
-static int
-vlistTxCode ( void )
+static int vlistTxCode ( void )
 {
   return VLIST;
 }
@@ -65297,9 +65188,9 @@ int  vlistGetSizeP ( void * vlistptr, void *context)
 {
   int txsize, varID;
   vlist_t *p = (vlist_t*) vlistptr;
-  txsize = serializeGetSize(vlist_nints, DATATYPE_INT, context);
-  txsize += serializeGetSize(1, DATATYPE_LONG, context);
-  txsize += vlistAttsGetSize(p, CDI_GLOBAL, context);
+  txsize = serializeGetSize(vlist_nints, CDI_DATATYPE_INT, context);
+  txsize += serializeGetSize(1, CDI_DATATYPE_LONG, context);
+  txsize += cdiAttsGetSize(p, CDI_GLOBAL, context);
   for ( varID = 0; varID <  p->nvars; varID++ )
     txsize += vlistVarGetPackSize(p, varID, context);
   return txsize;
@@ -65318,10 +65209,10 @@ void vlistPackP ( void * vlistptr, void * buf, int size, int *position,
   tempbuf[3] = p->tableID;
   tempbuf[4] = p->instID;
   tempbuf[5] = p->modelID;
-  serializePack(tempbuf, vlist_nints, DATATYPE_INT, buf, size, position, context);
-  serializePack(&p->ntsteps, 1, DATATYPE_LONG, buf, size, position, context);
+  serializePack(tempbuf, vlist_nints, CDI_DATATYPE_INT, buf, size, position, context);
+  serializePack(&p->ntsteps, 1, CDI_DATATYPE_LONG, buf, size, position, context);
 
-  vlistAttsPack(p, CDI_GLOBAL, buf, size, position, context);
+  cdiAttsPack(p, CDI_GLOBAL, buf, size, position, context);
   for ( varID = 0; varID < p->nvars; varID++ )
     {
       vlistVarPack(p, varID, (char *)buf, size, position, context);
@@ -65332,7 +65223,7 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
                  void *context, int force_id)
 {
   int tempbuf[vlist_nints];
-  serializeUnpack(buf, size, position, tempbuf, vlist_nints, DATATYPE_INT, context);
+  serializeUnpack(buf, size, position, tempbuf, vlist_nints, CDI_DATATYPE_INT, context);
   int nvars = tempbuf[1];
   int targetID = namespaceAdaptKey(tempbuf[0], originNamespace);
   vlist_t *p = vlist_new_entry(force_id?targetID:CDI_UNDEFID);
@@ -65344,8 +65235,8 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
   p->tableID = tempbuf[3];
   p->instID = namespaceAdaptKey(tempbuf[4], originNamespace);
   p->modelID = namespaceAdaptKey(tempbuf[5], originNamespace);
-  serializeUnpack(buf, size, position, &p->ntsteps, 1, DATATYPE_LONG, context);
-  vlistAttsUnpack(targetID, CDI_GLOBAL, buf, size, position, context);
+  serializeUnpack(buf, size, position, &p->ntsteps, 1, CDI_DATATYPE_LONG, context);
+  cdiAttsUnpack(targetID, CDI_GLOBAL, buf, size, position, context);
   for (int varID = 0; varID < nvars; varID++ )
     vlistVarUnpack(targetID, buf, size, position, originNamespace, context);
   reshSetStatus(targetID, &vlistOps,
@@ -65355,11 +65246,10 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
 
 void vlist_check_contents(int vlistID)
 {
-  int index, nzaxis, zaxisID;
-
-  nzaxis = vlistNzaxis(vlistID);
+  int zaxisID;
+  int nzaxis = vlistNzaxis(vlistID);
 
-  for ( index = 0; index < nzaxis; index++ )
+  for ( int index = 0; index < nzaxis; index++ )
     {
       zaxisID = vlistZaxis(vlistID, index);
       if ( zaxisInqType(zaxisID) == ZAXIS_GENERIC )
@@ -65371,7 +65261,7 @@ void vlist_check_contents(int vlistID)
 /* Resizes and initializes opt_grib_kvpair data structure. */
 void resize_opt_grib_entries(var_t *var, int nentries)
 {
-  if (var->opt_grib_kvpair_size >= nentries) 
+  if (var->opt_grib_kvpair_size >= nentries)
     {
       if ( CDI_Debug )
         Message("data structure has size %d, no resize to %d needed.", var->opt_grib_kvpair_size, nentries);
@@ -65391,7 +65281,7 @@ void resize_opt_grib_entries(var_t *var, int nentries)
       for (i=var->opt_grib_kvpair_size; i<new_size; i++) {
         tmp[i].int_val =     0;
         tmp[i].dbl_val =     0;
-        tmp[i].update  = FALSE;
+        tmp[i].update  = false;
         tmp[i].keyword =  NULL;
       } // for
       var->opt_grib_kvpair_size = new_size;
@@ -65419,6 +65309,7 @@ void resize_opt_grib_entries(var_t *var, int nentries)
 
 
 
+
 static
 cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
 {
@@ -65434,7 +65325,7 @@ cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
 	attsp = &(vlistptr->vars[varID].atts);
     }
 
-  return (attsp);
+  return attsp;
 }
 
 static
@@ -65452,27 +65343,24 @@ cdi_att_t *find_att(cdi_atts_t *attsp, const char *name)
     {
       cdi_att_t *attp = atts + attid;
       if ( attp->namesz == slen && memcmp(attp->name, name, slen) == 0 )
-        return (attp); /* Normal return */
+        return attp; /* Normal return */
     }
 
-  return (NULL);
+  return NULL;
 }
 
 static
 cdi_att_t *new_att(cdi_atts_t *attsp, const char *name)
 {
-  cdi_att_t *attp;
-  size_t slen;
-
   xassert(attsp != NULL);
   xassert(name  != NULL);
 
-  if ( attsp->nelems == attsp->nalloc ) return (NULL);
+  if ( attsp->nelems == attsp->nalloc ) return NULL;
 
-  attp = &(attsp->value[attsp->nelems]);
+  cdi_att_t *attp = &(attsp->value[attsp->nelems]);
   attsp->nelems++;
 
-  slen = strlen(name);
+  size_t slen = strlen(name);
   if ( slen > CDI_MAX_NAME ) slen = CDI_MAX_NAME;
 
   attp->name = (char *) Malloc(slen+1);
@@ -65480,7 +65368,7 @@ cdi_att_t *new_att(cdi_atts_t *attsp, const char *name)
   attp->namesz = slen;
   attp->xvalue = NULL;
 
-  return (attp);
+  return attp;
 }
 
 static
@@ -65500,44 +65388,64 @@ void fill_att(cdi_att_t *attp, int indtype, int exdtype, size_t nelems, size_t x
     }
 }
 
+static
+cdi_atts_t *cdi_get_attsp(int objID, int varID)
+{
+  cdi_atts_t *attsp = NULL;
+
+  if ( varID == CDI_GLOBAL && reshGetTxCode(objID) == GRID )
+    {
+      grid_t *gridptr = grid_to_pointer(objID);
+      attsp = &gridptr->atts;
+    }
+  else if ( varID == CDI_GLOBAL && reshGetTxCode(objID) == ZAXIS )
+    {
+      zaxis_t *zaxisptr = zaxis_to_pointer(objID);
+      attsp = &zaxisptr->atts;
+    }
+  else
+    {
+      vlist_t *vlistptr = vlist_to_pointer(objID);
+      attsp = get_attsp(vlistptr, varID);
+    }
+
+  return attsp;
+}
+
 /*
- at Function  vlistInqNatts
- at Title     Get number of variable attributes
+ at Function  cdiInqNatts
+ at Title     Get number of attributes
 
- at Prototype int vlistInqNatts(int vlistID, int varID, int *nattsp)
+ at Prototype int cdiInqNatts(int cdiID, int varID, int *nattsp)
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
-    @Item  nattsp   Pointer to location for returned number of variable attributes.
+    @Item  nattsp   Pointer to location for returned number of attributes.
 
 @Description
-The function @func{vlistInqNatts} gets the number of variable attributes assigned to this variable.
+The function @func{cdiInqNatts} gets the number of attributes assigned to this variable.
 
 @EndFunction
 */
-int vlistInqNatts(int vlistID, int varID, int *nattsp)
+int cdiInqNatts(int cdiID, int varID, int *nattsp)
 {
   int status = CDI_NOERR;
-  vlist_t *vlistptr;
-  cdi_atts_t *attsp;
 
-  vlistptr = vlist_to_pointer(vlistID);
-
-  attsp = get_attsp(vlistptr, varID);
+  cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
   xassert(attsp != NULL);
 
   *nattsp = (int)attsp->nelems;
 
-  return (status);
+  return status;
 }
 
 /*
- at Function  vlistInqAtt
+ at Function  cdiInqAtt
 @Title     Get information about an attribute
 
- at Prototype int vlistInqAtt(int vlistID, int varID, int attnum, char *name, int *typep, int *lenp)
+ at Prototype int cdiInqAtt(int cdiID, int varID, int attnum, char *name, int *typep, int *lenp)
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  attnum   Attribute number (from 0 to natts-1).
     @Item  name     Pointer to the location for the returned attribute name. The caller must allocate space for the
@@ -65547,22 +65455,20 @@ int vlistInqNatts(int vlistID, int varID, int *nattsp)
     @Item  lenp     Pointer to location for returned attribute number.
 
 @Description
-The function @func{vlistInqAtt} gets information about an attribute.
+The function @func{cdiInqAtt} gets information about an attribute.
 
 @EndFunction
 */
-int vlistInqAtt(int vlistID, int varID, int attnum, char *name, int *typep, int *lenp)
+int cdiInqAtt(int cdiID, int varID, int attnum, char *name, int *typep, int *lenp)
 {
   int status = CDI_NOERR;
-  cdi_att_t *attp = NULL;
 
   xassert(name != NULL);
 
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  cdi_atts_t *attsp = get_attsp(vlistptr, varID);
+  cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
   xassert(attsp != NULL);
 
+  cdi_att_t *attp = NULL;
   if ( attnum >= 0 && attnum < (int)attsp->nelems )
     attp = &(attsp->value[attnum]);
 
@@ -65580,102 +65486,79 @@ int vlistInqAtt(int vlistID, int varID, int attnum, char *name, int *typep, int
       status  = -1;
     }
 
-  return (status);
+  return status;
 }
 
 
-int vlistDelAtts(int vlistID, int varID)
+int cdiDelAtts(int cdiID, int varID)
 {
   int status = CDI_NOERR;
-  vlist_t *vlistptr;
-  cdi_att_t *attp = NULL;
-  cdi_atts_t *attsp;
-  int attid;
-
-  vlistptr = vlist_to_pointer(vlistID);
 
-  attsp = get_attsp(vlistptr, varID);
+  cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
   xassert(attsp != NULL);
 
-  for ( attid = 0; attid < (int)attsp->nelems; attid++ )
+  for ( int attid = 0; attid < (int)attsp->nelems; attid++ )
     {
-      attp = &(attsp->value[attid]);
+      cdi_att_t *attp = &(attsp->value[attid]);
       if ( attp->name   ) Free(attp->name);
       if ( attp->xvalue ) Free(attp->xvalue);
     }
 
   attsp->nelems = 0;
 
-  return (status);
+  return status;
 }
 
 
-int vlistDelAtt(int vlistID, int varID, const char *name)
+int cdiDelAtt(int cdiID, int varID, const char *name)
 {
   int status = CDI_NOERR;
 
-  UNUSED(vlistID);
+  UNUSED(cdiID);
   UNUSED(varID);
   UNUSED(name);
 
-  fprintf(stderr, "vlistDelAtt not implemented!\n");
+  fprintf(stderr, "cdiDelAtt not implemented!\n");
 
-  return (status);
+  return status;
 }
 
 static
-int vlist_def_att(int indtype, int exdtype, int vlistID, int varID, const char *name, size_t len, size_t xsz, const void *xp)
+int cdi_def_att(int indtype, int exdtype, int cdiID, int varID, const char *name, size_t len, size_t xsz, const void *xp)
 {
   int status = CDI_NOERR;
-  vlist_t *vlistptr;
-  cdi_att_t *attp;
-  cdi_atts_t *attsp;
 
   if ( len != 0 && xp == NULL ) /* Null arg */
-    {
-      return (CDI_EINVAL);
-    }
+    return CDI_EINVAL;
 
-  vlistptr = vlist_to_pointer(vlistID);
-
-  attsp = get_attsp(vlistptr, varID);
+  cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
   xassert(attsp != NULL);
 
-  attp = find_att(attsp, name);
-  if ( attp == NULL )
-    attp = new_att(attsp, name);
+  cdi_att_t *attp = find_att(attsp, name);
+  if ( attp == NULL ) attp = new_att(attsp, name);
 
-  if ( attp != NULL )
-    fill_att(attp, indtype, exdtype, len, xsz, xp);
+  if ( attp != NULL ) fill_att(attp, indtype, exdtype, len, xsz, xp);
 
-  return (status);
+  return status;
 }
 
 static
-int vlist_inq_att(int indtype, int vlistID, int varID, const char *name, size_t mxsz, void *xp)
+int cdi_inq_att(int indtype, int cdiID, int varID, const char *name, size_t mxsz, void *xp)
 {
   int status = CDI_NOERR;
-  vlist_t *vlistptr;
-  cdi_att_t *attp;
-  cdi_atts_t *attsp;
-  size_t xsz;
 
   if ( mxsz != 0 && xp == NULL ) /* Null arg */
-    {
-      return (CDI_EINVAL);
-    }
-
-  vlistptr = vlist_to_pointer(vlistID);
+    return CDI_EINVAL;
 
-  attsp = get_attsp(vlistptr, varID);
+  cdi_atts_t *attsp = cdi_get_attsp(cdiID, varID);
   xassert(attsp != NULL);
 
-  attp = find_att(attsp, name);
+  cdi_att_t *attp = find_att(attsp, name);
   if ( attp != NULL ) /* name in use */
     {
       if ( attp->indtype == indtype )
 	{
-	  xsz = attp->xsz;
+	  size_t xsz = attp->xsz;
 	  if ( mxsz < xsz ) xsz = mxsz;
 	  if ( xsz > 0 )
 	    memcpy(xp, attp->xvalue, xsz);
@@ -65692,184 +65575,178 @@ int vlist_inq_att(int indtype, int vlistID, int varID, const char *name, size_t
       status = -1;
     }
 
-  return (status);
+  return status;
 }
 
 
-int vlistCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2)
+int cdiCopyAtts(int cdiID1, int varID1, int cdiID2, int varID2)
 {
   int status = CDI_NOERR;
-  vlist_t *vlistptr1;
-  cdi_att_t *attp = NULL;
-  cdi_atts_t *attsp1;
-  int attid;
-
-  vlistptr1 = vlist_to_pointer(vlistID1);
 
-  attsp1 = get_attsp(vlistptr1, varID_1);
+  cdi_atts_t *attsp1 = cdi_get_attsp(cdiID1, varID1);
   xassert(attsp1 != NULL);
 
-  for ( attid = 0; attid < (int)attsp1->nelems; attid++ )
+  for ( int attid = 0; attid < (int)attsp1->nelems; attid++ )
     {
-      attp = &(attsp1->value[attid]);
-      vlist_def_att(attp->indtype, attp->exdtype, vlistID2, varID_2, attp->name, attp->nelems, attp->xsz, attp->xvalue);
+      cdi_att_t *attp = &(attsp1->value[attid]);
+      cdi_def_att(attp->indtype, attp->exdtype, cdiID2, varID2, attp->name, attp->nelems, attp->xsz, attp->xvalue);
     }
 
-  return (status);
+  return status;
 }
 
 /*
- at Function  vlistDefAttInt
+ at Function  cdiDefAttInt
 @Title     Define an integer attribute
 
- at Prototype int vlistDefAttInt(int vlistID, int varID, const char *name, int type, int len, const int *ip)
+ at Prototype int cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int *ip)
 
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate} or @fref{gridCreate}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
-    @Item  type     External data type (@func{DATATYPE_INT16} or @func{DATATYPE_INT32}).
+    @Item  type     External data type (@func{CDI_DATATYPE_INT16} or @func{CDI_DATATYPE_INT32}).
     @Item  len      Number of values provided for the attribute.
     @Item  ip       Pointer to one or more integer values.
 
 @Description
-The function @func{vlistDefAttInt} defines an integer attribute.
+The function @func{cdiDefAttInt} defines an integer attribute.
 
 @EndFunction
 */
-int vlistDefAttInt(int vlistID, int varID, const char *name, int type, int len, const int *ip)
+int cdiDefAttInt(int cdiID, int varID, const char *name, int type, int len, const int *ip)
 {
-  return vlist_def_att(DATATYPE_INT, type, vlistID, varID, name, (size_t)len, (size_t)len * sizeof (int), ip);
+  return cdi_def_att(CDI_DATATYPE_INT, type, cdiID, varID, name, (size_t)len, (size_t)len * sizeof(int), ip);
 }
 
 /*
- at Function  vlistDefAttFlt
+ at Function  cdiDefAttFlt
 @Title     Define a floating point attribute
 
- at Prototype int vlistDefAttFlt(int vlistID, int varID, const char *name, int type, int len, const double *dp)
+ at Prototype int cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double *dp)
 
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate} or @fref{gridCreate}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
-    @Item  type     External data type (@func{DATATYPE_FLT32} or @func{DATATYPE_FLT64}).
+    @Item  type     External data type (@func{CDI_DATATYPE_FLT32} or @func{CDI_DATATYPE_FLT64}).
     @Item  len      Number of values provided for the attribute.
     @Item  dp       Pointer to one or more floating point values.
 
 @Description
-The function @func{vlistDefAttFlt} defines a floating point attribute.
+The function @func{cdiDefAttFlt} defines a floating point attribute.
 
 @EndFunction
 */
-int vlistDefAttFlt(int vlistID, int varID, const char *name, int type, int len, const double *dp)
+int cdiDefAttFlt(int cdiID, int varID, const char *name, int type, int len, const double *dp)
 {
-  return vlist_def_att(DATATYPE_FLT, type, vlistID, varID, name, (size_t)len, (size_t)len * sizeof (double), dp);
+  return cdi_def_att(CDI_DATATYPE_FLT, type, cdiID, varID, name, (size_t)len, (size_t)len * sizeof(double), dp);
 }
 
 /*
- at Function  vlistDefAttTxt
+ at Function  cdiDefAttTxt
 @Title     Define a text attribute
 
- at Prototype int vlistDefAttTxt(int vlistID, int varID, const char *name, int len, const char *tp)
+ at Prototype int cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp)
 
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate} or @fref{gridCreate}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
     @Item  len      Number of values provided for the attribute.
     @Item  tp       Pointer to one or more character values.
 
 @Description
-The function @func{vlistDefAttTxt} defines a text attribute.
+The function @func{cdiDefAttTxt} defines a text attribute.
 
 @EndFunction
 */
-int vlistDefAttTxt(int vlistID, int varID, const char *name, int len, const char *tp)
+int cdiDefAttTxt(int cdiID, int varID, const char *name, int len, const char *tp)
 {
-  return vlist_def_att(DATATYPE_TXT, DATATYPE_TXT, vlistID, varID, name, (size_t)len, (size_t)len, tp);
+  return cdi_def_att(CDI_DATATYPE_TXT, CDI_DATATYPE_TXT, cdiID, varID, name, (size_t)len, (size_t)len, tp);
 }
 
 /*
- at Function  vlistInqAttInt
+ at Function  cdiInqAttInt
 @Title     Get the value(s) of an integer attribute
 
- at Prototype int vlistInqAttInt(int vlistID, int varID, const char *name, int mlen, int *ip)
+ at Prototype int cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int *ip)
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
     @Item  mlen     Number of allocated values provided for the attribute.
     @Item  ip       Pointer location for returned integer attribute value(s).
 
 @Description
-The function @func{vlistInqAttInt} gets the values(s) of an integer attribute.
+The function @func{cdiInqAttInt} gets the values(s) of an integer attribute.
 
 @EndFunction
 */
-int vlistInqAttInt(int vlistID, int varID, const char *name, int mlen, int *ip)
+int cdiInqAttInt(int cdiID, int varID, const char *name, int mlen, int *ip)
 {
-  return vlist_inq_att(DATATYPE_INT, vlistID, varID, name, (size_t)mlen * sizeof (int), ip);
+  return cdi_inq_att(CDI_DATATYPE_INT, cdiID, varID, name, (size_t)mlen * sizeof(int), ip);
 }
 
 /*
- at Function  vlistInqAttFlt
+ at Function  cdiInqAttFlt
 @Title     Get the value(s) of a floating point attribute
 
- at Prototype int vlistInqAttFlt(int vlistID, int varID, const char *name, int mlen, double *dp)
+ at Prototype int cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double *dp)
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
     @Item  mlen     Number of allocated values provided for the attribute.
     @Item  dp       Pointer location for returned floating point attribute value(s).
 
 @Description
-The function @func{vlistInqAttFlt} gets the values(s) of a floating point attribute.
+The function @func{cdiInqAttFlt} gets the values(s) of a floating point attribute.
 
 @EndFunction
 */
-int vlistInqAttFlt(int vlistID, int varID, const char *name, int mlen, double *dp)
+int cdiInqAttFlt(int cdiID, int varID, const char *name, int mlen, double *dp)
 {
-  return vlist_inq_att(DATATYPE_FLT, vlistID, varID, name, (size_t)mlen * sizeof (double), dp);
+  return cdi_inq_att(CDI_DATATYPE_FLT, cdiID, varID, name, (size_t)mlen * sizeof(double), dp);
 }
 
 /*
- at Function  vlistInqAttTxt
+ at Function  cdiInqAttTxt
 @Title     Get the value(s) of a text attribute
 
- at Prototype int vlistInqAttTxt(int vlistID, int varID, const char *name, int mlen, char *tp)
+ at Prototype int cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp)
 @Parameter
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate} or @fref{streamInqVlist}.
+    @Item  cdiID    CDI ID, from a previous call to @fref{vlistCreate}, @fref{gridCreate} or @fref{streamInqVlist}.
     @Item  varID    Variable identifier, or @func{CDI_GLOBAL} for a global attribute.
     @Item  name     Attribute name.
     @Item  mlen     Number of allocated values provided for the attribute.
     @Item  tp       Pointer location for returned text attribute value(s).
 
 @Description
-The function @func{vlistInqAttTxt} gets the values(s) of a text attribute.
+The function @func{cdiInqAttTxt} gets the values(s) of a text attribute.
 
 @EndFunction
 */
-int vlistInqAttTxt(int vlistID, int varID, const char *name, int mlen, char *tp)
+int cdiInqAttTxt(int cdiID, int varID, const char *name, int mlen, char *tp)
 {
-  return vlist_inq_att(DATATYPE_TXT, vlistID, varID, name, (size_t)mlen * sizeof (char), tp);
+  return cdi_inq_att(CDI_DATATYPE_TXT, cdiID, varID, name, (size_t)mlen * sizeof(char), tp);
 }
 
 enum {
-  vlist_att_nints = 4,          /* namesz, exdtype, indtype, nelems */
+  cdi_att_nints = 4,          /* namesz, exdtype, indtype, nelems */
 };
 
-static inline int
-vlistAttTypeLookup(cdi_att_t *attp)
+static inline
+int cdiAttTypeLookup(cdi_att_t *attp)
 {
   int type;
   switch (attp->indtype)
   {
-  case DATATYPE_FLT:
-    type = DATATYPE_FLT64;
+  case CDI_DATATYPE_FLT:
+    type = CDI_DATATYPE_FLT64;
     break;
-  case DATATYPE_INT:
-  case DATATYPE_TXT:
+  case CDI_DATATYPE_INT:
+  case CDI_DATATYPE_TXT:
     type = attp->indtype;
     break;
   default:
@@ -65880,8 +65757,7 @@ vlistAttTypeLookup(cdi_att_t *attp)
 }
 
 
-int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB,
-                      int attnum)
+int cdi_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum)
 {
   cdi_atts_t *attspa = get_attsp(a, varIDA),
     *attspb = get_attsp(b, varIDB);
@@ -65905,8 +65781,8 @@ int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB,
 }
 
 
-static int
-vlistAttGetSize(vlist_t *vlistptr, int varID, int attnum, void *context)
+static
+int cdiAttGetSize(vlist_t *vlistptr, int varID, int attnum, void *context)
 {
   cdi_atts_t *attsp;
   cdi_att_t *attp;
@@ -65914,30 +65790,31 @@ vlistAttGetSize(vlist_t *vlistptr, int varID, int attnum, void *context)
   xassert(attsp = get_attsp(vlistptr, varID));
   xassert(attnum >= 0 && attnum < (int)attsp->nelems);
   attp = &(attsp->value[attnum]);
-  int txsize = serializeGetSize(vlist_att_nints, DATATYPE_INT, context)
-    + serializeGetSize((int)attp->namesz, DATATYPE_TXT, context);
-  txsize += serializeGetSize((int)attp->nelems, vlistAttTypeLookup(attp), context);
+  int txsize = serializeGetSize(cdi_att_nints, CDI_DATATYPE_INT, context)
+    + serializeGetSize((int)attp->namesz, CDI_DATATYPE_TXT, context);
+  txsize += serializeGetSize((int)attp->nelems, cdiAttTypeLookup(attp), context);
   return txsize;
 }
 
-int
-vlistAttsGetSize(vlist_t *p, int varID, void *context)
+
+int cdiAttsGetSize(void *vp, int varID, void *context)
 {
+  vlist_t *p = (vlist_t*) vp;
   cdi_atts_t *attsp = get_attsp(p, varID);
-  int txsize = serializeGetSize(1, DATATYPE_INT, context);
+  int txsize = serializeGetSize(1, CDI_DATATYPE_INT, context);
   size_t numAtts = attsp->nelems;
   for (size_t i = 0; i < numAtts; ++i)
-    txsize += vlistAttGetSize(p, varID, (int)i, context);
+    txsize += cdiAttGetSize(p, varID, (int)i, context);
   return txsize;
 }
 
-static void
-vlistAttPack(vlist_t *vlistptr, int varID, int attnum,
-             void * buf, int size, int *position, void *context)
+static
+void cdiAttPack(vlist_t *vlistptr, int varID, int attnum,
+                void *buf, int size, int *position, void *context)
 {
   cdi_atts_t *attsp;
   cdi_att_t *attp;
-  int tempbuf[vlist_att_nints];
+  int tempbuf[cdi_att_nints];
 
   xassert(attsp = get_attsp(vlistptr, varID));
   xassert(attnum >= 0 && attnum < (int)attsp->nelems);
@@ -65946,50 +65823,49 @@ vlistAttPack(vlist_t *vlistptr, int varID, int attnum,
   tempbuf[1] = attp->exdtype;
   tempbuf[2] = attp->indtype;
   tempbuf[3] = (int)attp->nelems;
-  serializePack(tempbuf, vlist_att_nints, DATATYPE_INT, buf, size, position, context);
-  serializePack(attp->name, (int)attp->namesz, DATATYPE_TXT, buf, size, position, context);
-  serializePack(attp->xvalue, (int)attp->nelems, vlistAttTypeLookup(attp),
+  serializePack(tempbuf, cdi_att_nints, CDI_DATATYPE_INT, buf, size, position, context);
+  serializePack(attp->name, (int)attp->namesz, CDI_DATATYPE_TXT, buf, size, position, context);
+  serializePack(attp->xvalue, (int)attp->nelems, cdiAttTypeLookup(attp),
                 buf, size, position, context);
 }
 
-void
-vlistAttsPack(vlist_t *p, int varID,
-              void * buf, int size, int *position, void *context)
+
+void cdiAttsPack(void *vp, int varID, void *buf, int size, int *position, void *context)
 {
+  vlist_t *p = (vlist_t*) vp;
   cdi_atts_t *attsp = get_attsp(p, varID);
   size_t numAtts = attsp->nelems;
   int numAttsI = (int)numAtts;
   xassert(numAtts <= INT_MAX);
-  serializePack(&numAttsI, 1, DATATYPE_INT, buf, size, position, context);
+  serializePack(&numAttsI, 1, CDI_DATATYPE_INT, buf, size, position, context);
   for (size_t i = 0; i < numAtts; ++i)
-    vlistAttPack(p, varID, (int)i, buf, size, position, context);
+    cdiAttPack(p, varID, (int)i, buf, size, position, context);
 }
 
-static void
-vlistAttUnpack(int vlistID, int varID,
-               void * buf, int size, int *position, void *context)
+static
+void cdiAttUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context)
 {
-  int tempbuf[vlist_att_nints];
+  int tempbuf[cdi_att_nints];
 
   serializeUnpack(buf, size, position,
-                  tempbuf, vlist_att_nints, DATATYPE_INT, context);
+                  tempbuf, cdi_att_nints, CDI_DATATYPE_INT, context);
   char *attName = (char *) Malloc((size_t)tempbuf[0] + 1);
-  serializeUnpack(buf, size, position, attName, tempbuf[0], DATATYPE_TXT, context);
+  serializeUnpack(buf, size, position, attName, tempbuf[0], CDI_DATATYPE_TXT, context);
   attName[tempbuf[0]] = '\0';
   int attVDt;
   size_t elemSize;
   switch (tempbuf[2])
   {
-  case DATATYPE_FLT:
-    attVDt = DATATYPE_FLT64;
+  case CDI_DATATYPE_FLT:
+    attVDt = CDI_DATATYPE_FLT64;
     elemSize = sizeof(double);
     break;
-  case DATATYPE_INT:
-    attVDt = DATATYPE_INT;
+  case CDI_DATATYPE_INT:
+    attVDt = CDI_DATATYPE_INT;
     elemSize = sizeof(int);
     break;
-  case DATATYPE_TXT:
-    attVDt = DATATYPE_TXT;
+  case CDI_DATATYPE_TXT:
+    attVDt = CDI_DATATYPE_TXT;
     elemSize = 1;
     break;
   default:
@@ -65998,22 +65874,19 @@ vlistAttUnpack(int vlistID, int varID,
   }
   void *attData = (void *) Malloc(elemSize * (size_t)tempbuf[3]);
   serializeUnpack(buf, size, position, attData, tempbuf[3], attVDt, context);
-  vlist_def_att(tempbuf[2], tempbuf[1], vlistID, varID, attName,
-                (size_t)tempbuf[3], (size_t)tempbuf[3] * elemSize, attData);
+  cdi_def_att(tempbuf[2], tempbuf[1], cdiID, varID, attName,
+              (size_t)tempbuf[3], (size_t)tempbuf[3] * elemSize, attData);
   Free(attName);
   Free(attData);
 }
 
-void
-vlistAttsUnpack(int vlistID, int varID,
-                void * buf, int size, int *position, void *context)
+
+void cdiAttsUnpack(int cdiID, int varID, void *buf, int size, int *position, void *context)
 {
-  int numAtts, i;
-  serializeUnpack(buf, size, position, &numAtts, 1, DATATYPE_INT, context);
-  for (i = 0; i < numAtts; ++i)
-  {
-    vlistAttUnpack(vlistID, varID, buf, size, position, context);
-  }
+  int numAtts;
+  serializeUnpack(buf, size, position, &numAtts, 1, CDI_DATATYPE_INT, context);
+  for ( int i = 0; i < numAtts; ++i )
+    cdiAttUnpack(cdiID, varID, buf, size, position, context);
 }
 
 /*
@@ -66028,11 +65901,9 @@ vlistAttsUnpack(int vlistID, int varID,
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <limits.h>
-
 
 #if  defined  (HAVE_LIBGRIB_API)
-#  include <grib_api.h>
+#include <grib_api.h>
 #endif
 
 
@@ -66046,6 +65917,7 @@ void vlistvarInitEntry(int vlistID, int varID)
   vlistptr->vars[varID].flag          = 0;
   vlistptr->vars[varID].param         = 0;
   vlistptr->vars[varID].datatype      = CDI_UNDEFID;
+  vlistptr->vars[varID].timetype      = CDI_UNDEFID;
   vlistptr->vars[varID].tsteptype     = TSTEP_INSTANT;
   vlistptr->vars[varID].timave        = 0;
   vlistptr->vars[varID].timaccu       = 0;
@@ -66059,7 +65931,7 @@ void vlistvarInitEntry(int vlistID, int varID)
   vlistptr->vars[varID].instID        = CDI_UNDEFID;
   vlistptr->vars[varID].modelID       = CDI_UNDEFID;
   vlistptr->vars[varID].tableID       = CDI_UNDEFID;
-  vlistptr->vars[varID].missvalused   = FALSE;
+  vlistptr->vars[varID].missvalused   = false;
   vlistptr->vars[varID].missval       = cdiDefaultMissval;
   vlistptr->vars[varID].addoffset     = 0.0;
   vlistptr->vars[varID].scalefactor   = 1.0;
@@ -66069,11 +65941,11 @@ void vlistvarInitEntry(int vlistID, int varID)
   vlistptr->vars[varID].units         = NULL;
   vlistptr->vars[varID].extra         = NULL;
   vlistptr->vars[varID].levinfo       = NULL;
-  vlistptr->vars[varID].comptype      = COMPRESS_NONE;
+  vlistptr->vars[varID].comptype      = CDI_COMPRESS_NONE;
   vlistptr->vars[varID].complevel     = 1;
   vlistptr->vars[varID].atts.nalloc   = MAX_ATTRIBUTES;
   vlistptr->vars[varID].atts.nelems   = 0;
-  vlistptr->vars[varID].lvalidrange   = 0;
+  vlistptr->vars[varID].lvalidrange   = false;
   vlistptr->vars[varID].validrange[0] = VALIDMISS;
   vlistptr->vars[varID].validrange[1] = VALIDMISS;
   vlistptr->vars[varID].ensdata       = NULL;
@@ -66083,18 +65955,13 @@ void vlistvarInitEntry(int vlistID, int varID)
   vlistptr->vars[varID].opt_grib_nentries    = 0;
 }
 
-
-
 static
 int vlistvarNewEntry(int vlistID)
 {
   int varID = 0;
-  int vlistvarSize;
-  var_t *vlistvar;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  vlistvarSize = vlistptr->varsAllocated;
-  vlistvar     = vlistptr->vars;
+  int vlistvarSize = vlistptr->varsAllocated;
+  var_t *vlistvar = vlistptr->vars;
   /*
     Look for a free slot in vlistvar.
     (Create the table the first time through).
@@ -66103,8 +65970,8 @@ int vlistvarNewEntry(int vlistID)
     {
       vlistvarSize = 2;
       vlistvar = (var_t *) Malloc((size_t)vlistvarSize * sizeof (var_t));
-      for (int i = 0; i < vlistvarSize; i++ )
-	vlistvar[i].isUsed = FALSE;
+      for ( int i = 0; i < vlistvarSize; i++ )
+	vlistvar[i].isUsed = false;
     }
   else
     {
@@ -66119,7 +65986,7 @@ int vlistvarNewEntry(int vlistID)
       vlistvar = (var_t *) Realloc(vlistvar,
                                    (size_t)(vlistvarSize *= 2) * sizeof(var_t));
       for ( int i = varID; i < vlistvarSize; i++ )
-	vlistvar[i].isUsed = FALSE;
+	vlistvar[i].isUsed = false;
     }
 
   vlistptr->varsAllocated = vlistvarSize;
@@ -66127,9 +65994,9 @@ int vlistvarNewEntry(int vlistID)
 
   vlistvarInitEntry(vlistID, varID);
 
-  vlistptr->vars[varID].isUsed = TRUE;
+  vlistptr->vars[varID].isUsed = true;
 
-  return (varID);
+  return varID;
 }
 
 void vlistCheckVarID(const char *caller, int vlistID, int varID)
@@ -66147,24 +66014,24 @@ void vlistCheckVarID(const char *caller, int vlistID, int varID)
 }
 
 
-int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int tsteptype, int tilesetID)
+int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int timetype, int tilesetID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   if ( CDI_Debug )
-    Message("gridID = %d  zaxisID = %d  tsteptype = %d", gridID, zaxisID, tsteptype);
+    Message("gridID = %d  zaxisID = %d  timetype = %d", gridID, zaxisID, timetype);
 
   int varID = vlistvarNewEntry(vlistID);
 
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   vlistptr->nvars++;
   vlistptr->vars[varID].gridID    = gridID;
   vlistptr->vars[varID].zaxisID   = zaxisID;
-  vlistptr->vars[varID].tsteptype = tsteptype;
+  vlistptr->vars[varID].timetype = timetype;
   vlistptr->vars[varID].subtypeID = tilesetID;
 
-  if ( tsteptype < 0 )
+  if ( timetype < 0 )
     {
-      Message("Unexpected tstep type %d, set to TSTEP_INSTANT!", tsteptype);
-      vlistptr->vars[varID].tsteptype = TSTEP_INSTANT;
+      Message("Unexpected time type %d, set to TIME_VARYING!", timetype);
+      vlistptr->vars[varID].timetype = TIME_VARYING;
     }
 
   vlistAdd2GridIDs(vlistptr, gridID);
@@ -66173,21 +66040,21 @@ int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int tsteptype, int ti
 
   vlistptr->vars[varID].param = cdiEncodeParam(-(varID + 1), 255, 255);
   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
-  return (varID);
+
+  return varID;
 }
 
 /*
 @Function  vlistDefVar
 @Title     Define a Variable
 
- at Prototype int vlistDefVar(int vlistID, int gridID, int zaxisID, int tsteptype)
+ at Prototype int vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype)
 @Parameter
     @Item  vlistID   Variable list ID, from a previous call to @fref{vlistCreate}.
     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
     @Item  zaxisID   Z-axis ID, from a previous call to @fref{zaxisCreate}.
-    @Item  tsteptype One of the set of predefined CDI timestep types.
-                     The valid CDI timestep types are @func{TSTEP_CONSTANT}, @func{TSTEP_INSTANT},
-                     @func{TSTEP_ACCUM}, @func{TSTEP_AVG}, @func{TSTEP_MAX}, @func{TSTEP_MIN} and @func{TSTEP_SD}.
+    @Item  timetype  One of the set of predefined CDI timestep types.
+                     The valid CDI timestep types are @func{TIME_CONSTANT} and @func{TIME_VARYING}.
 
 @Description
 The function @func{vlistDefVar} adds a new variable to vlistID.
@@ -66204,7 +66071,7 @@ and add a variable with @func{vlistDefVar}.
 int vlistID, varID;
    ...
 vlistID = vlistCreate();
-varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_INSTANT);
+varID = vlistDefVar(vlistID, gridID, zaxisID, TIME_VARYING);
    ...
 streamDefVlist(streamID, vlistID);
    ...
@@ -66213,10 +66080,10 @@ vlistDestroy(vlistID);
 @EndSource
 @EndFunction
 */
-int vlistDefVar(int vlistID, int gridID, int zaxisID, int tsteptype)
+int vlistDefVar(int vlistID, int gridID, int zaxisID, int timetype)
 {
   /* call "vlistDefVarTiles" with a trivial tile index: */
-  return vlistDefVarTiles(vlistID, gridID, zaxisID, tsteptype, CDI_UNDEFID);
+  return vlistDefVarTiles(vlistID, gridID, zaxisID, timetype, CDI_UNDEFID);
 }
 
 void
@@ -66295,15 +66162,15 @@ void vlistDefVarCode(int vlistID, int varID, int code)
 }
 
 
-void vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *tsteptype)
+void vlistInqVar(int vlistID, int varID, int *gridID, int *zaxisID, int *timetype)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  *gridID    = vlistptr->vars[varID].gridID;
-  *zaxisID   = vlistptr->vars[varID].zaxisID;
-  *tsteptype = vlistptr->vars[varID].tsteptype;
+  *gridID   = vlistptr->vars[varID].gridID;
+  *zaxisID  = vlistptr->vars[varID].zaxisID;
+  *timetype = vlistptr->vars[varID].timetype;
 
   return;
 }
@@ -66331,7 +66198,7 @@ int vlistInqVarGrid(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].gridID);
+  return vlistptr->vars[varID].gridID;
 }
 
 /*
@@ -66357,7 +66224,7 @@ int vlistInqVarZaxis(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].zaxisID);
+  return vlistptr->vars[varID].zaxisID;
 }
 
 
@@ -66378,7 +66245,8 @@ int vlistInqVarSubtype(int vlistID, int varID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   vlistCheckVarID(__func__, vlistID, varID);
-  return (vlistptr->vars[varID].subtypeID);
+
+  return vlistptr->vars[varID].subtypeID;
 }
 
 
@@ -66405,7 +66273,7 @@ int vlistInqVarParam(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].param);
+  return vlistptr->vars[varID].param;
 }
 
 /*
@@ -66442,7 +66310,7 @@ int vlistInqVarCode(int vlistID, int varID)
       tableInqParCode(vlistptr->vars[varID].tableID, vlistptr->vars[varID].name, &code);
     }
 
-  return (code);
+  return code;
 }
 
 
@@ -66452,37 +66320,7 @@ const char *vlistInqVarNamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].name);
-}
-
-
-const char *vlistInqVarLongnamePtr(int vlistID, int varID)
-{
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  return (vlistptr->vars[varID].longname);
-}
-
-
-const char *vlistInqVarStdnamePtr(int vlistID, int varID)
-{
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  return (vlistptr->vars[varID].stdname);
-}
-
-
-const char *vlistInqVarUnitsPtr(int vlistID, int varID)
-{
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  vlistCheckVarID(__func__, vlistID, varID);
-
-  return (vlistptr->vars[varID].units);
+  return vlistptr->vars[varID].name;
 }
 
 /*
@@ -66521,8 +66359,9 @@ void vlistInqVarName(int vlistID, int varID, char *name)
 	{
 	  int code = pnum;
 	  int tableID = vlistptr->vars[varID].tableID;
-	  if ( tableInqParName(tableID, code, name) != 0 )
-	    sprintf(name, "var%d", code);
+          name[0] = 0;
+          tableInqEntry(tableID, code, -1, name, NULL, NULL);
+	  if ( !name[0] ) sprintf(name, "var%d", code);
 	}
       else
 	{
@@ -66558,24 +66397,29 @@ char* vlistCopyVarName(int vlistId, int varId)
   vlistCheckVarID(__func__, vlistId, varId);
 
   //If a name is set in the variable description, use that.
-  const char* name = vlistptr->vars[varId].name;
-  if(name) return strdup(name);
+  {
+    const char* name = vlistptr->vars[varId].name;
+    if (name) return strdup(name);
+  }
 
   //Otherwise we check if we should use the table of parameter descriptions.
   int param = vlistptr->vars[varId].param;
   int discipline, category, number;
   cdiDecodeParam(param, &number, &category, &discipline);
   char *result = NULL;
-  if(discipline == 255)
+  if (discipline == 255)
     {
       int tableId = vlistptr->vars[varId].tableID;
-      if(( name = tableInqParNamePtr(tableId, number) ))
+      char name[CDI_MAX_NAME]; name[0] = 0;
+      tableInqEntry(tableId, number, -1, name, NULL, NULL);
+      if ( name[0] )
         result = strdup(name);
-      {
-        //No luck, fall back to outputting a name of the format "var<num>".
-        result = (char *) Malloc(3 + 3 * sizeof (int) * CHAR_BIT / 8 + 2);
-        sprintf(result, "var%d", number);
-      }
+      else
+        {
+          //No luck, fall back to outputting a name of the format "var<num>".
+          result = (char *) Malloc(3 + 3 * sizeof (int) * CHAR_BIT / 8 + 2);
+          sprintf(result, "var%d", number);
+        }
     }
   else
     {
@@ -66624,8 +66468,7 @@ void vlistInqVarLongname(int vlistID, int varID, char *longname)
 	{
 	  int code = pnum;
           int tableID = vlistptr->vars[varID].tableID;
-	  if ( tableInqParLongname(tableID, code, longname) != 0 )
-	    longname[0] = '\0';
+          tableInqEntry(tableID, code, -1, NULL, longname, NULL);
 	}
     }
   else
@@ -66709,8 +66552,7 @@ void vlistInqVarUnits(int vlistID, int varID, char *units)
 	{
 	  int code = pnum;
 	  int tableID = vlistptr->vars[varID].tableID;
-	  if ( tableInqParUnits(tableID, code, units) != 0 )
-	    units[0] = '\0';
+          tableInqEntry(tableID, code, -1, NULL, NULL, units);
 	}
     }
   else
@@ -66729,28 +66571,27 @@ int vlistInqVarID(int vlistID, int code)
       int param = vlistptr->vars[varID].param;
       int pdis, pcat, pnum;
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
-      if ( pnum == code ) return (varID);
+      if ( pnum == code ) return varID;
     }
 
-  return (CDI_UNDEFID);
+  return CDI_UNDEFID;
 }
 
 
-int vlistInqVarSize(int vlistID, int varID)
+size_t vlistInqVarSize(int vlistID, int varID)
 {
   vlistCheckVarID(__func__, vlistID, varID);
 
-  int zaxisID, gridID;
-  int tsteptype;
-  vlistInqVar(vlistID, varID, &gridID, &zaxisID, &tsteptype);
+  int zaxisID, gridID, timetype;
+  vlistInqVar(vlistID, varID, &gridID, &zaxisID, &timetype);
 
-  int nlevs = zaxisInqSize(zaxisID);
+  size_t nlevs = (size_t)zaxisInqSize(zaxisID);
 
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
-  int size = gridsize*nlevs;
+  size_t size = gridsize*nlevs;
 
-  return (size);
+  return size;
 }
 
 /*
@@ -66767,9 +66608,9 @@ The function @func{vlistInqVarDatatype} returns the data type of a variable.
 
 @Result
 @func{vlistInqVarDatatype} returns an identifier to the data type of the variable.
-The valid CDI data types are @func{DATATYPE_PACK8}, @func{DATATYPE_PACK16}, @func{DATATYPE_PACK24},
- at func{DATATYPE_FLT32}, @func{DATATYPE_FLT64}, @func{DATATYPE_INT8}, @func{DATATYPE_INT16} and 
- at func{DATATYPE_INT32}.
+The valid CDI data types are @func{CDI_DATATYPE_PACK8}, @func{CDI_DATATYPE_PACK16}, @func{CDI_DATATYPE_PACK24},
+ at func{CDI_DATATYPE_FLT32}, @func{CDI_DATATYPE_FLT64}, @func{CDI_DATATYPE_INT8}, @func{CDI_DATATYPE_INT16} and 
+ at func{CDI_DATATYPE_INT32}.
 
 @EndFunction
 */
@@ -66779,7 +66620,7 @@ int vlistInqVarDatatype(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].datatype);
+  return vlistptr->vars[varID].datatype;
 }
 
 
@@ -66790,11 +66631,11 @@ int vlistInqVarNumber(int vlistID, int varID)
   vlistCheckVarID(__func__, vlistID, varID);
 
   int number = CDI_REAL;
-  if ( vlistptr->vars[varID].datatype == DATATYPE_CPX32 ||
-       vlistptr->vars[varID].datatype == DATATYPE_CPX64 )
+  if ( vlistptr->vars[varID].datatype == CDI_DATATYPE_CPX32 ||
+       vlistptr->vars[varID].datatype == CDI_DATATYPE_CPX64 )
     number = CDI_COMP;
 
-  return (number);
+  return number;
 }
 
 /*
@@ -66806,9 +66647,9 @@ int vlistInqVarNumber(int vlistID, int varID)
     @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
     @Item  varID    Variable identifier.
     @Item  datatype The data type identifier.
-                    The valid CDI data types are @func{DATATYPE_PACK8}, @func{DATATYPE_PACK16},
-                    @func{DATATYPE_PACK24}, @func{DATATYPE_FLT32}, @func{DATATYPE_FLT64},
-                    @func{DATATYPE_INT8}, @func{DATATYPE_INT16} and @func{DATATYPE_INT32}.
+                    The valid CDI data types are @func{CDI_DATATYPE_PACK8}, @func{CDI_DATATYPE_PACK16},
+                    @func{CDI_DATATYPE_PACK24}, @func{CDI_DATATYPE_FLT32}, @func{CDI_DATATYPE_FLT64},
+                    @func{CDI_DATATYPE_INT8}, @func{CDI_DATATYPE_INT16} and @func{CDI_DATATYPE_INT32}.
 
 @Description
 The function @func{vlistDefVarDatatype} defines the data type of a variable.
@@ -66825,15 +66666,15 @@ void vlistDefVarDatatype(int vlistID, int varID, int datatype)
     {
       vlistptr->vars[varID].datatype = datatype;
 
-      if ( vlistptr->vars[varID].missvalused == FALSE )
+      if ( !vlistptr->vars[varID].missvalused )
         switch (datatype)
           {
-          case DATATYPE_INT8:   vlistptr->vars[varID].missval = -SCHAR_MAX; break;
-          case DATATYPE_UINT8:  vlistptr->vars[varID].missval =  UCHAR_MAX; break;
-          case DATATYPE_INT16:  vlistptr->vars[varID].missval = -SHRT_MAX;  break;
-          case DATATYPE_UINT16: vlistptr->vars[varID].missval =  USHRT_MAX; break;
-          case DATATYPE_INT32:  vlistptr->vars[varID].missval = -INT_MAX;   break;
-          case DATATYPE_UINT32: vlistptr->vars[varID].missval =  UINT_MAX;  break;
+          case CDI_DATATYPE_INT8:   vlistptr->vars[varID].missval = -SCHAR_MAX; break;
+          case CDI_DATATYPE_UINT8:  vlistptr->vars[varID].missval =  UCHAR_MAX; break;
+          case CDI_DATATYPE_INT16:  vlistptr->vars[varID].missval = -SHRT_MAX;  break;
+          case CDI_DATATYPE_UINT16: vlistptr->vars[varID].missval =  USHRT_MAX; break;
+          case CDI_DATATYPE_INT32:  vlistptr->vars[varID].missval = -INT_MAX;   break;
+          case CDI_DATATYPE_UINT32: vlistptr->vars[varID].missval =  UINT_MAX;  break;
           }
       reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
     }
@@ -66854,7 +66695,7 @@ void vlistDefVarInstitut(int vlistID, int varID, int instID)
 int vlistInqVarInstitut(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].instID);
+  return vlistptr->vars[varID].instID;
 }
 
 
@@ -66872,7 +66713,7 @@ void vlistDefVarModel(int vlistID, int varID, int modelID)
 int vlistInqVarModel(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].modelID);
+  return vlistptr->vars[varID].modelID;
 }
 
 
@@ -66898,7 +66739,7 @@ void vlistDefVarTable(int vlistID, int varID, int tableID)
 int vlistInqVarTable(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].tableID);
+  return vlistptr->vars[varID].tableID;
 }
 
 /*
@@ -67060,7 +66901,7 @@ double vlistInqVarMissval(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].missval);
+  return vlistptr->vars[varID].missval;
 }
 
 /*
@@ -67085,7 +66926,7 @@ void vlistDefVarMissval(int vlistID, int varID, double missval)
   vlistCheckVarID(__func__, vlistID, varID);
 
   vlistptr->vars[varID].missval = missval;
-  vlistptr->vars[varID].missvalused = TRUE;
+  vlistptr->vars[varID].missvalused = true;
 }
 
 /*
@@ -67170,7 +67011,7 @@ int vlistInqVarValidrange(int vlistID, int varID, double *validrange)
       validrange[1] = vlistptr->vars[varID].validrange[1];
     }
 
-  return (vlistptr->vars[varID].lvalidrange);
+  return (int)vlistptr->vars[varID].lvalidrange;
 }
 
 
@@ -67182,7 +67023,7 @@ void vlistDefVarValidrange(int vlistID, int varID, const double *validrange)
 
   vlistptr->vars[varID].validrange[0] = validrange[0];
   vlistptr->vars[varID].validrange[1] = validrange[1];
-  vlistptr->vars[varID].lvalidrange = TRUE;
+  vlistptr->vars[varID].lvalidrange = true;
   reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
 }
 
@@ -67193,7 +67034,7 @@ double vlistInqVarScalefactor(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].scalefactor);
+  return vlistptr->vars[varID].scalefactor;
 }
 
 
@@ -67203,7 +67044,7 @@ double vlistInqVarAddoffset(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].addoffset);
+  return vlistptr->vars[varID].addoffset;
 }
 
 
@@ -67235,6 +67076,24 @@ void vlistDefVarAddoffset(int vlistID, int varID, double addoffset)
 }
 
 
+void vlistDefVarTimetype(int vlistID, int varID, int timetype)
+{
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  if (vlistptr->vars[varID].timetype != timetype)
+    {
+      vlistptr->vars[varID].timetype = timetype;
+      reshSetStatus(vlistID, &vlistOps, RESH_DESYNC_IN_USE);
+    }
+}
+
+
+int vlistInqVarTimetype(int vlistID, int varID)
+{
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  return vlistptr->vars[varID].timetype;
+}
+
+
 void vlistDefVarTsteptype(int vlistID, int varID, int tsteptype)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
@@ -67260,7 +67119,7 @@ The function @func{vlistInqVarTsteptype} returns the timestep type of a Variable
 @Result
 @func{vlistInqVarTsteptype} returns the timestep type of the Variable,
 one of the set of predefined CDI timestep types.
-The valid CDI timestep types are @func{TSTEP_CONSTANT}, @func{TSTEP_INSTANT},
+The valid CDI timestep types are @func{TSTEP_INSTANT},
 @func{TSTEP_ACCUM}, @func{TSTEP_AVG}, @func{TSTEP_MAX}, @func{TSTEP_MIN} and @func{TSTEP_SD}.
 
 @EndFunction
@@ -67268,7 +67127,7 @@ The valid CDI timestep types are @func{TSTEP_CONSTANT}, @func{TSTEP_INSTANT},
 int vlistInqVarTsteptype(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].tsteptype);
+  return vlistptr->vars[varID].tsteptype;
 }
 
 
@@ -67286,7 +67145,7 @@ void vlistDefVarTimave(int vlistID, int varID, int timave)
 int vlistInqVarTimave(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].timave);
+  return vlistptr->vars[varID].timave;
 }
 
 
@@ -67304,7 +67163,7 @@ void vlistDefVarTimaccu(int vlistID, int varID, int timaccu)
 int vlistInqVarTimaccu(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].timaccu);
+  return vlistptr->vars[varID].timaccu;
 }
 
 
@@ -67322,7 +67181,7 @@ void vlistDefVarTypeOfGeneratingProcess(int vlistID, int varID, int typeOfGenera
 int vlistInqVarTypeOfGeneratingProcess(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].typeOfGeneratingProcess);
+  return vlistptr->vars[varID].typeOfGeneratingProcess;
 }
 
 
@@ -67341,8 +67200,7 @@ void vlistDefVarProductDefinitionTemplate(int vlistID, int varID, int productDef
 int vlistInqVarProductDefinitionTemplate(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-
-  return (vlistptr->vars[varID].productDefinitionTemplate);
+  return vlistptr->vars[varID].productDefinitionTemplate;
 }
 
 
@@ -67400,7 +67258,7 @@ void vlistDestroyVarUnits(int vlistID, int varID)
 int vlistInqVarMissvalUsed(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].missvalused);
+  return (int)vlistptr->vars[varID].missvalused;
 }
 
 
@@ -67439,7 +67297,7 @@ int vlistInqFlag(int vlistID, int varID, int levID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   if (vlistptr->vars[varID].levinfo)
-    return (vlistptr->vars[varID].levinfo[levID].flag);
+    return vlistptr->vars[varID].levinfo[levID].flag;
   else
     {
       levinfo_t li = DEFAULT_LEVINFO(levID);
@@ -67464,7 +67322,7 @@ int vlistFindVar(int vlistID, int fvarID)
       Message("varID not found for fvarID %d in vlistID %d!", fvarID, vlistID);
     }
 
-  return (varID);
+  return varID;
 }
 
 
@@ -67491,14 +67349,14 @@ int vlistFindLevel(int vlistID, int fvarID, int flevelID)
 	}
     }
 
-  return (levelID);
+  return levelID;
 }
 
 
 int vlistMergedVar(int vlistID, int varID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
-  return (vlistptr->vars[varID].mvarID);
+  return vlistptr->vars[varID].mvarID;
 }
 
 
@@ -67537,7 +67395,7 @@ int vlistInqIndex(int vlistID, int varID, int levelID)
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   if (vlistptr->vars[varID].levinfo)
-    return (vlistptr->vars[varID].levinfo[levelID].index);
+    return vlistptr->vars[varID].levinfo[levelID].index;
   else
     {
       levinfo_t li = DEFAULT_LEVINFO(levelID);
@@ -67626,7 +67484,7 @@ int vlistInqVarCompType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].comptype);
+  return vlistptr->vars[varID].comptype;
 }
 
 
@@ -67650,7 +67508,7 @@ int vlistInqVarCompLevel(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].complevel);
+  return vlistptr->vars[varID].complevel;
 }
 
 
@@ -67674,7 +67532,7 @@ int vlistInqVarChunkType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].chunktype);
+  return vlistptr->vars[varID].chunktype;
 }
 
 static
@@ -67735,9 +67593,7 @@ void  vlistDefVarXYZ(int vlistID, int varID, int xyz)
 
 void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3])
 {
-  vlist_t *vlistptr;
-
-  vlistptr = vlist_to_pointer(vlistID);
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   vlistCheckVarID(__func__, vlistID, varID);
 
@@ -67751,7 +67607,7 @@ int vlistInqVarXYZ(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].xyz);
+  return vlistptr->vars[varID].xyz;
 }
 
 /* Ensemble Info Routines */
@@ -67788,7 +67644,7 @@ int vlistInqVarEnsemble( int vlistID, int varID, int *ensID, int *ensCount, int
       status = 1;
     }
 
-  return (status);
+  return status;
 }
 
 
@@ -67813,7 +67669,7 @@ void vlistDefVarIntKey(int vlistID, int varID, const char *name, int value)
   if ( idx < vlistptr->vars[varID].opt_grib_nentries )
     {
       vlistptr->vars[varID].opt_grib_kvpair[idx].int_val = value;
-      vlistptr->vars[varID].opt_grib_kvpair[idx].update  = TRUE;
+      vlistptr->vars[varID].opt_grib_kvpair[idx].update  = true;
     }
   else
     {
@@ -67822,7 +67678,7 @@ void vlistDefVarIntKey(int vlistID, int varID, const char *name, int value)
       idx = vlistptr->vars[varID].opt_grib_nentries -1;
       vlistptr->vars[varID].opt_grib_kvpair[idx].data_type   = t_int;
       vlistptr->vars[varID].opt_grib_kvpair[idx].int_val     = value;
-      vlistptr->vars[varID].opt_grib_kvpair[idx].update      = TRUE;
+      vlistptr->vars[varID].opt_grib_kvpair[idx].update      = true;
       if ( name )
         vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = strdupx(name);
       else
@@ -67876,7 +67732,7 @@ void vlistDefVarDblKey(int vlistID, int varID, const char *name, double value)
   if ( idx < vlistptr->vars[varID].opt_grib_nentries )
     {
       vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val = value;
-      vlistptr->vars[varID].opt_grib_kvpair[idx].update  = TRUE;
+      vlistptr->vars[varID].opt_grib_kvpair[idx].update  = true;
     }
   else
     {
@@ -67885,7 +67741,7 @@ void vlistDefVarDblKey(int vlistID, int varID, const char *name, double value)
       idx = vlistptr->vars[varID].opt_grib_nentries - 1;
       vlistptr->vars[varID].opt_grib_kvpair[idx].data_type = t_double;
       vlistptr->vars[varID].opt_grib_kvpair[idx].dbl_val   = value;
-      vlistptr->vars[varID].opt_grib_kvpair[idx].update    = TRUE;
+      vlistptr->vars[varID].opt_grib_kvpair[idx].update    = true;
       if ( name )
         vlistptr->vars[varID].opt_grib_kvpair[idx].keyword = strdupx(name);
       else
@@ -68018,7 +67874,7 @@ int vlistInqVarIntKey(int vlistID, int varID, const char* name)
 
 void vlistDefVarIOrank(int vlistID, int varID, int iorank)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID );
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   vlistCheckVarID ( __func__, vlistID, varID );
 
@@ -68052,7 +67908,7 @@ int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
 #define FCMP2(f) (namespaceResHDecode(pva->f).idx       \
                   != namespaceResHDecode(pvb->f).idx)
   int diff = FCMP(fvarID) | FCMP(mvarID) | FCMP(flag) | FCMP(param)
-    | FCMP(datatype) | FCMP(tsteptype) | FCMP(timave) | FCMP(timaccu)
+    | FCMP(datatype) | FCMP(timetype) | FCMP(tsteptype) | FCMP(timave) | FCMP(timaccu)
     | FCMP(chunktype) | FCMP(xyz) | FCMP2(gridID) | FCMP2(zaxisID)
     | FCMP2(instID) | FCMP2(modelID) | FCMP2(tableID) | FCMP(missvalused)
     | FCMPFLT(missval) | FCMPFLT(addoffset) | FCMPFLT(scalefactor) | FCMPSTR(name)
@@ -68078,7 +67934,7 @@ int vlistVarCompare(vlist_t *a, int varIDA, vlist_t *b, int varIDB)
   if (natts != b->vars[varIDB].atts.nelems)
     return 1;
   for (size_t attID = 0; attID < natts; ++attID)
-    diff |= vlist_att_compare(a, varIDA, b, varIDB, (int)attID);
+    diff |= cdi_att_compare(a, varIDA, b, varIDB, (int)attID);
   if ((diff |= ((pva->ensdata == NULL) ^ (pvb->ensdata == NULL))))
     return 1;
   if (pva->ensdata)
@@ -68096,21 +67952,21 @@ enum {
 int vlistVarGetPackSize(vlist_t *p, int varID, void *context)
 {
   var_t *var = p->vars + varID;
-  int varsize = serializeGetSize(vlistvar_nints, DATATYPE_INT, context)
-    + serializeGetSize(vlistvar_ndbls, DATATYPE_FLT64, context);
+  int varsize = serializeGetSize(vlistvar_nints, CDI_DATATYPE_INT, context)
+    + serializeGetSize(vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
   if (var->name)
-    varsize += serializeGetSize((int)strlen(var->name), DATATYPE_TXT, context);
+    varsize += serializeGetSize((int)strlen(var->name), CDI_DATATYPE_TXT, context);
   if (var->longname)
-    varsize += serializeGetSize((int)strlen(var->longname), DATATYPE_TXT, context);
+    varsize += serializeGetSize((int)strlen(var->longname), CDI_DATATYPE_TXT, context);
   if (var->stdname)
-    varsize += serializeGetSize((int)strlen(var->stdname), DATATYPE_TXT, context);
+    varsize += serializeGetSize((int)strlen(var->stdname), CDI_DATATYPE_TXT, context);
   if (var->units)
-    varsize += serializeGetSize((int)strlen(var->units), DATATYPE_TXT, context);
+    varsize += serializeGetSize((int)strlen(var->units), CDI_DATATYPE_TXT, context);
   if (var->extra)
-    varsize += serializeGetSize((int)strlen(var->extra), DATATYPE_TXT, context);
+    varsize += serializeGetSize((int)strlen(var->extra), CDI_DATATYPE_TXT, context);
   varsize += serializeGetSize(4 * zaxisInqSize(var->zaxisID),
-                              DATATYPE_INT, context);
-  varsize += vlistAttsGetSize(p, varID, context);
+                              CDI_DATATYPE_INT, context);
+  varsize += cdiAttsGetSize(p, varID, context);
   return varsize;
 }
 
@@ -68125,7 +67981,7 @@ void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position,
   tempbuf[0] = var->flag;
   tempbuf[1] = var->gridID;
   tempbuf[2] = var->zaxisID;
-  tempbuf[3] = var->tsteptype;
+  tempbuf[3] = var->timetype;
   tempbuf[4] = namesz = var->name?(int)strlen(var->name):0;
   tempbuf[5] = longnamesz = var->longname?(int)strlen(var->longname):0;
   tempbuf[6] = stdnamesz = var->stdname?(int)strlen(var->stdname):0;
@@ -68137,7 +67993,7 @@ void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position,
   tempbuf[12] = var->tableID;
   tempbuf[13] = var->timave;
   tempbuf[14] = var->timaccu;
-  tempbuf[15] = var->missvalused;
+  tempbuf[15] = (int)var->missvalused;
   tempbuf[16] = var->comptype;
   tempbuf[17] = var->complevel;
   int nlevs = var->levinfo ? zaxisInqSize(var->zaxisID) : 0;
@@ -68147,23 +68003,23 @@ void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position,
   dtempbuf[0] = var->missval;
   dtempbuf[1] = var->scalefactor;
   dtempbuf[2] = var->addoffset;
-  serializePack(tempbuf, vlistvar_nints, DATATYPE_INT,
+  serializePack(tempbuf, vlistvar_nints, CDI_DATATYPE_INT,
                 buf, size, position, context);
-  serializePack(dtempbuf, vlistvar_ndbls, DATATYPE_FLT64,
+  serializePack(dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64,
                 buf, size, position, context);
   if (namesz)
-    serializePack(var->name, namesz, DATATYPE_TXT, buf, size, position, context);
+    serializePack(var->name, namesz, CDI_DATATYPE_TXT, buf, size, position, context);
   if (longnamesz)
-    serializePack(var->longname, longnamesz, DATATYPE_TXT,
+    serializePack(var->longname, longnamesz, CDI_DATATYPE_TXT,
                   buf, size, position, context);
   if (stdnamesz)
-    serializePack(var->stdname, stdnamesz, DATATYPE_TXT,
+    serializePack(var->stdname, stdnamesz, CDI_DATATYPE_TXT,
                   buf, size, position, context);
   if (unitssz)
-    serializePack(var->units, unitssz, DATATYPE_TXT,
+    serializePack(var->units, unitssz, CDI_DATATYPE_TXT,
                   buf, size, position, context);
   if (extralen)
-    serializePack(var->extra, extralen, DATATYPE_TXT,
+    serializePack(var->extra, extralen, CDI_DATATYPE_TXT,
                   buf, size, position, context);
   if (nlevs)
     {
@@ -68175,10 +68031,10 @@ void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position,
           levbuf[levID][2] = var->levinfo[levID].mlevelID;
           levbuf[levID][3] = var->levinfo[levID].flevelID;
         }
-      serializePack(levbuf, nlevs * 4, DATATYPE_INT,
+      serializePack(levbuf, nlevs * 4, CDI_DATATYPE_INT,
                     buf, size, position, context);
     }
-  vlistAttsPack(p, varID, buf, size, position, context);
+  cdiAttsPack(p, varID, buf, size, position, context);
 }
 
 static inline int
@@ -68196,9 +68052,9 @@ void vlistVarUnpack(int vlistID, char * buf, int size, int *position,
   char *varname = NULL;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
   serializeUnpack(buf, size, position,
-                  tempbuf, vlistvar_nints, DATATYPE_INT, context);
+                  tempbuf, vlistvar_nints, CDI_DATATYPE_INT, context);
   serializeUnpack(buf, size, position,
-                  dtempbuf, vlistvar_ndbls, DATATYPE_FLT64, context);
+                  dtempbuf, vlistvar_ndbls, CDI_DATATYPE_FLT64, context);
 
   /* ------------------------------------------- */
   /* NOTE: Tile sets  currently not supported!!! */
@@ -68216,35 +68072,35 @@ void vlistVarUnpack(int vlistID, char * buf, int size, int *position,
   if (tempbuf[4])
   {
     serializeUnpack(buf, size, position,
-                    varname, tempbuf[4], DATATYPE_TXT, context);
+                    varname, tempbuf[4], CDI_DATATYPE_TXT, context);
     varname[tempbuf[4]] = '\0';
     vlistDefVarName(vlistID, newvar, varname);
   }
   if (tempbuf[5])
   {
     serializeUnpack(buf, size, position,
-                    varname, tempbuf[5], DATATYPE_TXT, context);
+                    varname, tempbuf[5], CDI_DATATYPE_TXT, context);
     varname[tempbuf[5]] = '\0';
     vlistDefVarLongname(vlistID, newvar, varname);
   }
   if (tempbuf[6])
   {
     serializeUnpack(buf, size, position,
-                    varname, tempbuf[6], DATATYPE_TXT, context);
+                    varname, tempbuf[6], CDI_DATATYPE_TXT, context);
     varname[tempbuf[6]] = '\0';
     vlistDefVarStdname(vlistID, newvar, varname);
   }
   if (tempbuf[7])
   {
     serializeUnpack(buf, size, position,
-                    varname, tempbuf[7], DATATYPE_TXT, context);
+                    varname, tempbuf[7], CDI_DATATYPE_TXT, context);
     varname[tempbuf[7]] = '\0';
     vlistDefVarUnits(vlistID, newvar, varname);
   }
   if (tempbuf[20])
     {
       serializeUnpack(buf, size, position,
-                      varname, tempbuf[20], DATATYPE_TXT, context);
+                      varname, tempbuf[20], CDI_DATATYPE_TXT, context);
       varname[tempbuf[20]] = '\0';
       vlistDefVarExtra(vlistID, newvar, varname);
     }
@@ -68273,7 +68129,7 @@ void vlistVarUnpack(int vlistID, char * buf, int size, int *position,
       int i, flagSetLev = 0;
       cdiVlistCreateVarLevInfo(vlistptr, newvar);
       serializeUnpack(buf, size, position,
-                      levbuf, nlevs * 4, DATATYPE_INT, context);
+                      levbuf, nlevs * 4, CDI_DATATYPE_INT, context);
       for (i = 0; i < nlevs; ++i)
         {
           vlistDefFlag(vlistID, newvar, i, levbuf[i][0]);
@@ -68287,7 +68143,7 @@ void vlistVarUnpack(int vlistID, char * buf, int size, int *position,
       vlistDefFlag(vlistID, newvar, flagSetLev, levbuf[flagSetLev][0]);
     }
   vlistDefVarIOrank(vlistID, newvar, tempbuf[19]);
-  vlistAttsUnpack(vlistID, newvar, buf, size, position, context);
+  cdiAttsUnpack(vlistID, newvar, buf, size, position, context);
 }
 
 
@@ -68322,10 +68178,10 @@ static const struct {
 }
 ZaxistypeEntry[] = {
   { /*  0 */ 0, "sfc",               "surface",                "",               ""},
-  { /*  1 */ 0, "lev",               "generic",                "",               "level"},
+  { /*  1 */ 0, "lev",               "generic",                "",               ""},
   { /*  2 */ 2, "lev",               "hybrid",                 "",               "level"},
   { /*  3 */ 2, "lev",               "hybrid_half",            "",               "level"},
-  { /*  4 */ 2, "lev",               "pressure",               "air_pressure",   "Pa"},
+  { /*  4 */ 2, "plev",              "pressure",               "air_pressure",   "Pa"},
   { /*  5 */ 1, "height",            "height",                 "height",         "m"},
   { /*  6 */ 2, "depth",             "depth_below_sea",        "depth",          "m"},
   { /*  7 */ 2, "depth",             "depth_below_land",       "",               "cm"},
@@ -68347,6 +68203,7 @@ ZaxistypeEntry[] = {
   { /* 23 */ 0, "sedimentbottomtw",  "sediment_bottom_tw",     "",               ""},
   { /* 24 */ 0, "mixlayer",          "mix_layer",              "",               ""},
   { /* 25 */ 0, "height",            "generalized_height",     "height",         ""},
+  { /* 26 */ 0, "character",         "area_type",              "",               ""},
 };
 
 enum {
@@ -68354,35 +68211,6 @@ enum {
 };
 
 
-typedef struct {
-  char     dimname[CDI_MAX_NAME];
-  char     vdimname[CDI_MAX_NAME];
-  char     name[CDI_MAX_NAME];
-  char     longname[CDI_MAX_NAME];
-  char     stdname[CDI_MAX_NAME];
-  char     units[CDI_MAX_NAME];
-  char     psname[CDI_MAX_NAME];
-  double  *vals;
-  double  *lbounds;
-  double  *ubounds;
-  double  *weights;
-  int      self;
-  int      prec;
-  int      scalar;
-  int      type;
-  int      ltype;    /* GRIB level type */
-  int      ltype2;
-  int      size;
-  int      direction;
-  int      vctsize;
-  unsigned positive;
-  double  *vct;
-  int      number;   /* Reference number to a generalized Z-axis */
-  int      nhlev;
-  unsigned char uuid[CDI_UUID_SIZE];
-}
-zaxis_t;
-
 static int    zaxisCompareP    (zaxis_t *z1, zaxis_t *z2);
 static void   zaxisDestroyP    ( void * zaxisptr );
 static void   zaxisPrintP      ( void * zaxisptr, FILE * fp );
@@ -68406,65 +68234,75 @@ const resOps *getZaxisOps(void)
 
 static int  ZAXIS_Debug = 0;   /* If set to 1, debugging */
 
-void zaxisGetTypeDescription(int zaxisType, int* outPositive, const char** outName, const char** outLongName, const char** outStdName, const char** outUnit)
+void zaxisGetTypeDescription(int zaxisType, int *outPositive, const char **outName, const char **outLongName, const char **outStdName, const char **outUnit)
 {
-  if(zaxisType < 0 || zaxisType >= CDI_NumZaxistype)
+  if ( zaxisType < 0 || zaxisType >= CDI_NumZaxistype )
     {
-      if(outPositive) *outPositive = 0;
-      if(outName) *outName = NULL;
-      if(outLongName) *outLongName = NULL;
-      if(outStdName) *outStdName = NULL;
-      if(outUnit) *outUnit = NULL;
+      if (outPositive) *outPositive = 0;
+      if (outName) *outName = NULL;
+      if (outLongName) *outLongName = NULL;
+      if (outStdName) *outStdName = NULL;
+      if (outUnit) *outUnit = NULL;
     }
   else
     {
-      if(outPositive) *outPositive = ZaxistypeEntry[zaxisType].positive;
-      if(outName) *outName = ZaxistypeEntry[zaxisType].name;
-      if(outLongName) *outLongName = ZaxistypeEntry[zaxisType].longname;
-      if(outStdName) *outStdName = ZaxistypeEntry[zaxisType].stdname;
-      if(outUnit) *outUnit = ZaxistypeEntry[zaxisType].units;
+      if (outPositive) *outPositive = ZaxistypeEntry[zaxisType].positive;
+      if (outName) *outName = ZaxistypeEntry[zaxisType].name;
+      if (outLongName && zaxisType != ZAXIS_GENERIC) *outLongName = ZaxistypeEntry[zaxisType].longname;
+      if (outStdName) *outStdName = ZaxistypeEntry[zaxisType].stdname;
+      if (outUnit) *outUnit = ZaxistypeEntry[zaxisType].units;
     }
 }
 
+
+zaxis_t *zaxis_to_pointer(int id)
+{
+  return (zaxis_t *)reshGetVal(id, &zaxisOps);
+}
+
 static
-void zaxisDefaultValue(zaxis_t *zaxisptr)
-{
-  zaxisptr->self        = CDI_UNDEFID;
-  zaxisptr->name[0]     = 0;
-  zaxisptr->longname[0] = 0;
-  zaxisptr->stdname[0]  = 0;
-  zaxisptr->dimname[0]  = 0;
-  zaxisptr->vdimname[0] = 0;
-  zaxisptr->units[0]    = 0;
-  zaxisptr->psname[0]   = 0;
-  zaxisptr->vals        = NULL;
-  zaxisptr->ubounds     = NULL;
-  zaxisptr->lbounds     = NULL;
-  zaxisptr->weights     = NULL;
-  zaxisptr->type        = CDI_UNDEFID;
-  zaxisptr->ltype       = 0;
-  zaxisptr->ltype2      = -1;
-  zaxisptr->positive    = 0;
-  zaxisptr->scalar      = 0;
-  zaxisptr->direction   = 0;
-  zaxisptr->prec        = 0;
-  zaxisptr->size        = 0;
-  zaxisptr->vctsize     = 0;
-  zaxisptr->vct         = NULL;
-  zaxisptr->number      = 0;
-  zaxisptr->nhlev       = 0;
+void zaxis_init(zaxis_t *zaxisptr)
+{
+  zaxisptr->self          = CDI_UNDEFID;
+  zaxisptr->name[0]       = 0;
+  zaxisptr->longname[0]   = 0;
+  zaxisptr->stdname[0]    = 0;
+  zaxisptr->dimname[0]    = 0;
+  zaxisptr->vdimname[0]   = 0;
+  zaxisptr->units[0]      = 0;
+  zaxisptr->psname[0]     = 0;
+  zaxisptr->p0name[0]     = 0;
+  zaxisptr->p0value.defined = false;
+  zaxisptr->vals          = NULL;
+  zaxisptr->cvals         = NULL;
+  zaxisptr->clength       = 0;
+  zaxisptr->ubounds       = NULL;
+  zaxisptr->lbounds       = NULL;
+  zaxisptr->weights       = NULL;
+  zaxisptr->type          = CDI_UNDEFID;
+  zaxisptr->ltype         = 0;
+  zaxisptr->ltype2        = -1;
+  zaxisptr->positive      = 0;
+  zaxisptr->scalar        = 0;
+  zaxisptr->direction     = 0;
+  zaxisptr->datatype      = 0;
+  zaxisptr->size          = 0;
+  zaxisptr->vctsize       = 0;
+  zaxisptr->vct           = NULL;
+  zaxisptr->number        = 0;
+  zaxisptr->nhlev         = 0;
   memset(zaxisptr->uuid, 0, CDI_UUID_SIZE);
+  zaxisptr->atts.nalloc   = MAX_ATTRIBUTES;
+  zaxisptr->atts.nelems   = 0;
 }
 
-
 static
 zaxis_t *zaxisNewEntry(int id)
 {
   zaxis_t *zaxisptr = (zaxis_t *) Malloc(sizeof(zaxis_t));
+  zaxis_init(zaxisptr);
 
-  zaxisDefaultValue ( zaxisptr );
-
-  if (id == CDI_UNDEFID)
+  if ( id == CDI_UNDEFID )
     zaxisptr->self = reshPut(zaxisptr, &zaxisOps);
   else
     {
@@ -68472,27 +68310,17 @@ zaxis_t *zaxisNewEntry(int id)
       reshReplace(id, zaxisptr, &zaxisOps);
     }
 
-  return (zaxisptr);
+  return zaxisptr;
 }
 
-static inline zaxis_t *
-zaxisID2Ptr(int id)
-{
-  return (zaxis_t *)reshGetVal(id, &zaxisOps);
-}
-
-
 static
 void zaxisInit(void)
 {
-  static int zaxisInitialized = 0;
-  char *env;
-
+  static bool zaxisInitialized = false;
   if ( zaxisInitialized ) return;
+  zaxisInitialized = true;
 
-  zaxisInitialized = 1;
-
-  env = getenv("ZAXIS_DEBUG");
+  const char *env = getenv("ZAXIS_DEBUG");
   if ( env ) ZAXIS_Debug = atoi(env);
 }
 
@@ -68504,14 +68332,14 @@ void zaxis_copy(zaxis_t *zaxisptr2, zaxis_t *zaxisptr1)
   zaxisptr2->self = zaxisID2;
 }
 
+
 unsigned cdiZaxisCount(void)
 {
   return reshCountType(&zaxisOps);
 }
 
-
-static int
-zaxisCreate_(int zaxistype, int size, int id)
+static
+int zaxisCreate_(int zaxistype, int size, int id)
 {
   zaxis_t *zaxisptr = zaxisNewEntry(id);
 
@@ -68524,7 +68352,7 @@ zaxisCreate_(int zaxistype, int size, int id)
 
   int zaxisID = zaxisptr->self;
   zaxisDefName(zaxisID, ZaxistypeEntry[zaxistype].name);
-  zaxisDefLongname(zaxisID, ZaxistypeEntry[zaxistype].longname);
+  if ( zaxistype != ZAXIS_GENERIC ) zaxisDefLongname(zaxisID, ZaxistypeEntry[zaxistype].longname);
   zaxisDefUnits(zaxisID, ZaxistypeEntry[zaxistype].units);
 
   if ( *ZaxistypeEntry[zaxistype].stdname )
@@ -68532,16 +68360,9 @@ zaxisCreate_(int zaxistype, int size, int id)
 
   zaxisptr->positive = ZaxistypeEntry[zaxistype].positive;
 
-  double *vals = zaxisptr->vals
-    = (double *) Malloc((size_t)size * sizeof(double));
-
-  for ( int ilev = 0; ilev < size; ilev++ )
-    vals[ilev] = 0.0;
-
   return zaxisID;
 }
 
-
 /*
 @Function  zaxisCreate
 @Title     Create a vertical Z-axis
@@ -68583,21 +68404,27 @@ zaxisDefLevels(zaxisID, levs);
 */
 int zaxisCreate(int zaxistype, int size)
 {
-  if ( CDI_Debug )
-    Message("zaxistype: %d size: %d ", zaxistype, size);
+  if ( CDI_Debug ) Message("zaxistype: %d size: %d ", zaxistype, size);
+
+  zaxisInit();
 
-  zaxisInit ();
   return zaxisCreate_(zaxistype, size, CDI_UNDEFID);
 }
 
-
-static void zaxisDestroyKernel( zaxis_t * zaxisptr )
+static
+void zaxisDestroyKernel( zaxis_t * zaxisptr )
 {
   xassert ( zaxisptr );
 
   int id = zaxisptr->self;
 
   if ( zaxisptr->vals )    Free( zaxisptr->vals );
+  if ( zaxisptr->cvals )
+    {
+      for ( int i=0; i<zaxisptr->size; i++)
+        Free(zaxisptr->cvals[i]);
+      Free( zaxisptr->cvals );
+    }
   if ( zaxisptr->lbounds ) Free( zaxisptr->lbounds );
   if ( zaxisptr->ubounds ) Free( zaxisptr->ubounds );
   if ( zaxisptr->weights ) Free( zaxisptr->weights );
@@ -68620,16 +68447,15 @@ static void zaxisDestroyKernel( zaxis_t * zaxisptr )
 */
 void zaxisDestroy(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  zaxisDestroyKernel ( zaxisptr );
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  zaxisDestroyKernel(zaxisptr);
 }
 
 
 static
-void zaxisDestroyP ( void * zaxisptr )
+void zaxisDestroyP(void *zaxisptr)
 {
-  zaxisDestroyKernel (( zaxis_t * ) zaxisptr );
+  zaxisDestroyKernel((zaxis_t *) zaxisptr);
 }
 
 
@@ -68638,7 +68464,7 @@ const char *zaxisNamePtr(int zaxistype)
   const char *name = (zaxistype >= 0 && zaxistype < CDI_NumZaxistype)
     ? ZaxistypeEntry[zaxistype].longname
     : ZaxistypeEntry[ZAXIS_GENERIC].longname;
-  return (name);
+  return name;
 }
 
 
@@ -68652,36 +68478,44 @@ void zaxisSetString(char *zaxisstrname, const char *name, size_t len)
 {
   if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
   strncpy(zaxisstrname, name, len);
-  zaxisstrname[len - 1] = 0;
+  zaxisstrname[len-1] = 0;
 }
 
 static inline
 void zaxisGetString(char *name, const char *zaxisstrname, size_t len)
 {
-  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
-  strncpy(name, zaxisstrname, len);
-  name[len - 1] = 0;
+  size_t slen = strlen(zaxisstrname)+1;
+  if ( slen > len ) slen = len;
+  if ( slen > CDI_MAX_NAME ) slen = CDI_MAX_NAME;
+  strncpy(name, zaxisstrname, slen);
+  name[slen-1] = 0;
 }
 
 static
-char *zaxis_key_to_string(zaxis_t *zaxisptr, int key)
+void *zaxis_key_to_ptr(zaxis_t *zaxisptr, int key)
 {
-  char *zaxisstring = NULL;
+  void *keyptr = NULL;
 
   switch (key)
     {
-    case CDI_ZAXIS_DIMNAME:  zaxisstring = zaxisptr->dimname; break;
-    case CDI_ZAXIS_VDIMNAME: zaxisstring = zaxisptr->vdimname; break;
+    case CDI_KEY_NAME:      keyptr = (void*)zaxisptr->name; break;
+    case CDI_KEY_LONGNAME:  keyptr = (void*)zaxisptr->longname; break;
+    case CDI_KEY_UNITS:     keyptr = (void*)zaxisptr->units; break;
+    case CDI_KEY_DIMNAME:   keyptr = (void*)zaxisptr->dimname; break;
+    case CDI_KEY_VDIMNAME:  keyptr = (void*)zaxisptr->vdimname; break;
+    case CDI_KEY_PSNAME:    keyptr = (void*)zaxisptr->psname; break;
+    case CDI_KEY_P0NAME:    keyptr = (void*)zaxisptr->p0name; break;
+    case CDI_KEY_P0VALUE:   keyptr = (void*)&zaxisptr->p0value; break;
     }
 
-  return zaxisstring;
+  return keyptr;
 }
 
 /*
- at Function  cdiZaxisDefString
+ at Function  cdiZaxisDefKeyStr
 @Title     Define a CDI Z-axis string value from a key
 
- at Prototype int cdiZaxisDefString(int zaxisID, int key, int size, const char *mesg)
+ at Prototype int cdiZaxisDefKeyStr(int zaxisID, int key, int size, const char *mesg)
 @Parameter
     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
     @Item  key      The key to be searched
@@ -68689,37 +68523,37 @@ char *zaxis_key_to_string(zaxis_t *zaxisptr, int key)
     @Item  mesg     The address of a string where the data will be read
 
 @Description
-The function @func{cdiZaxisDefString} defines a CDI Z-axis string value from a key.
+The function @func{cdiZaxisDefKeyStr} defines a CDI Z-axis string value from a key.
 
 @Result
- at func{cdiZaxisDefString} returns 0 if OK and integer value on error.
+ at func{cdiZaxisDefKeyStr} returns 0 if OK and integer value on error.
 
 @EndFunction
 */
-int cdiZaxisDefString(int zaxisID, int key, int size, const char *mesg)
+int cdiZaxisDefKeyStr(int zaxisID, int key, int size, const char *mesg)
 {
-  if ( size <= 0 || mesg == NULL || *mesg == 0 ) return -1;
+  if ( size < 1 || mesg == NULL ) return -1;
 
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  char *zaxisstring = zaxis_key_to_string(zaxisptr, key);
-  if ( zaxisstring == NULL)
+  char *keyptr = (char*)zaxis_key_to_ptr(zaxisptr, key);
+  if ( keyptr == NULL)
     {
       Warning("CDI zaxis string key %d not supported!", key);
       return -1;
     }
 
-  zaxisSetString(zaxisstring, mesg, (size_t)size);
+  zaxisSetString(keyptr, mesg, (size_t)size);
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
 
   return 0;
 }
 
 /*
- at Function  cdiZaxisInqString
+ at Function  cdiZaxisInqKeyStr
 @Title     Get a CDI Z-axis string value from a key
 
- at Prototype int cdiZaxisInqString(int zaxisID, int key, int size, char *mesg)
+ at Prototype int cdiZaxisInqKeyStr(int zaxisID, int key, int size, char *mesg)
 @Parameter
     @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
     @Item  key      The key to be searched.
@@ -68730,26 +68564,99 @@ int cdiZaxisDefString(int zaxisID, int key, int size, const char *mesg)
                     is given by the predefined constant @func{CDI_MAX_NAME}.
 
 @Description
-The function @func{cdiZaxisInqString} return a CDI Z-axis string value from a key.
+The function @func{cdiZaxisInqKeyStr} return a CDI Z-axis string value from a key.
 
 @Result
- at func{cdiZaxisInqString} returns 0 if OK and integer value on error.
+ at func{cdiZaxisInqKeyStr} returns 0 if OK and integer value on error.
 
 @EndFunction
 */
-int cdiZaxisInqString(int zaxisID, int key, int size, char *mesg)
+int cdiZaxisInqKeyStr(int zaxisID, int key, int size, char *mesg)
 {
-  if ( size <= 0 || mesg == NULL ) return -1;
+  if ( size < 1 || mesg == NULL ) return -1;
 
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  const char *zaxisstring = zaxis_key_to_string(zaxisptr, key);
-  if ( zaxisstring == NULL)
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  const char *keyptr = (const char*)zaxis_key_to_ptr(zaxisptr, key);
+  if ( keyptr == NULL)
     {
       Warning("CDI zaxis string key %d not supported!", key);
       return -1;
     }
 
-  zaxisGetString(mesg, zaxisstring, (size_t)size);
+  zaxisGetString(mesg, keyptr, (size_t)size);
+
+  return 0;
+}
+
+
+/*
+ at Function  cdiZaxisDefKeyFlt
+ at Title     Define a CDI Z-axis floating point value from a key
+
+ at Prototype int cdiZaxisDefKeyFlt(int zaxisID, int key, double value)
+ at Parameter
+    @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
+    @Item  key      The key to be searched
+    @Item  value    A double where the data will be read
+
+ at Description
+The function @func{cdiZaxisDefKeyFlt} defines a CDI Z-axis double value from a key.
+
+ at Result
+ at func{cdiZaxisDefKeyFlt} returns 0 if OK and integer value on error.
+
+ at EndFunction
+*/
+int cdiZaxisDefKeyFlt(int zaxisID, int key, double value)
+{
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+
+  zkey_double_t *keyptr = (zkey_double_t*)zaxis_key_to_ptr(zaxisptr, key);
+  if ( keyptr == NULL)
+    {
+      Warning("CDI zaxis double key %d not supported!", key);
+      return -1;
+    }
+
+  keyptr->value = value;
+  keyptr->defined = true;
+
+  reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+
+  return 0;
+}
+
+/*
+ at Function  cdiZaxisInqKeyFlt
+ at Title     Get a CDI Z-axis floating point value from a key
+
+ at Prototype int cdiZaxisInqKeyFlt(int zaxisID, int key, double *value)
+ at Parameter
+    @Item  zaxisID  Z-axis ID, from a previous call to @fref{zaxisCreate}.
+    @Item  key      The key to be searched.
+    @Item value     The address of a double where the data will be retrieved.
+
+ at Description
+The function @func{cdiZaxisInqKeyFlt} return a CDI Z-axis double value from a key.
+
+ at Result
+ at func{cdiZaxisInqKeyFlt} returns 0 if OK and integer value on error.
+
+ at EndFunction
+*/
+int cdiZaxisInqKeyFlt(int zaxisID, int key, double *value)
+{
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  zkey_double_t *keyptr = (zkey_double_t*)zaxis_key_to_ptr(zaxisptr, key);
+  if ( keyptr == NULL)
+    {
+      Warning("CDI zaxis double key %d not supported!", key);
+      return -1;
+    }
+
+  if ( !keyptr->defined ) return 1;
+
+  *value = keyptr->value;
 
   return 0;
 }
@@ -68770,14 +68677,7 @@ The function @func{zaxisDefName} defines the name of a Z-axis.
 */
 void zaxisDefName(int zaxisID, const char *name)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  if ( name )
-    {
-      strncpy(zaxisptr->name, name, CDI_MAX_NAME - 1);
-      zaxisptr->name[CDI_MAX_NAME - 1] = '\0';
-      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
-    }
+  (void)cdiZaxisDefKeyStr(zaxisID, CDI_KEY_NAME, CDI_MAX_NAME, name);
 }
 
 /*
@@ -68796,14 +68696,7 @@ The function @func{zaxisDefLongname} defines the longname of a Z-axis.
 */
 void zaxisDefLongname(int zaxisID, const char *longname)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  if ( longname )
-    {
-      strncpy(zaxisptr->longname, longname, CDI_MAX_NAME - 1);
-      zaxisptr->longname[CDI_MAX_NAME - 1] = '\0';
-      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
-    }
+  (void)cdiZaxisDefKeyStr(zaxisID, CDI_KEY_LONGNAME, CDI_MAX_NAME, longname);
 }
 
 /*
@@ -68822,27 +68715,7 @@ The function @func{zaxisDefUnits} defines the units of a Z-axis.
 */
 void zaxisDefUnits(int zaxisID, const char *units)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  if ( units )
-    {
-      strncpy(zaxisptr->units, units, CDI_MAX_NAME - 1);
-      zaxisptr->units[CDI_MAX_NAME - 1] = '\0';
-      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
-    }
-}
-
-
-void zaxisDefPsName(int zaxisID, const char *psname)
-{
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  if ( psname )
-    {
-      strncpy(zaxisptr->psname, psname, CDI_MAX_NAME - 1);
-      zaxisptr->name[CDI_MAX_NAME - 1] = '\0';
-      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
-    }
+  (void)cdiZaxisDefKeyStr(zaxisID, CDI_KEY_UNITS, CDI_MAX_NAME, units);
 }
 
 /*
@@ -68866,13 +68739,12 @@ The function @func{zaxisInqName} returns the name of a Z-axis.
 */
 void zaxisInqName(int zaxisID, char *name)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  strcpy(name, zaxisptr->name);
+  (void)cdiZaxisInqKeyStr(zaxisID, CDI_KEY_NAME, CDI_MAX_NAME, name);
 }
 
 const char *zaxisInqNamePtr(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->name;
 }
 
@@ -68897,8 +68769,7 @@ The function @func{zaxisInqLongname} returns the longname of a Z-axis.
 */
 void zaxisInqLongname(int zaxisID, char *longname)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  strcpy(longname, zaxisptr->longname);
+  (void)cdiZaxisInqKeyStr(zaxisID, CDI_KEY_LONGNAME, CDI_MAX_NAME, longname);
 }
 
 /*
@@ -68922,51 +68793,43 @@ The function @func{zaxisInqUnits} returns the units of a Z-axis.
 */
 void zaxisInqUnits(int zaxisID, char *units)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  strcpy(units, zaxisptr->units);
+  (void)cdiZaxisInqKeyStr(zaxisID, CDI_KEY_UNITS, CDI_MAX_NAME, units);
 }
 
 
 void zaxisInqStdname(int zaxisID, char *stdname)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   strcpy(stdname, zaxisptr->stdname);
 }
 
 
-void zaxisInqPsName(int zaxisID, char *psname)
-{
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  strcpy(psname, zaxisptr->psname);
-}
-
-
-void zaxisDefPrec(int zaxisID, int prec)
+void zaxisDefDatatype(int zaxisID, int datatype)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if (zaxisptr->prec != prec)
+  if ( zaxisptr->datatype != datatype )
     {
-      zaxisptr->prec = prec;
+      zaxisptr->datatype = datatype;
       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
     }
 }
 
 
-int zaxisInqPrec(int zaxisID)
+int zaxisInqDatatype(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->prec);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->datatype;
 }
 
 
 void zaxisDefPositive(int zaxisID, int positive)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if (zaxisptr->positive != (unsigned)(positive != 0))
+  if ( zaxisptr->positive != (unsigned)positive )
     {
-      zaxisptr->positive = (unsigned)(positive != 0);
+      zaxisptr->positive = (unsigned)positive;
       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
     }
 }
@@ -68974,14 +68837,14 @@ void zaxisDefPositive(int zaxisID, int positive)
 
 int zaxisInqPositive(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return (int)zaxisptr->positive;
 }
 
 
 void zaxisDefScalar(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   zaxisptr->scalar = 1;
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
@@ -68989,14 +68852,14 @@ void zaxisDefScalar(int zaxisID)
 
 int zaxisInqScalar(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->scalar;
 }
 
 
 void zaxisDefLtype(int zaxisID, int ltype)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if (zaxisptr->ltype != ltype)
     {
@@ -69008,16 +68871,16 @@ void zaxisDefLtype(int zaxisID, int ltype)
 
 int zaxisInqLtype(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->ltype;
 }
 
 
 void zaxisDefLtype2(int zaxisID, int ltype2)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if (zaxisptr->ltype2 != ltype2)
+  if ( zaxisptr->ltype2 != ltype2 )
     {
       zaxisptr->ltype2 = ltype2;
       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
@@ -69027,7 +68890,7 @@ void zaxisDefLtype2(int zaxisID, int ltype2)
 
 int zaxisInqLtype2(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->ltype2;
 }
 
@@ -69047,15 +68910,41 @@ The function @func{zaxisDefLevels} defines the levels of a Z-axis.
 */
 void zaxisDefLevels(int zaxisID, const double *levels)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  size_t size = (size_t)zaxisptr->size;
+
+  if ( levels )
+    {
+      if ( zaxisptr->vals == NULL )
+        zaxisptr->vals = (double*) Malloc(size*sizeof(double));
+
+      double *vals = zaxisptr->vals;
+
+      for ( size_t ilev = 0; ilev < size; ++ilev )
+        vals[ilev] = levels[ilev];
+
+      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+    }
+}
 
+
+void zaxisDefCvals(int zaxisID, const char **cvals, int clen)
+{
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   int size = zaxisptr->size;
 
-  double *vals = zaxisptr->vals;
+  if ( cvals && clen )
+    {
+      zaxisptr->clength = clen;
+      zaxisptr->cvals = (char**) Malloc((size_t)size*sizeof(char *));
 
-  for (int ilev = 0; ilev < size; ilev++ )
-    vals[ilev] = levels[ilev];
-  reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+      for ( int ilev = 0; ilev < size; ++ilev )
+        {
+          zaxisptr->cvals[ilev] = Malloc((size_t)clen*sizeof(char));
+          memcpy(zaxisptr->cvals[ilev],cvals[ilev], (size_t)clen*sizeof(char));
+        }
+      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+    }
 }
 
 /*
@@ -69075,16 +68964,22 @@ The function @func{zaxisDefLevel} defines one level of a Z-axis.
 */
 void zaxisDefLevel(int zaxisID, int levelID, double level)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  if ( levelID >= 0 && levelID < zaxisptr->size )
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  int size = zaxisptr->size;
+
+  if ( zaxisptr->vals == NULL )
+    zaxisptr->vals = (double*) Malloc((size_t)size*sizeof(double));
+
+  if ( levelID >= 0 && levelID < size )
     zaxisptr->vals[levelID] = level;
+
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
 }
 
 
 void zaxisDefNlevRef(int zaxisID, const int nhlev)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   if (zaxisptr->nhlev != nhlev)
     {
       zaxisptr->nhlev = nhlev;
@@ -69095,7 +68990,7 @@ void zaxisDefNlevRef(int zaxisID, const int nhlev)
 
 int zaxisInqNlevRef(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->nhlev;
 }
 
@@ -69115,7 +69010,7 @@ The function @func{zaxisDefNumber} defines the reference number for a generalize
 */
 void zaxisDefNumber(int zaxisID, const int number)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   if (zaxisptr->number != number)
     {
       zaxisptr->number = number;
@@ -69140,7 +69035,7 @@ The function @func{zaxisInqNumber} returns the reference number to a generalized
 */
 int zaxisInqNumber(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->number;
 }
 
@@ -69160,7 +69055,7 @@ The function @func{zaxisDefUUID} defines the UUID for a generalized  Z-axis.
 */
 void zaxisDefUUID(int zaxisID, const unsigned char uuid[CDI_UUID_SIZE])
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   memcpy(zaxisptr->uuid, uuid, CDI_UUID_SIZE);
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
 }
@@ -69183,7 +69078,7 @@ The function @func{zaxisInqUUID} returns the UUID to a generalized Z-axis.
 */
 void zaxisInqUUID(int zaxisID, unsigned char uuid[CDI_UUID_SIZE])
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   memcpy(uuid, zaxisptr->uuid, CDI_UUID_SIZE);
 }
 
@@ -69206,43 +69101,54 @@ The function @func{zaxisInqLevel} returns one level of a Z-axis.
 double zaxisInqLevel(int zaxisID, int levelID)
 {
   double level = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if ( levelID >= 0 && levelID < zaxisptr->size )
+  if ( zaxisptr->vals && levelID >= 0 && levelID < zaxisptr->size )
     level = zaxisptr->vals[levelID];
 
   return level;
 }
 
-double zaxisInqLbound(int zaxisID, int index)
+
+double zaxisInqLbound(int zaxisID, int levelID)
 {
   double level = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if ( zaxisptr->lbounds && ( index >= 0 && index < zaxisptr->size ) )
-      level = zaxisptr->lbounds[index];
+  if ( zaxisptr->lbounds && levelID >= 0 && levelID < zaxisptr->size )
+    level = zaxisptr->lbounds[levelID];
 
   return level;
 }
 
 
-double zaxisInqUbound(int zaxisID, int index)
+double zaxisInqUbound(int zaxisID, int levelID)
 {
   double level = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+
+  if ( zaxisptr->ubounds && levelID >= 0 && levelID < zaxisptr->size )
+    level = zaxisptr->ubounds[levelID];
 
-  if ( zaxisptr->ubounds && ( index >= 0 && index < zaxisptr->size ) )
-    level = zaxisptr->ubounds[index];
   return level;
 }
 
 
 const double *zaxisInqLevelsPtr(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->vals;
 }
 
+
+char **zaxisInqCValsPtr(int zaxisID)
+{
+  char **cvals = NULL;
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  cvals = zaxisptr->cvals;
+  return cvals;
+}
+
 /*
 @Function  zaxisInqLevels
 @Title     Get all levels of a Z-axis
@@ -69260,55 +69166,98 @@ The function @func{zaxisInqLevels} returns all levels of a Z-axis.
 @func{zaxisInqLevels} saves all levels to the parameter @func{levels}.
 @EndFunction
 */
-void zaxisInqLevels(int zaxisID, double *levels)
+int zaxisInqLevels(int zaxisID, double *levels)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  int size = zaxisptr->size;
-  for (int i = 0; i < size; i++ )
-    levels[i] =  zaxisptr->vals[i];
+  int size = 0;
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+
+  if ( zaxisptr->vals )
+    {
+      size = zaxisptr->size;
+
+      if ( levels )
+        for ( int i = 0; i < size; i++ )
+          levels[i] = zaxisptr->vals[i];
+    }
+
+  return size;
+}
+
+int zaxisInqCLen(int zaxisID)
+{
+  int size = 0;
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+
+  if ( zaxisptr->cvals && zaxisptr->clength)
+    size = zaxisptr->clength;
+  return size;
+}
+
+int zaxisInqCVals(int zaxisID, char ***clevels)
+{
+  int size = 0;
+  size_t clen = 0;
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+
+  if ( zaxisptr->cvals )
+    {
+      size = zaxisptr->size;
+      clen = zaxisptr->clength;
+      if ( size && clen )
+        {
+          (*clevels) = Malloc(size*sizeof(char*));
+          for ( int i = 0; i < size; i++ )
+            {
+              (*clevels)[i] = Malloc(clen*sizeof(char));
+              memcpy((*clevels)[i], zaxisptr->cvals[i], clen*sizeof(char));
+            }
+          }
+    }
+
+  return size;
 }
 
 
 int zaxisInqLbounds(int zaxisID, double *lbounds)
 {
   int size = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->lbounds )
     {
       size = zaxisptr->size;
 
       if ( lbounds )
-        for (int i = 0; i < size; i++ )
-          lbounds[i] =  zaxisptr->lbounds[i];
+        for ( int i = 0; i < size; i++ )
+          lbounds[i] = zaxisptr->lbounds[i];
     }
 
-  return (size);
+  return size;
 }
 
 
 int zaxisInqUbounds(int zaxisID, double *ubounds)
 {
   int size = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->ubounds )
     {
       size = zaxisptr->size;
 
       if ( ubounds )
-        for (int i = 0; i < size; i++ )
-          ubounds[i] =  zaxisptr->ubounds[i];
+        for ( int i = 0; i < size; i++ )
+          ubounds[i] = zaxisptr->ubounds[i];
     }
 
-  return (size);
+  return size;
 }
 
 
 int zaxisInqWeights(int zaxisID, double *weights)
 {
   int size = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->weights )
     {
@@ -69316,25 +69265,29 @@ int zaxisInqWeights(int zaxisID, double *weights)
 
       if ( weights )
         for ( int i = 0; i < size; i++ )
-          weights[i] =  zaxisptr->weights[i];
+          weights[i] = zaxisptr->weights[i];
     }
 
-  return (size);
+  return size;
 }
 
 
 int zaxisInqLevelID(int zaxisID, double level)
 {
   int levelID = CDI_UNDEFID;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  int size = zaxisptr->size;
-  for ( int i = 0; i < size; i++ )
-    if ( fabs(level-zaxisptr->vals[i]) < DBL_EPSILON )
-      {
-        levelID = i;
-        break;
-      }
+  if ( zaxisptr->vals )
+    {
+      int size = zaxisptr->size;
+
+      for ( int i = 0; i < size; i++ )
+        if ( fabs(level-zaxisptr->vals[i]) < DBL_EPSILON )
+          {
+            levelID = i;
+            break;
+          }
+    }
 
   return levelID;
 }
@@ -69366,8 +69319,8 @@ The valid CDI Z-axis types are @func{ZAXIS_GENERIC}, @func{ZAXIS_SURFACE},
 */
 int zaxisInqType(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->type);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->type;
 }
 
 /*
@@ -69388,16 +69341,16 @@ The function @func{zaxisInqSize} returns the size of a Z-axis.
 */
 int zaxisInqSize(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->size);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->size;
 }
 
 
 void cdiCheckZaxis(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if ( zaxisInqType(zaxisID) == ZAXIS_GENERIC )
+  if ( zaxisInqType(zaxisID) == ZAXIS_GENERIC && zaxisptr->vals )
     {
       int size = zaxisptr->size;
       if ( size > 1 )
@@ -69431,7 +69384,7 @@ void cdiCheckZaxis(int zaxisID)
 
 void zaxisDefVct(int zaxisID, int size, const double *vct)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->vct == 0 || zaxisptr->vctsize != size )
     {
@@ -69446,28 +69399,28 @@ void zaxisDefVct(int zaxisID, int size, const double *vct)
 
 void zaxisInqVct(int zaxisID, double *vct)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   memcpy(vct, zaxisptr->vct, (size_t)zaxisptr->vctsize * sizeof (double));
 }
 
 
 int zaxisInqVctSize(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->vctsize);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->vctsize;
 }
 
 
 const double *zaxisInqVctPtr(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->vct);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->vct;
 }
 
 
 void zaxisDefLbounds(int zaxisID, const double *lbounds)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   size_t size = (size_t)zaxisptr->size;
 
@@ -69485,7 +69438,7 @@ void zaxisDefLbounds(int zaxisID, const double *lbounds)
 
 void zaxisDefUbounds(int zaxisID, const double *ubounds)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   size_t size = (size_t)zaxisptr->size;
 
@@ -69503,7 +69456,7 @@ void zaxisDefUbounds(int zaxisID, const double *ubounds)
 
 void zaxisDefWeights(int zaxisID, const double *weights)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   size_t size = (size_t)zaxisptr->size;
 
@@ -69521,34 +69474,33 @@ void zaxisDefWeights(int zaxisID, const double *weights)
 
 void zaxisChangeType(int zaxisID, int zaxistype)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   zaxisptr->type = zaxistype;
 }
 
 
 void zaxisResize(int zaxisID, int size)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   xassert(size >= 0);
 
   zaxisptr->size = size;
 
   if ( zaxisptr->vals )
-    zaxisptr->vals = (double *) Realloc(zaxisptr->vals, (size_t)size * sizeof(double));
+    zaxisptr->vals = (double *) Realloc(zaxisptr->vals, (size_t)size*sizeof(double));
 }
 
 
 int zaxisDuplicate(int zaxisID)
 {
-  int zaxisIDnew;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   int zaxistype = zaxisInqType(zaxisID);
   int zaxissize = zaxisInqSize(zaxisID);
 
-  zaxisIDnew = zaxisCreate(zaxistype, zaxissize);
-  zaxis_t *zaxisptrnew = zaxisID2Ptr(zaxisIDnew);
+  int zaxisIDnew = zaxisCreate(zaxistype, zaxissize);
+  zaxis_t *zaxisptrnew = zaxis_to_pointer(zaxisIDnew);
 
   zaxis_copy(zaxisptrnew, zaxisptr);
 
@@ -69556,10 +69508,9 @@ int zaxisDuplicate(int zaxisID)
   strcpy(zaxisptrnew->longname, zaxisptr->longname);
   strcpy(zaxisptrnew->units, zaxisptr->units);
 
-  if ( zaxisptr->vals != NULL )
+  if ( zaxisptr->vals )
     {
       size_t size = (size_t)zaxissize;
-
       zaxisptrnew->vals = (double *) Malloc(size * sizeof (double));
       memcpy(zaxisptrnew->vals, zaxisptr->vals, size * sizeof (double));
     }
@@ -69567,7 +69518,6 @@ int zaxisDuplicate(int zaxisID)
   if ( zaxisptr->lbounds )
     {
       size_t size = (size_t)zaxissize;
-
       zaxisptrnew->lbounds = (double *) Malloc(size * sizeof (double));
       memcpy(zaxisptrnew->lbounds, zaxisptr->lbounds, size * sizeof(double));
     }
@@ -69575,15 +69525,13 @@ int zaxisDuplicate(int zaxisID)
   if ( zaxisptr->ubounds )
     {
       size_t size = (size_t)zaxissize;
-
       zaxisptrnew->ubounds = (double *) Malloc(size * sizeof (double));
       memcpy(zaxisptrnew->ubounds, zaxisptr->ubounds, size * sizeof (double));
     }
 
-  if ( zaxisptr->vct != NULL )
+  if ( zaxisptr->vct )
     {
       size_t size = (size_t)zaxisptr->vctsize;
-
       if ( size )
         {
           zaxisptrnew->vctsize = (int)size;
@@ -69592,55 +69540,71 @@ int zaxisDuplicate(int zaxisID)
         }
     }
 
-  return (zaxisIDnew);
+  return zaxisIDnew;
 }
 
-
-static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
+static
+void zaxisPrintKernel(zaxis_t *zaxisptr, FILE *fp)
 {
-  unsigned char uuid[CDI_UUID_SIZE];
-  int levelID;
-  int nbyte;
-
-  xassert ( zaxisptr );
+  xassert(zaxisptr);
 
   int zaxisID = zaxisptr->self;
-
   int type    = zaxisptr->type;
   int nlevels = zaxisptr->size;
-  int prec    = zaxisptr->prec;
+  int datatype = zaxisptr->datatype;
 
-  int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
+  int dig = (datatype == CDI_DATATYPE_FLT64) ? 15 : 7;
 
+  int nbyte;
   int nbyte0 = 0;
-  fprintf(fp, "#\n");
-  fprintf(fp, "# zaxisID %d\n", index);
-  fprintf(fp, "#\n");
   fprintf(fp, "zaxistype = %s\n", zaxisNamePtr(type));
   fprintf(fp, "size      = %d\n", nlevels);
+  if ( nlevels == 1 )
+    {
+      bool zscalar = (bool)zaxisptr->scalar;
+      if ( zscalar ) fprintf(fp, "scalar    = true\n");
+    }
   if ( zaxisptr->name[0]     ) fprintf(fp, "name      = %s\n", zaxisptr->name);
   if ( zaxisptr->longname[0] ) fprintf(fp, "longname  = %s\n", zaxisptr->longname);
   if ( zaxisptr->units[0]    ) fprintf(fp, "units     = %s\n", zaxisptr->units);
 
-  nbyte0 = fprintf(fp, "levels    = ");
-  nbyte = nbyte0;
-  for ( levelID = 0; levelID < nlevels; levelID++ )
+  if ( zaxisptr->vals )
     {
-      if ( nbyte > 80 )
-	{
-	  fprintf(fp, "\n");
-	  fprintf(fp, "%*s", nbyte0, "");
-	  nbyte = nbyte0;
-	}
-      nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->vals[levelID]);
+      nbyte0 = fprintf(fp, "levels    = ");
+      nbyte = nbyte0;
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
+        {
+          if ( nbyte > 80 )
+            {
+              fprintf(fp, "\n");
+              fprintf(fp, "%*s", nbyte0, "");
+              nbyte = nbyte0;
+            }
+          nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->vals[levelID]);
+        }
+      fprintf(fp, "\n");
+    }
+
+  if ( zaxisptr->cvals )
+    {
+      dig = datatype;
+      nbyte0 = fprintf(fp, "types     = ");
+      nbyte = nbyte0;
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
+        {
+          fprintf(fp, "\n");
+          fprintf(fp, "%*s", nbyte0, "");
+          nbyte = nbyte0;
+          nbyte += fprintf(fp, "%.*s [%d]", dig, zaxisptr->cvals[levelID], levelID+1);
+        }
+      fprintf(fp, "\n");
     }
-  fprintf(fp, "\n");
 
   if ( zaxisptr->lbounds && zaxisptr->ubounds )
     {
       nbyte0 = fprintf(fp, "lbounds   = ");
       nbyte = nbyte0;
-      for ( levelID = 0; levelID < nlevels; levelID++ )
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
 	    {
@@ -69654,7 +69618,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 
       nbyte0 = fprintf(fp, "ubounds   = ");
       nbyte = nbyte0;
-      for ( levelID = 0; levelID < nlevels; levelID++ )
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
 	    {
@@ -69705,6 +69669,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 
   if ( type == ZAXIS_REFERENCE )
     {
+      unsigned char uuid[CDI_UUID_SIZE];
       zaxisInqUUID(zaxisID, uuid);
       if ( *uuid )
         {
@@ -69717,44 +69682,41 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 }
 
 
-void zaxisPrint ( int zaxisID, int index )
+void zaxisPrint(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-
-  zaxisPrintKernel ( zaxisptr, index, stdout );
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  zaxisPrintKernel(zaxisptr, stdout);
 }
 
 
 static
-void zaxisPrintP ( void * voidptr, FILE * fp )
+void zaxisPrintP(void * voidptr, FILE * fp)
 {
   zaxis_t *zaxisptr = ( zaxis_t * ) voidptr;
 
   xassert ( zaxisptr );
 
-  zaxisPrintKernel(zaxisptr, zaxisptr->self, fp);
+  zaxisPrintKernel(zaxisptr, fp);
 }
 
 
-static int
-zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
+static
+int zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
 {
-  enum {
-    differ = 1,
-  };
+  enum { differ = 1 };
   int diff = 0;
   xassert(z1 && z2);
 
   diff |= (z1->type != z2->type)
     | (z1->ltype != z2->ltype)
     | (z1->direction != z2->direction)
-    | (z1->prec != z2->prec)
+    | (z1->datatype != z2->datatype)
     | (z1->size != z2->size)
     | (z1->vctsize != z2->vctsize)
     | (z1->positive != z2->positive);
 
-  if (diff)
-    return differ;
+  if ( diff ) return differ;
+
   int size = z1->size;
   int anyPresent = 0;
   int present = (z1->vals != NULL);
@@ -69763,7 +69725,7 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
   if (!diff && present)
     {
       const double *p = z1->vals, *q = z2->vals;
-      for (int i = 0; i < size; i++)
+      for ( int i = 0; i < size; i++ )
         diff |= IS_NOT_EQUAL(p[i], q[i]);
     }
 
@@ -69773,7 +69735,7 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
   if (!diff && present)
     {
       const double *p = z1->lbounds, *q = z2->lbounds;
-      for (int i = 0; i < size; i++)
+      for ( int i = 0; i < size; i++ )
         diff |= IS_NOT_EQUAL(p[i], q[i]);
     }
 
@@ -69783,7 +69745,7 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
   if (!diff && present)
     {
       const double *p = z1->ubounds, *q = z2->ubounds;
-      for (int i = 0; i < size; ++i)
+      for ( int i = 0; i < size; ++i )
         diff |= IS_NOT_EQUAL(p[i], q[i]);
     }
 
@@ -69793,7 +69755,7 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
   if (!diff && present)
     {
       const double *p = z1->weights, *q = z2->weights;
-      for (int i = 0; i < size; ++i)
+      for ( int i = 0; i < size; ++i )
         diff |= IS_NOT_EQUAL(p[i], q[i]);
     }
 
@@ -69804,7 +69766,7 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
       int vctsize = z1->vctsize;
       xassert(vctsize);
       const double *p = z1->vct, *q = z2->vct;
-      for (int i = 0; i < vctsize; ++i)
+      for ( int i = 0; i < vctsize; ++i )
         diff |= IS_NOT_EQUAL(p[i], q[i]);
     }
 
@@ -69820,8 +69782,8 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
 }
 
 
-static int
-zaxisTxCode ( void )
+static
+int zaxisTxCode(void)
 {
   return ZAXIS;
 }
@@ -69836,10 +69798,10 @@ enum { zaxisNint     = 8,
 };
 
 #define ZAXIS_STR_SERIALIZE { zaxisP->name, zaxisP->longname, \
-      zaxisP->stdname, zaxisP->units }
+                              zaxisP->stdname, zaxisP->units }
 
 static
-int zaxisGetMemberMask ( zaxis_t * zaxisP )
+int zaxisGetMemberMask( zaxis_t * zaxisP )
 {
   int memberMask = 0;
 
@@ -69856,33 +69818,33 @@ static int
 zaxisGetPackSize(void * voidP, void *context)
 {
   zaxis_t * zaxisP = ( zaxis_t * ) voidP;
-  int packBufferSize = serializeGetSize(zaxisNint, DATATYPE_INT, context)
-    + serializeGetSize(1, DATATYPE_UINT32, context);
+  int packBufferSize = serializeGetSize(zaxisNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if (zaxisP->vals || zaxisP->lbounds || zaxisP->ubounds || zaxisP->weights)
     xassert(zaxisP->size);
 
   if ( zaxisP->vals )
-    packBufferSize += serializeGetSize(zaxisP->size, DATATYPE_FLT64, context)
-      + serializeGetSize(1, DATATYPE_UINT32, context);
+    packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
+      + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if ( zaxisP->lbounds )
-    packBufferSize += serializeGetSize(zaxisP->size, DATATYPE_FLT64, context)
-      + serializeGetSize(1, DATATYPE_UINT32, context);
+    packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
+      + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if ( zaxisP->ubounds )
-    packBufferSize += serializeGetSize(zaxisP->size, DATATYPE_FLT64, context)
-      + serializeGetSize(1, DATATYPE_UINT32, context);
+    packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
+      + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if ( zaxisP->weights )
-    packBufferSize += serializeGetSize(zaxisP->size, DATATYPE_FLT64, context)
-      + serializeGetSize(1, DATATYPE_UINT32, context);
+    packBufferSize += serializeGetSize(zaxisP->size, CDI_DATATYPE_FLT64, context)
+      + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if ( zaxisP->vct )
     {
       xassert ( zaxisP->vctsize );
-      packBufferSize += serializeGetSize(zaxisP->vctsize, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      packBufferSize += serializeGetSize(zaxisP->vctsize, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   {
@@ -69892,10 +69854,10 @@ zaxisGetPackSize(void * voidP, void *context)
       += serializeStrTabGetPackSize(strTab, (int)numStr, context);
   }
 
-  packBufferSize += serializeGetSize(1, DATATYPE_UCHAR, context);
+  packBufferSize += serializeGetSize(1, CDI_DATATYPE_UCHAR, context);
 
   if (!cdiUUIDIsNull(zaxisP->uuid))
-    packBufferSize += serializeGetSize(CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+    packBufferSize += serializeGetSize(CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
 
   return packBufferSize;
 }
@@ -69910,11 +69872,11 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
   uint32_t d;
 
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  intBuffer, zaxisNint, DATATYPE_INT, context);
+                  intBuffer, zaxisNint, CDI_DATATYPE_INT, context);
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
+                  &d, 1, CDI_DATATYPE_UINT32, context);
 
-  xassert(cdiCheckSum(DATATYPE_INT, zaxisNint, intBuffer) == d);
+  xassert(cdiCheckSum(CDI_DATATYPE_INT, zaxisNint, intBuffer) == d);
 
   zaxisInit();
 
@@ -69922,7 +69884,7 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
     = zaxisNewEntry(force_id ? namespaceAdaptKey(intBuffer[0], originNamespace)
                     : CDI_UNDEFID);
 
-  zaxisP->prec      = intBuffer[1];
+  zaxisP->datatype  = intBuffer[1];
   zaxisP->type      = intBuffer[2];
   zaxisP->ltype     = intBuffer[3];
   zaxisP->size      = intBuffer[4];
@@ -69937,10 +69899,10 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
 
       zaxisP->vals = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      zaxisP->vals, size, DATATYPE_FLT64, context);
+                      zaxisP->vals, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, zaxisP->vals) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->vals) == d);
     }
 
   if (memberMask & lbounds)
@@ -69950,10 +69912,10 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
 
       zaxisP->lbounds = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      zaxisP->lbounds, size, DATATYPE_FLT64, context);
+                      zaxisP->lbounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, zaxisP->lbounds) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->lbounds) == d);
     }
 
   if (memberMask & ubounds)
@@ -69963,10 +69925,10 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
 
       zaxisP->ubounds = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      zaxisP->ubounds, size, DATATYPE_FLT64, context);
+                      zaxisP->ubounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, zaxisP->ubounds) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->ubounds) == d);
     }
 
   if (memberMask & weights)
@@ -69976,10 +69938,10 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
 
       zaxisP->weights = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      zaxisP->weights, size, DATATYPE_FLT64, context);
+                      zaxisP->weights, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, zaxisP->weights) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, zaxisP->weights) == d);
     }
 
   if ( memberMask & vct )
@@ -69989,10 +69951,10 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
 
       zaxisP->vct = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      zaxisP->vct, size, DATATYPE_FLT64, context);
+                      zaxisP->vct, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT64, size, zaxisP->vct) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT64, size, zaxisP->vct) == d);
     }
 
   {
@@ -70003,11 +69965,11 @@ zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
   }
 
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &zaxisP->positive, 1, DATATYPE_UCHAR, context);
+                  &zaxisP->positive, 1, CDI_DATATYPE_UCHAR, context);
 
   if (memberMask & zaxisHasUUIDFlag)
     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    zaxisP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+                    zaxisP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
 
   reshSetStatus(zaxisP->self, &zaxisOps,
                 reshGetStatus(zaxisP->self, &zaxisOps) & ~RESH_SYNC_BIT);
@@ -70023,7 +69985,7 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
   uint32_t d;
 
   intBuffer[0]  = zaxisP->self;
-  intBuffer[1]  = zaxisP->prec;
+  intBuffer[1]  = zaxisP->datatype;
   intBuffer[2]  = zaxisP->type;
   intBuffer[3]  = zaxisP->ltype;
   intBuffer[4]  = zaxisP->size;
@@ -70031,30 +69993,30 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
   intBuffer[6]  = zaxisP->vctsize;
   intBuffer[7]  = memberMask = zaxisGetMemberMask ( zaxisP );
 
-  serializePack(intBuffer, zaxisNint, DATATYPE_INT,
+  serializePack(intBuffer, zaxisNint, CDI_DATATYPE_INT,
                 packBuffer, packBufferSize, packBufferPos, context);
-  d = cdiCheckSum(DATATYPE_INT, zaxisNint, intBuffer);
-  serializePack(&d, 1, DATATYPE_UINT32,
+  d = cdiCheckSum(CDI_DATATYPE_INT, zaxisNint, intBuffer);
+  serializePack(&d, 1, CDI_DATATYPE_UINT32,
                 packBuffer, packBufferSize, packBufferPos, context);
 
 
   if ( memberMask & vals )
     {
       xassert(zaxisP->size);
-      serializePack(zaxisP->vals, zaxisP->size, DATATYPE_FLT64,
+      serializePack(zaxisP->vals, zaxisP->size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, zaxisP->size, zaxisP->vals );
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->vals );
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
   if (memberMask & lbounds)
     {
       xassert(zaxisP->size);
-      serializePack(zaxisP->lbounds, zaxisP->size, DATATYPE_FLT64,
+      serializePack(zaxisP->lbounds, zaxisP->size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, zaxisP->size, zaxisP->lbounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->lbounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -70062,10 +70024,10 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       xassert(zaxisP->size);
 
-      serializePack(zaxisP->ubounds, zaxisP->size, DATATYPE_FLT64,
+      serializePack(zaxisP->ubounds, zaxisP->size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, zaxisP->size, zaxisP->ubounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->ubounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -70073,10 +70035,10 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       xassert(zaxisP->size);
 
-      serializePack(zaxisP->weights, zaxisP->size, DATATYPE_FLT64,
+      serializePack(zaxisP->weights, zaxisP->size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, zaxisP->size, zaxisP->weights);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, zaxisP->size, zaxisP->weights);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -70084,10 +70046,10 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       xassert(zaxisP->vctsize);
 
-      serializePack(zaxisP->vct, zaxisP->vctsize, DATATYPE_FLT64,
+      serializePack(zaxisP->vct, zaxisP->vctsize, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT64, zaxisP->vctsize, zaxisP->vct);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT64, zaxisP->vctsize, zaxisP->vct);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -70098,11 +70060,11 @@ zaxisPack(void * voidP, void * packBuffer, int packBufferSize,
                         packBuffer, packBufferSize, packBufferPos, context);
   }
 
-  serializePack(&zaxisP->positive, 1, DATATYPE_UCHAR,
+  serializePack(&zaxisP->positive, 1, CDI_DATATYPE_UCHAR,
                 packBuffer, packBufferSize, packBufferPos, context);
 
   if (memberMask & zaxisHasUUIDFlag)
-    serializePack(zaxisP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR,
+    serializePack(zaxisP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR,
                   packBuffer, packBufferSize, packBufferPos, context);
 
 }
@@ -70124,7 +70086,7 @@ void cdiZaxisGetIndexList(unsigned nzaxis, int *zaxisResHs)
  * require-trailing-newline: t
  * End:
  */
-   static const char cdi_libvers[] = "1.7.2" " of " "Jun  7 2016"" " "20:09:57";
+   static const char cdi_libvers[] = "1.9.2" " of " "Nov  6 2017"" " "11:55:15";
 const char *cdiLibraryVersion(void)
 {
   return (cdi_libvers);
@@ -70728,7 +70690,7 @@ if (e>s) {                           /* Need this to handle NULL string.*/
 } return s; }
 
 #ifndef __CF__KnR
-static int num_elem(char *strv, unsigned elem_len, int term_char, int num_term);
+static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term);
 #endif
 /* kill_trailingn(s,t,e) will kill the trailing t's in string s. e normally 
 points to the terminating '\0' of s, but may actually point to anywhere in s.
@@ -70745,8 +70707,7 @@ else if (e>s) {                      /* Watch out for neg. length string.*/
   while (e>s && *--e==t){;}          /* Don't follow t's past beginning. */
   e[*e==t?0:1] = '\0';               /* Handle s[0]=t correctly.       */
 }
-if (0)  /* to prevent not used warnings in gcc (added by TJ) */
-  num_elem("", 0, '\0', 1);
+(void)num_elem;  /* to prevent not used warnings in gcc (added by TJ) */
 
  return s; }
 
@@ -70796,7 +70757,7 @@ typedef DSC$DESCRIPTOR_A(1) fstringvector;
 #define NUM_ELEM_ARG(B) *_2(A,B),_NUM_ELEM_ARG
 #define TERM_CHARS(A,B) A,B
 #ifndef __CF__KnR
-static int num_elem(char *strv, unsigned elem_len, int term_char, int num_term)
+static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term)
 #else
 static int num_elem(      strv,          elem_len,     term_char,     num_term)
                     char *strv; unsigned elem_len; int term_char; int num_term;
@@ -70815,10 +70776,10 @@ for (num=0; ; num++) {
   if (i==(unsigned)num_term) break;
   else strv += elem_len-i;
 }
-if (0) {  /* to prevent not used warnings in gcc (added by ROOT) */
-   c2fstrv(0, 0, 0, 0); f2cstrv(0, 0, 0, 0); kill_trailing(0, 0);
-   vkill_trailing(0, 0, 0, 0); num_elem(0, 0, 0, 0);
-}
+/* to prevent not used warnings in gcc (added by ROOT, changed by TJ
+ * because of unreachable warnings from clang) */
+(void)c2fstrv; (void)f2cstrv; (void)kill_trailing;
+(void)vkill_trailing; (void)num_elem;
 return (int)num;
 }
 /* #endif removed 2/10/98 (CFITSIO) */
@@ -72708,10 +72669,32 @@ string. */
 
 #if defined (HAVE_CF_INTERFACE)
 
+#include <limits.h>
+#include <assert.h>
+
 #if ! defined (__CFORTRAN_LOADED)
+#  if defined __clang__
+#    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wreserved-id-macro"
+#  endif
 #  include "cfortran.h"
+#  if defined __clang__
+#    pragma GCC diagnostic pop
+#  endif
+#endif
+/* These functions are meant to be called from Fortran and don't
+ * need an interface declaration in a C header. */
+#if defined __clang__
+#  pragma GCC diagnostic ignored "-Wmissing-prototypes"
 #endif
 
+static
+int size_t_c2f(size_t value_size_t)
+{
+  assert(value_size_t < INT_MAX);
+  return (int) value_size_t;
+}
+
 
 /*  Byte order  */
 
@@ -72830,28 +72813,105 @@ FCALLSCFUN2 (INT, streamInqTimestep, STREAMINQTIMESTEP, streaminqtimestep, INT,
 FCALLSCFUN1 (INT, streamInqCurTimestepID, STREAMINQCURTIMESTEPID, streaminqcurtimestepid, INT)
 FCALLSCFUN1 (STRING, streamFilename, STREAMFILENAME, streamfilename, INT)
 FCALLSCFUN1 (STRING, streamFilesuffix, STREAMFILESUFFIX, streamfilesuffix, INT)
+static int streamNvals_fwrap(int streamID)
+{
+  size_t v;
+  v = streamNvals(streamID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, streamNvals_fwrap, STREAMNVALS, streamnvals, INT)
 FCALLSCFUN1 (INT, streamInqNvars, STREAMINQNVARS, streaminqnvars, INT)
 
-/*  STREAM var I/O routines  */
+/*  STREAM var I/O routines (random access)  */
 
-FCALLSCSUB4 (streamWriteVar, STREAMWRITEVAR, streamwritevar, INT, INT, DOUBLEV, INT)
-FCALLSCSUB4 (streamWriteVarF, STREAMWRITEVARF, streamwritevarf, INT, INT, FLOATV, INT)
-FCALLSCSUB4 (streamReadVar, STREAMREADVAR, streamreadvar, INT, INT, DOUBLEV, PINT)
-FCALLSCSUB4 (streamReadVarF, STREAMREADVARF, streamreadvarf, INT, INT, FLOATV, PINT)
-FCALLSCSUB5 (streamWriteVarSlice, STREAMWRITEVARSLICE, streamwritevarslice, INT, INT, INT, DOUBLEV, INT)
-FCALLSCSUB5 (streamWriteVarSliceF, STREAMWRITEVARSLICEF, streamwritevarslicef, INT, INT, INT, FLOATV, INT)
-FCALLSCSUB5 (streamReadVarSlice, STREAMREADVARSLICE, streamreadvarslice, INT, INT, INT, DOUBLEV, PINT)
-FCALLSCSUB5 (streamReadVarSliceF, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
-FCALLSCSUB5 (streamWriteVarChunk, STREAMWRITEVARCHUNK, streamwritevarchunk, INT, INT, INTVV, DOUBLEV, INT)
+static void streamWriteVar_fwrap(int streamID, int varID, const double data[], int nmiss)
+{
+  streamWriteVar(streamID, varID, data, (size_t)nmiss);
+}
+FCALLSCSUB4 (streamWriteVar_fwrap, STREAMWRITEVAR, streamwritevar, INT, INT, DOUBLEV, INT)
+static void streamWriteVarF_fwrap(int streamID, int varID, const float data[], int nmiss)
+{
+  streamWriteVarF(streamID, varID, data, (size_t)nmiss);
+}
+FCALLSCSUB4 (streamWriteVarF_fwrap, STREAMWRITEVARF, streamwritevarf, INT, INT, FLOATV, INT)
+static void streamReadVar_fwrap(int streamID, int varID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVar(streamID, varID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB4 (streamReadVar_fwrap, STREAMREADVAR, streamreadvar, INT, INT, DOUBLEV, PINT)
+static void streamReadVarF_fwrap(int streamID, int varID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarF(streamID, varID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB4 (streamReadVarF_fwrap, STREAMREADVARF, streamreadvarf, INT, INT, FLOATV, PINT)
+static void streamWriteVarSlice_fwrap(int streamID, int varID, int levelID, const double data[], int nmiss)
+{
+  streamWriteVarSlice(streamID, varID, levelID, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarSlice_fwrap, STREAMWRITEVARSLICE, streamwritevarslice, INT, INT, INT, DOUBLEV, INT)
+static void streamWriteVarSliceF_fwrap(int streamID, int varID, int levelID, const float data[], int nmiss)
+{
+  streamWriteVarSliceF(streamID, varID, levelID, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarSliceF_fwrap, STREAMWRITEVARSLICEF, streamwritevarslicef, INT, INT, INT, FLOATV, INT)
+static void streamReadVarSlice_fwrap(int streamID, int varID, int levelID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarSlice(streamID, varID, levelID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB5 (streamReadVarSlice_fwrap, STREAMREADVARSLICE, streamreadvarslice, INT, INT, INT, DOUBLEV, PINT)
+static void streamReadVarSliceF_fwrap(int streamID, int varID, int levelID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadVarSliceF(streamID, varID, levelID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB5 (streamReadVarSliceF_fwrap, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
+static void streamWriteVarChunk_fwrap(int streamID, int varID, const int rect[3][2], const double data[], int nmiss)
+{
+  streamWriteVarChunk(streamID, varID, rect, data, (size_t)nmiss);
+}
+FCALLSCSUB5 (streamWriteVarChunk_fwrap, STREAMWRITEVARCHUNK, streamwritevarchunk, INT, INT, INTVV, DOUBLEV, INT)
 
-/*  STREAM record I/O routines  */
+/*  STREAM record I/O routines (sequential access)  */
 
 FCALLSCSUB3 (streamDefRecord, STREAMDEFRECORD, streamdefrecord, INT, INT, INT)
 FCALLSCSUB3 (streamInqRecord, STREAMINQRECORD, streaminqrecord, INT, PINT, PINT)
-FCALLSCSUB3 (streamWriteRecord, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
-FCALLSCSUB3 (streamWriteRecordF, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
-FCALLSCSUB3 (streamReadRecord, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
-FCALLSCSUB3 (streamReadRecordF, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
+static void streamWriteRecord_fwrap(int streamID, const double data[], int nmiss)
+{
+  streamWriteRecord(streamID, data, (size_t)nmiss);
+}
+FCALLSCSUB3 (streamWriteRecord_fwrap, STREAMWRITERECORD, streamwriterecord, INT, DOUBLEV, INT)
+static void streamWriteRecordF_fwrap(int streamID, const float data[], int nmiss)
+{
+  streamWriteRecordF(streamID, data, (size_t)nmiss);
+}
+FCALLSCSUB3 (streamWriteRecordF_fwrap, STREAMWRITERECORDF, streamwriterecordf, INT, FLOATV, INT)
+static void streamReadRecord_fwrap(int streamID, double data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadRecord(streamID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB3 (streamReadRecord_fwrap, STREAMREADRECORD, streamreadrecord, INT, DOUBLEV, PINT)
+static void streamReadRecordF_fwrap(int streamID, float data[], int *nmiss)
+{
+  size_t nmiss_size_t;
+  streamReadRecordF(streamID, data, &nmiss_size_t);
+  assert(nmiss_size_t < INT_MAX);
+  *nmiss = nmiss_size_t;
+}
+FCALLSCSUB3 (streamReadRecordF_fwrap, STREAMREADRECORDF, streamreadrecordf, INT, FLOATV, PINT)
 FCALLSCSUB2 (streamCopyRecord, STREAMCOPYRECORD, streamcopyrecord, INT, INT)
 
 /*  File driven I/O (may yield better performance than using the streamXXX functions)  */
@@ -72875,7 +72935,13 @@ FCALLSCFUN1 (INT, vlistNzaxis, VLISTNZAXIS, vlistnzaxis, INT)
 FCALLSCFUN1 (INT, vlistNsubtypes, VLISTNSUBTYPES, vlistnsubtypes, INT)
 FCALLSCSUB2 (vlistDefNtsteps, VLISTDEFNTSTEPS, vlistdefntsteps, INT, INT)
 FCALLSCFUN1 (INT, vlistNtsteps, VLISTNTSTEPS, vlistntsteps, INT)
-FCALLSCFUN1 (INT, vlistGridsizeMax, VLISTGRIDSIZEMAX, vlistgridsizemax, INT)
+static int vlistGridsizeMax_fwrap(int vlistID)
+{
+  size_t v;
+  v = vlistGridsizeMax(vlistID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, vlistGridsizeMax_fwrap, VLISTGRIDSIZEMAX, vlistgridsizemax, INT)
 FCALLSCFUN2 (INT, vlistGrid, VLISTGRID, vlistgrid, INT, INT)
 FCALLSCFUN2 (INT, vlistGridIndex, VLISTGRIDINDEX, vlistgridindex, INT, INT)
 FCALLSCSUB3 (vlistChangeGridIndex, VLISTCHANGEGRIDINDEX, vlistchangegridindex, INT, INT, INT)
@@ -72909,6 +72975,8 @@ FCALLSCFUN2 (INT, vlistInqVarZaxis, VLISTINQVARZAXIS, vlistinqvarzaxis, INT, INT
 /*  used in MPIOM  */
 
 FCALLSCFUN2 (INT, vlistInqVarID, VLISTINQVARID, vlistinqvarid, INT, INT)
+FCALLSCSUB3 (vlistDefVarTimetype, VLISTDEFVARTIMETYPE, vlistdefvartimetype, INT, INT, INT)
+FCALLSCFUN2 (INT, vlistInqVarTimetype, VLISTINQVARTIMETYPE, vlistinqvartimetype, INT, INT)
 FCALLSCSUB3 (vlistDefVarTsteptype, VLISTDEFVARTSTEPTYPE, vlistdefvartsteptype, INT, INT, INT)
 FCALLSCFUN2 (INT, vlistInqVarTsteptype, VLISTINQVARTSTEPTYPE, vlistinqvartsteptype, INT, INT)
 FCALLSCSUB3 (vlistDefVarCompType, VLISTDEFVARCOMPTYPE, vlistdefvarcomptype, INT, INT, INT)
@@ -72957,7 +73025,13 @@ FCALLSCSUB3 (vlistDefVarTypeOfGeneratingProcess, VLISTDEFVARTYPEOFGENERATINGPROC
 FCALLSCFUN2 (INT, vlistInqVarTypeOfGeneratingProcess, VLISTINQVARTYPEOFGENERATINGPROCESS, vlistinqvartypeofgeneratingprocess, INT, INT)
 FCALLSCSUB3 (vlistDefVarProductDefinitionTemplate, VLISTDEFVARPRODUCTDEFINITIONTEMPLATE, vlistdefvarproductdefinitiontemplate, INT, INT, INT)
 FCALLSCFUN2 (INT, vlistInqVarProductDefinitionTemplate, VLISTINQVARPRODUCTDEFINITIONTEMPLATE, vlistinqvarproductdefinitiontemplate, INT, INT)
-FCALLSCFUN2 (INT, vlistInqVarSize, VLISTINQVARSIZE, vlistinqvarsize, INT, INT)
+static int vlistInqVarSize_fwrap(int vlistID, int varID)
+{
+  size_t v;
+  v = vlistInqVarSize(vlistID, varID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, vlistInqVarSize_fwrap, VLISTINQVARSIZE, vlistinqvarsize, INT, INT)
 FCALLSCSUB4 (vlistDefIndex, VLISTDEFINDEX, vlistdefindex, INT, INT, INT, INT)
 FCALLSCFUN3 (INT, vlistInqIndex, VLISTINQINDEX, vlistinqindex, INT, INT, INT)
 FCALLSCSUB4 (vlistDefFlag, VLISTDEFFLAG, vlistdefflag, INT, INT, INT, INT)
@@ -72979,23 +73053,18 @@ FCALLSCFUN3 (INT, vlistHasVarKey, VLISTHASVARKEY, vlisthasvarkey, INT, INT, STRI
 FCALLSCFUN3 (DOUBLE, vlistInqVarDblKey, VLISTINQVARDBLKEY, vlistinqvardblkey, INT, INT, STRING)
 FCALLSCFUN3 (INT, vlistInqVarIntKey, VLISTINQVARINTKEY, vlistinqvarintkey, INT, INT, STRING)
 
-/*  needed only for CDO operator after  */
-
-FCALLSCFUN2 (STRING, vlistInqVarNamePtr, VLISTINQVARNAMEPTR, vlistinqvarnameptr, INT, INT)
-FCALLSCFUN2 (STRING, vlistInqVarLongnamePtr, VLISTINQVARLONGNAMEPTR, vlistinqvarlongnameptr, INT, INT)
-FCALLSCFUN2 (STRING, vlistInqVarUnitsPtr, VLISTINQVARUNITSPTR, vlistinqvarunitsptr, INT, INT)
-
-/*  VLIST attributes  */
+/*  CDI attributes  */
 
-FCALLSCFUN3 (INT, vlistInqNatts, VLISTINQNATTS, vlistinqnatts, INT, INT, PINT)
-FCALLSCFUN6 (INT, vlistInqAtt, VLISTINQATT, vlistinqatt, INT, INT, INT, PSTRING, PINT, PINT)
-FCALLSCFUN3 (INT, vlistDelAtt, VLISTDELATT, vlistdelatt, INT, INT, STRING)
-FCALLSCFUN6 (INT, vlistDefAttInt, VLISTDEFATTINT, vlistdefattint, INT, INT, STRING, INT, INT, INTV)
-FCALLSCFUN6 (INT, vlistDefAttFlt, VLISTDEFATTFLT, vlistdefattflt, INT, INT, STRING, INT, INT, DOUBLEV)
-FCALLSCFUN5 (INT, vlistDefAttTxt, VLISTDEFATTTXT, vlistdefatttxt, INT, INT, STRING, INT, PPSTRING)
-FCALLSCFUN5 (INT, vlistInqAttInt, VLISTINQATTINT, vlistinqattint, INT, INT, STRING, INT, INTV)
-FCALLSCFUN5 (INT, vlistInqAttFlt, VLISTINQATTFLT, vlistinqattflt, INT, INT, STRING, INT, DOUBLEV)
-FCALLSCFUN5 (INT, vlistInqAttTxt, VLISTINQATTTXT, vlistinqatttxt, INT, INT, STRING, INT, PPSTRING)
+FCALLSCFUN3 (INT, cdiInqNatts, CDIINQNATTS, cdiinqnatts, INT, INT, PINT)
+FCALLSCFUN6 (INT, cdiInqAtt, CDIINQATT, cdiinqatt, INT, INT, INT, PSTRING, PINT, PINT)
+FCALLSCFUN3 (INT, cdiDelAtt, CDIDELATT, cdidelatt, INT, INT, STRING)
+FCALLSCFUN4 (INT, cdiCopyAtts, CDICOPYATTS, cdicopyatts, INT, INT, INT, INT)
+FCALLSCFUN6 (INT, cdiDefAttInt, CDIDEFATTINT, cdidefattint, INT, INT, STRING, INT, INT, INTV)
+FCALLSCFUN6 (INT, cdiDefAttFlt, CDIDEFATTFLT, cdidefattflt, INT, INT, STRING, INT, INT, DOUBLEV)
+FCALLSCFUN5 (INT, cdiDefAttTxt, CDIDEFATTTXT, cdidefatttxt, INT, INT, STRING, INT, PPSTRING)
+FCALLSCFUN5 (INT, cdiInqAttInt, CDIINQATTINT, cdiinqattint, INT, INT, STRING, INT, INTV)
+FCALLSCFUN5 (INT, cdiInqAttFlt, CDIINQATTFLT, cdiinqattflt, INT, INT, STRING, INT, DOUBLEV)
+FCALLSCFUN5 (INT, cdiInqAttTxt, CDIINQATTTXT, cdiinqatttxt, INT, INT, STRING, INT, PPSTRING)
 
 /*  GRID routines  */
 
@@ -73006,27 +73075,81 @@ FCALLSCSUB2 (gridDefMaskGME, GRIDDEFMASKGME, griddefmaskgme, INT, INTV)
 FCALLSCFUN2 (INT, gridInqMaskGME, GRIDINQMASKGME, gridinqmaskgme, INT, INTV)
 FCALLSCSUB2 (gridDefMask, GRIDDEFMASK, griddefmask, INT, INTV)
 FCALLSCFUN2 (INT, gridInqMask, GRIDINQMASK, gridinqmask, INT, INTV)
-FCALLSCSUB3 (gridPrint, GRIDPRINT, gridprint, INT, INT, INT)
-FCALLSCFUN2 (INT, gridCreate, GRIDCREATE, gridcreate, INT, INT)
+FCALLSCSUB2 (gridPrint, GRIDPRINT, gridprint, INT, INT)
+static int gridCreate_fwrap(int gridtype, int size)
+{
+  int v;
+  v = gridCreate(gridtype, (size_t)size);
+  return v;
+}
+FCALLSCFUN2 (INT, gridCreate_fwrap, GRIDCREATE, gridcreate, INT, INT)
 FCALLSCSUB1 (gridDestroy, GRIDDESTROY, griddestroy, INT)
 FCALLSCFUN1 (INT, gridDuplicate, GRIDDUPLICATE, gridduplicate, INT)
+FCALLSCSUB2 (gridDefProj, GRIDDEFPROJ, griddefproj, INT, INT)
+FCALLSCFUN1 (INT, gridInqProj, GRIDINQPROJ, gridinqproj, INT)
+FCALLSCFUN1 (INT, gridInqProjType, GRIDINQPROJTYPE, gridinqprojtype, INT)
 FCALLSCFUN1 (INT, gridInqType, GRIDINQTYPE, gridinqtype, INT)
-FCALLSCFUN1 (INT, gridInqSize, GRIDINQSIZE, gridinqsize, INT)
-FCALLSCSUB2 (gridDefXsize, GRIDDEFXSIZE, griddefxsize, INT, INT)
-FCALLSCFUN1 (INT, gridInqXsize, GRIDINQXSIZE, gridinqxsize, INT)
-FCALLSCSUB2 (gridDefYsize, GRIDDEFYSIZE, griddefysize, INT, INT)
-FCALLSCFUN1 (INT, gridInqYsize, GRIDINQYSIZE, gridinqysize, INT)
+static int gridInqSize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqSize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqSize_fwrap, GRIDINQSIZE, gridinqsize, INT)
+static void gridDefXsize_fwrap(int gridID, int xsize)
+{
+  gridDefXsize(gridID, (size_t)xsize);
+}
+FCALLSCSUB2 (gridDefXsize_fwrap, GRIDDEFXSIZE, griddefxsize, INT, INT)
+static int gridInqXsize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqXsize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqXsize_fwrap, GRIDINQXSIZE, gridinqxsize, INT)
+static void gridDefYsize_fwrap(int gridID, int ysize)
+{
+  gridDefYsize(gridID, (size_t)ysize);
+}
+FCALLSCSUB2 (gridDefYsize_fwrap, GRIDDEFYSIZE, griddefysize, INT, INT)
+static int gridInqYsize_fwrap(int gridID)
+{
+  size_t v;
+  v = gridInqYsize(gridID);
+  return size_t_c2f(v);
+}
+FCALLSCFUN1 (INT, gridInqYsize_fwrap, GRIDINQYSIZE, gridinqysize, INT)
 FCALLSCSUB2 (gridDefNP, GRIDDEFNP, griddefnp, INT, INT)
 FCALLSCFUN1 (INT, gridInqNP, GRIDINQNP, gridinqnp, INT)
 FCALLSCSUB2 (gridDefXvals, GRIDDEFXVALS, griddefxvals, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqXvals, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV)
+static int gridInqXvals_fwrap(int gridID, double xvals[])
+{
+  size_t v;
+  v = gridInqXvals(gridID, xvals);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqXvals_fwrap, GRIDINQXVALS, gridinqxvals, INT, DOUBLEV)
+FCALLSCFUN1 (INT, gridInqXIsc, GRIDINQXISC, gridinqxisc, INT)
 FCALLSCSUB2 (gridDefYvals, GRIDDEFYVALS, griddefyvals, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqYvals, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
+static int gridInqYvals_fwrap(int gridID, double yvals[])
+{
+  size_t v;
+  v = gridInqYvals(gridID, yvals);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqYvals_fwrap, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
+FCALLSCFUN1 (INT, gridInqYIsc, GRIDINQYISC, gridinqyisc, INT)
 
 /*  CDI grid string key values  */
 
-FCALLSCFUN4 (INT, cdiGridDefString, CDIGRIDDEFSTRING, cdigriddefstring, INT, INT, INT, STRING)
-FCALLSCFUN4 (INT, cdiGridInqString, CDIGRIDINQSTRING, cdigridinqstring, INT, INT, INT, PSTRING)
+
+/*  CDI zaxis string key values  */
+
+FCALLSCFUN4 (INT, cdiGridDefKeyStr, CDIGRIDDEFKEYSTR, cdigriddefkeystr, INT, INT, INT, STRING)
+FCALLSCFUN4 (INT, cdiGridInqKeyStr, CDIGRIDINQKEYSTR, cdigridinqkeystr, INT, INT, INT, PSTRING)
+FCALLSCFUN3 (INT, cdiZaxisDefKeyFlt, CDIZAXISDEFKEYFLT, cdizaxisdefkeyflt, INT, INT, DOUBLE)
+FCALLSCFUN3 (INT, cdiZaxisInqKeyFlt, CDIZAXISINQKEYFLT, cdizaxisinqkeyflt, INT, INT, PDOUBLE)
 FCALLSCSUB2 (gridDefXname, GRIDDEFXNAME, griddefxname, INT, STRING)
 FCALLSCSUB2 (gridInqXname, GRIDINQXNAME, gridinqxname, INT, PSTRING)
 FCALLSCSUB2 (gridDefXlongname, GRIDDEFXLONGNAME, griddefxlongname, INT, STRING)
@@ -73041,34 +73164,28 @@ FCALLSCSUB2 (gridDefYunits, GRIDDEFYUNITS, griddefyunits, INT, STRING)
 FCALLSCSUB2 (gridInqYunits, GRIDINQYUNITS, gridinqyunits, INT, PSTRING)
 FCALLSCSUB2 (gridInqXstdname, GRIDINQXSTDNAME, gridinqxstdname, INT, PSTRING)
 FCALLSCSUB2 (gridInqYstdname, GRIDINQYSTDNAME, gridinqystdname, INT, PSTRING)
-FCALLSCSUB2 (gridDefPrec, GRIDDEFPREC, griddefprec, INT, INT)
-FCALLSCFUN1 (INT, gridInqPrec, GRIDINQPREC, gridinqprec, INT)
-FCALLSCFUN2 (DOUBLE, gridInqXval, GRIDINQXVAL, gridinqxval, INT, INT)
-FCALLSCFUN2 (DOUBLE, gridInqYval, GRIDINQYVAL, gridinqyval, INT, INT)
+FCALLSCSUB2 (gridDefDatatype, GRIDDEFDATATYPE, griddefdatatype, INT, INT)
+FCALLSCFUN1 (INT, gridInqDatatype, GRIDINQDATATYPE, gridinqdatatype, INT)
+static double gridInqXval_fwrap(int gridID, int index)
+{
+  double v;
+  v = gridInqXval(gridID, (size_t)index);
+  return v;
+}
+FCALLSCFUN2 (DOUBLE, gridInqXval_fwrap, GRIDINQXVAL, gridinqxval, INT, INT)
+static double gridInqYval_fwrap(int gridID, int index)
+{
+  double v;
+  v = gridInqYval(gridID, (size_t)index);
+  return v;
+}
+FCALLSCFUN2 (DOUBLE, gridInqYval_fwrap, GRIDINQYVAL, gridinqyval, INT, INT)
 FCALLSCFUN1 (DOUBLE, gridInqXinc, GRIDINQXINC, gridinqxinc, INT)
 FCALLSCFUN1 (DOUBLE, gridInqYinc, GRIDINQYINC, gridinqyinc, INT)
 FCALLSCFUN1 (INT, gridIsCircular, GRIDISCIRCULAR, gridiscircular, INT)
-FCALLSCFUN1 (INT, gridIsRotated, GRIDISROTATED, gridisrotated, INT)
-FCALLSCSUB2 (gridDefXpole, GRIDDEFXPOLE, griddefxpole, INT, DOUBLE)
-FCALLSCFUN1 (DOUBLE, gridInqXpole, GRIDINQXPOLE, gridinqxpole, INT)
-FCALLSCSUB2 (gridDefYpole, GRIDDEFYPOLE, griddefypole, INT, DOUBLE)
-FCALLSCFUN1 (DOUBLE, gridInqYpole, GRIDINQYPOLE, gridinqypole, INT)
-FCALLSCSUB2 (gridDefAngle, GRIDDEFANGLE, griddefangle, INT, DOUBLE)
-FCALLSCFUN1 (DOUBLE, gridInqAngle, GRIDINQANGLE, gridinqangle, INT)
 FCALLSCFUN1 (INT, gridInqTrunc, GRIDINQTRUNC, gridinqtrunc, INT)
 FCALLSCSUB2 (gridDefTrunc, GRIDDEFTRUNC, griddeftrunc, INT, INT)
 
-/*  Hexagonal GME grid  */
-
-FCALLSCSUB2 (gridDefGMEnd, GRIDDEFGMEND, griddefgmend, INT, INT)
-FCALLSCFUN1 (INT, gridInqGMEnd, GRIDINQGMEND, gridinqgmend, INT)
-FCALLSCSUB2 (gridDefGMEni, GRIDDEFGMENI, griddefgmeni, INT, INT)
-FCALLSCFUN1 (INT, gridInqGMEni, GRIDINQGMENI, gridinqgmeni, INT)
-FCALLSCSUB2 (gridDefGMEni2, GRIDDEFGMENI2, griddefgmeni2, INT, INT)
-FCALLSCFUN1 (INT, gridInqGMEni2, GRIDINQGMENI2, gridinqgmeni2, INT)
-FCALLSCSUB2 (gridDefGMEni3, GRIDDEFGMENI3, griddefgmeni3, INT, INT)
-FCALLSCFUN1 (INT, gridInqGMEni3, GRIDINQGMENI3, gridinqgmeni3, INT)
-
 /*  Reference of an unstructured grid  */
 
 FCALLSCSUB2 (gridDefNumber, GRIDDEFNUMBER, griddefnumber, INT, INT)
@@ -73080,47 +73197,64 @@ FCALLSCFUN2 (INT, gridInqReference, GRIDINQREFERENCE, gridinqreference, INT, PST
 FCALLSCSUB2 (gridDefUUID, GRIDDEFUUID, griddefuuid, INT, PVOID)
 FCALLSCSUB2 (gridInqUUID, GRIDINQUUID, gridinquuid, INT, PVOID)
 
-/*  Lambert Conformal Conic grid (GRIB version)  */
+/*  Rotated Lon/Lat grid  */
 
-FCALLSCSUB10 (gridDefLCC, GRIDDEFLCC, griddeflcc, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, INT, INT)
-FCALLSCSUB10 (gridInqLCC, GRIDINQLCC, gridinqlcc, INT, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PINT, PINT)
+FCALLSCSUB4 (gridDefParamRLL, GRIDDEFPARAMRLL, griddefparamrll, INT, DOUBLE, DOUBLE, DOUBLE)
+FCALLSCSUB4 (gridInqParamRLL, GRIDINQPARAMRLL, gridinqparamrll, INT, PDOUBLE, PDOUBLE, PDOUBLE)
 
-/*  Lambert Conformal Conic 2 grid (PROJ version)  */
+/*  Hexagonal GME grid  */
 
-FCALLSCSUB6 (gridDefLcc2, GRIDDEFLCC2, griddeflcc2, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE)
-FCALLSCSUB6 (gridInqLcc2, GRIDINQLCC2, gridinqlcc2, INT, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE)
+FCALLSCSUB5 (gridDefParamGME, GRIDDEFPARAMGME, griddefparamgme, INT, INT, INT, INT, INT)
+FCALLSCSUB5 (gridInqParamGME, GRIDINQPARAMGME, gridinqparamgme, INT, PINT, PINT, PINT, PINT)
 
-/*  Lambert Azimuthal Equal Area grid  */
+/*  Lambert Conformal Conic grid (GRIB version)  */
 
-FCALLSCSUB4 (gridDefLaea, GRIDDEFLAEA, griddeflaea, INT, DOUBLE, DOUBLE, DOUBLE)
-FCALLSCSUB4 (gridInqLaea, GRIDINQLAEA, gridinqlaea, INT, PDOUBLE, PDOUBLE, PDOUBLE)
+FCALLSCSUB12 (gridDefParamLCC, GRIDDEFPARAMLCC, griddefparamlcc, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE)
+FCALLSCFUN12 (INT, gridInqParamLCC, GRIDINQPARAMLCC, gridinqparamlcc, INT, DOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE)
 FCALLSCSUB2 (gridDefArea, GRIDDEFAREA, griddefarea, INT, DOUBLEV)
 FCALLSCSUB2 (gridInqArea, GRIDINQAREA, gridinqarea, INT, DOUBLEV)
 FCALLSCFUN1 (INT, gridHasArea, GRIDHASAREA, gridhasarea, INT)
 FCALLSCSUB2 (gridDefNvertex, GRIDDEFNVERTEX, griddefnvertex, INT, INT)
 FCALLSCFUN1 (INT, gridInqNvertex, GRIDINQNVERTEX, gridinqnvertex, INT)
 FCALLSCSUB2 (gridDefXbounds, GRIDDEFXBOUNDS, griddefxbounds, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqXbounds, GRIDINQXBOUNDS, gridinqxbounds, INT, DOUBLEV)
+static int gridInqXbounds_fwrap(int gridID, double xbounds[])
+{
+  size_t v;
+  v = gridInqXbounds(gridID, xbounds);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqXbounds_fwrap, GRIDINQXBOUNDS, gridinqxbounds, INT, DOUBLEV)
 FCALLSCSUB2 (gridDefYbounds, GRIDDEFYBOUNDS, griddefybounds, INT, DOUBLEV)
-FCALLSCFUN2 (INT, gridInqYbounds, GRIDINQYBOUNDS, gridinqybounds, INT, DOUBLEV)
+static int gridInqYbounds_fwrap(int gridID, double ybounds[])
+{
+  size_t v;
+  v = gridInqYbounds(gridID, ybounds);
+  return size_t_c2f(v);
+}
+FCALLSCFUN2 (INT, gridInqYbounds_fwrap, GRIDINQYBOUNDS, gridinqybounds, INT, DOUBLEV)
 FCALLSCSUB3 (gridDefRowlon, GRIDDEFROWLON, griddefrowlon, INT, INT, INTV)
 FCALLSCSUB2 (gridInqRowlon, GRIDINQROWLON, gridinqrowlon, INT, INTV)
 FCALLSCSUB2 (gridChangeType, GRIDCHANGETYPE, gridchangetype, INT, INT)
 FCALLSCSUB2 (gridDefComplexPacking, GRIDDEFCOMPLEXPACKING, griddefcomplexpacking, INT, INT)
 FCALLSCFUN1 (INT, gridInqComplexPacking, GRIDINQCOMPLEXPACKING, gridinqcomplexpacking, INT)
+FCALLSCSUB2 (gridDefUvRelativeToGrid, GRIDDEFUVRELATIVETOGRID, griddefuvrelativetogrid, INT, INT)
+FCALLSCFUN1 (INT, gridInqUvRelativeToGrid, GRIDINQUVRELATIVETOGRID, gridinquvrelativetogrid, INT)
+FCALLSCSUB2 (gridDefScanningMode, GRIDDEFSCANNINGMODE, griddefscanningmode, INT, INT)
+FCALLSCFUN1 (INT, gridInqScanningMode, GRIDINQSCANNINGMODE, gridinqscanningmode, INT)
 
 /*  ZAXIS routines  */
 
 FCALLSCSUB2 (zaxisName, ZAXISNAME, zaxisname, INT, PSTRING)
+FCALLSCFUN1 (STRING, zaxisNamePtr, ZAXISNAMEPTR, zaxisnameptr, INT)
 FCALLSCFUN2 (INT, zaxisCreate, ZAXISCREATE, zaxiscreate, INT, INT)
 FCALLSCSUB1 (zaxisDestroy, ZAXISDESTROY, zaxisdestroy, INT)
 FCALLSCFUN1 (INT, zaxisInqType, ZAXISINQTYPE, zaxisinqtype, INT)
 FCALLSCFUN1 (INT, zaxisInqSize, ZAXISINQSIZE, zaxisinqsize, INT)
 FCALLSCFUN1 (INT, zaxisDuplicate, ZAXISDUPLICATE, zaxisduplicate, INT)
-FCALLSCSUB2 (zaxisResize, ZAXISRESIZE, zaxisresize, INT, INT)
-FCALLSCSUB2 (zaxisPrint, ZAXISPRINT, zaxisprint, INT, INT)
+FCALLSCSUB1 (zaxisPrint, ZAXISPRINT, zaxisprint, INT)
 FCALLSCSUB2 (zaxisDefLevels, ZAXISDEFLEVELS, zaxisdeflevels, INT, DOUBLEV)
-FCALLSCSUB2 (zaxisInqLevels, ZAXISINQLEVELS, zaxisinqlevels, INT, DOUBLEV)
+FCALLSCFUN2 (INT, zaxisInqLevels, ZAXISINQLEVELS, zaxisinqlevels, INT, DOUBLEV)
+FCALLSCFUN1 (INT, zaxisInqCLen, ZAXISINQCLEN, zaxisinqclen, INT)
 FCALLSCSUB3 (zaxisDefLevel, ZAXISDEFLEVEL, zaxisdeflevel, INT, INT, DOUBLE)
 FCALLSCFUN2 (DOUBLE, zaxisInqLevel, ZAXISINQLEVEL, zaxisinqlevel, INT, INT)
 FCALLSCSUB2 (zaxisDefNlevRef, ZAXISDEFNLEVREF, zaxisdefnlevref, INT, INT)
@@ -73129,11 +73263,8 @@ FCALLSCSUB2 (zaxisDefNumber, ZAXISDEFNUMBER, zaxisdefnumber, INT, INT)
 FCALLSCFUN1 (INT, zaxisInqNumber, ZAXISINQNUMBER, zaxisinqnumber, INT)
 FCALLSCSUB2 (zaxisDefUUID, ZAXISDEFUUID, zaxisdefuuid, INT, PVOID)
 FCALLSCSUB2 (zaxisInqUUID, ZAXISINQUUID, zaxisinquuid, INT, PVOID)
-
-/*  CDI zaxis string key values  */
-
-FCALLSCFUN4 (INT, cdiZaxisDefString, CDIZAXISDEFSTRING, cdizaxisdefstring, INT, INT, INT, STRING)
-FCALLSCFUN4 (INT, cdiZaxisInqString, CDIZAXISINQSTRING, cdizaxisinqstring, INT, INT, INT, PSTRING)
+FCALLSCFUN4 (INT, cdiZaxisDefKeyStr, CDIZAXISDEFKEYSTR, cdizaxisdefkeystr, INT, INT, INT, STRING)
+FCALLSCFUN4 (INT, cdiZaxisInqKeyStr, CDIZAXISINQKEYSTR, cdizaxisinqkeystr, INT, INT, INT, PSTRING)
 FCALLSCSUB2 (zaxisDefName, ZAXISDEFNAME, zaxisdefname, INT, STRING)
 FCALLSCSUB2 (zaxisInqName, ZAXISINQNAME, zaxisinqname, INT, PSTRING)
 FCALLSCSUB2 (zaxisDefLongname, ZAXISDEFLONGNAME, zaxisdeflongname, INT, STRING)
@@ -73141,10 +73272,8 @@ FCALLSCSUB2 (zaxisInqLongname, ZAXISINQLONGNAME, zaxisinqlongname, INT, PSTRING)
 FCALLSCSUB2 (zaxisDefUnits, ZAXISDEFUNITS, zaxisdefunits, INT, STRING)
 FCALLSCSUB2 (zaxisInqUnits, ZAXISINQUNITS, zaxisinqunits, INT, PSTRING)
 FCALLSCSUB2 (zaxisInqStdname, ZAXISINQSTDNAME, zaxisinqstdname, INT, PSTRING)
-FCALLSCSUB2 (zaxisDefPsName, ZAXISDEFPSNAME, zaxisdefpsname, INT, STRING)
-FCALLSCSUB2 (zaxisInqPsName, ZAXISINQPSNAME, zaxisinqpsname, INT, PSTRING)
-FCALLSCSUB2 (zaxisDefPrec, ZAXISDEFPREC, zaxisdefprec, INT, INT)
-FCALLSCFUN1 (INT, zaxisInqPrec, ZAXISINQPREC, zaxisinqprec, INT)
+FCALLSCSUB2 (zaxisDefDatatype, ZAXISDEFDATATYPE, zaxisdefdatatype, INT, INT)
+FCALLSCFUN1 (INT, zaxisInqDatatype, ZAXISINQDATATYPE, zaxisinqdatatype, INT)
 FCALLSCSUB2 (zaxisDefPositive, ZAXISDEFPOSITIVE, zaxisdefpositive, INT, INT)
 FCALLSCFUN1 (INT, zaxisInqPositive, ZAXISINQPOSITIVE, zaxisinqpositive, INT)
 FCALLSCSUB1 (zaxisDefScalar, ZAXISDEFSCALAR, zaxisdefscalar, INT)
@@ -73184,6 +73313,7 @@ FCALLSCSUB2 (taxisDefFtime, TAXISDEFFTIME, taxisdefftime, INT, INT)
 FCALLSCFUN1 (INT, taxisInqFdate, TAXISINQFDATE, taxisinqfdate, INT)
 FCALLSCFUN1 (INT, taxisInqFtime, TAXISINQFTIME, taxisinqftime, INT)
 FCALLSCFUN1 (INT, taxisHasBounds, TAXISHASBOUNDS, taxishasbounds, INT)
+FCALLSCSUB1 (taxisWithBounds, TAXISWITHBOUNDS, taxiswithbounds, INT)
 FCALLSCSUB1 (taxisDeleteBounds, TAXISDELETEBOUNDS, taxisdeletebounds, INT)
 FCALLSCSUB3 (taxisDefVdateBounds, TAXISDEFVDATEBOUNDS, taxisdefvdatebounds, INT, INT, INT)
 FCALLSCSUB3 (taxisDefVtimeBounds, TAXISDEFVTIMEBOUNDS, taxisdefvtimebounds, INT, INT, INT)
@@ -73222,27 +73352,15 @@ FCALLSCFUN1 (STRING, modelInqNamePtr, MODELINQNAMEPTR, modelinqnameptr, INT)
 
 /*  Table routines  */
 
-FCALLSCSUB2 (tableWriteC, TABLEWRITEC, tablewritec, STRING, INT)
 FCALLSCSUB2 (tableWrite, TABLEWRITE, tablewrite, STRING, INT)
 FCALLSCFUN1 (INT, tableRead, TABLEREAD, tableread, STRING)
 FCALLSCFUN3 (INT, tableDef, TABLEDEF, tabledef, INT, INT, STRING)
 FCALLSCFUN1 (STRING, tableInqNamePtr, TABLEINQNAMEPTR, tableinqnameptr, INT)
-FCALLSCSUB5 (tableDefEntry, TABLEDEFENTRY, tabledefentry, INT, INT, STRING, STRING, STRING)
 FCALLSCFUN3 (INT, tableInq, TABLEINQ, tableinq, INT, INT, STRING)
 FCALLSCFUN0 (INT, tableInqNumber, TABLEINQNUMBER, tableinqnumber)
 FCALLSCFUN1 (INT, tableInqNum, TABLEINQNUM, tableinqnum, INT)
 FCALLSCFUN1 (INT, tableInqModel, TABLEINQMODEL, tableinqmodel, INT)
-FCALLSCSUB5 (tableInqPar, TABLEINQPAR, tableinqpar, INT, INT, PSTRING, PSTRING, PSTRING)
-FCALLSCFUN3 (INT, tableInqParCode, TABLEINQPARCODE, tableinqparcode, INT, PSTRING, PINT)
-FCALLSCFUN3 (INT, tableInqParName, TABLEINQPARNAME, tableinqparname, INT, INT, PSTRING)
-FCALLSCFUN3 (INT, tableInqParLongname, TABLEINQPARLONGNAME, tableinqparlongname, INT, INT, PSTRING)
-FCALLSCFUN3 (INT, tableInqParUnits, TABLEINQPARUNITS, tableinqparunits, INT, INT, PSTRING)
-
-/*  needed only for CDO operator after  */
-
-FCALLSCFUN2 (STRING, tableInqParNamePtr, TABLEINQPARNAMEPTR, tableinqparnameptr, INT, INT)
-FCALLSCFUN2 (STRING, tableInqParLongnamePtr, TABLEINQPARLONGNAMEPTR, tableinqparlongnameptr, INT, INT)
-FCALLSCFUN2 (STRING, tableInqParUnitsPtr, TABLEINQPARUNITSPTR, tableinqparunitsptr, INT, INT)
+FCALLSCSUB6 (tableInqEntry, TABLEINQENTRY, tableinqentry, INT, INT, INT, PSTRING, PSTRING, PSTRING)
 
 /*  History routines  */
 
@@ -73276,4 +73394,7 @@ FCALLSCFUN4 (INT, subtypeInqAttribute, SUBTYPEINQATTRIBUTE, subtypeinqattribute,
 FCALLSCFUN2 (INT, vlistInqVarSubtype, VLISTINQVARSUBTYPE, vlistinqvarsubtype, INT, INT)
 FCALLSCSUB3 (gribapiLibraryVersion, GRIBAPILIBRARYVERSION, gribapilibraryversion, PINT, PINT, PINT)
 
+#if defined __clang__
+#  pragma GCC diagnostic pop
+#endif
 #endif
diff --git a/libcdi/src/cdipio.h b/libcdi/src/cdipio.h
index 4ff825a..d5df933 100644
--- a/libcdi/src/cdipio.h
+++ b/libcdi/src/cdipio.h
@@ -49,12 +49,12 @@ void     pioWriteTimestep(void);
 void     cdiPioRDMAProgress(void);
 
 void     streamWriteVarPart    (int streamID, int varID,
-                                const void *data, int nmiss,
+                                const void *data, size_t nmiss,
                                 Xt_idxlist partDesc);
 void     streamWriteScatteredVarPart(int streamID, int varID, const void *data,
                                      int numBlocks, const int blocklengths[],
                                      const int displacements[],
-                                     int nmiss, Xt_idxlist partDesc);
+                                     size_t nmiss, Xt_idxlist partDesc);
 /* cdiPioCSRLastN: return role codes appropriate to use the last
    \textit{nProcsIO} tasks as I/O servers */
 int cdiPioCSRLastN(MPI_Comm commSuper, int IOMode, int nProcsIO);
diff --git a/libcdi/src/cdipioFortran.c b/libcdi/src/cdipioFortran.c
index b076ece..e51c477 100644
--- a/libcdi/src/cdipioFortran.c
+++ b/libcdi/src/cdipioFortran.c
@@ -55,12 +55,12 @@ static int cdiPioInit_fwrap(int commSuper, int confResH, int *pioNamespace)
 FCALLSCFUN3 (INT, cdiPioInit_fwrap, CDIPIOINIT, cdipioinit, INT, INT, PINT)
 FCALLSCSUB0 (pioWriteTimestep, PIOWRITETIMESTEP, piowritetimestep)
 FCALLSCSUB0 (cdiPioRDMAProgress, CDIPIORDMAPROGRESS, cdipiordmaprogress)
-static void streamWriteVarPart_fwrap(int streamID, int varID, const void *data, int nmiss, void *partDesc)
+static void streamWriteVarPart_fwrap(int streamID, int varID, const void *data, size_t nmiss, void *partDesc)
 {
   streamWriteVarPart(streamID, varID, data, nmiss, (*(Xt_idxlist *)partDesc));
 }
 FCALLSCSUB5 (streamWriteVarPart_fwrap, STREAMWRITEVARPART, streamwritevarpart, INT, INT, PVOID, INT, PVOID)
-static void streamWriteScatteredVarPart_fwrap(int streamID, int varID, const void *data, int numBlocks, const int  blocklengths[], const int  displacements[], int nmiss, void *partDesc)
+static void streamWriteScatteredVarPart_fwrap(int streamID, int varID, const void *data, int numBlocks, const int  blocklengths[], const int  displacements[], size_t nmiss, void *partDesc)
 {
   streamWriteScatteredVarPart(streamID, varID, data, numBlocks, blocklengths, displacements, nmiss, (*(Xt_idxlist *)partDesc));
 }
diff --git a/libcdi/src/config.h.in b/libcdi/src/config.h.in
index 3110e95..1293cb9 100644
--- a/libcdi/src/config.h.in
+++ b/libcdi/src/config.h.in
@@ -267,6 +267,11 @@
 # endif
 #endif
 
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
diff --git a/libcdi/src/grb_read.c b/libcdi/src/grb_read.c
index 787dd65..ee5f3d2 100644
--- a/libcdi/src/grb_read.c
+++ b/libcdi/src/grb_read.c
@@ -16,8 +16,8 @@
 
 
 static
-int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
-	      int unreduced, int *nmiss, double missval, int vlistID, int varID)
+int grbDecode(int filetype, int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+	      int unreduced, size_t *nmiss, double missval, int vlistID, int varID)
 {
   int status = 0;
 
@@ -29,7 +29,7 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
       if ( cdiNAdditionalGRIBKeys > 0 )
 	Error("CGRIBEX decode does not support reading of additional GRIB keys!");
 #endif
-      status = cgribexDecode(memtype, gribbuffer, gribsize, data, (long) datasize, unreduced, nmiss, missval);
+      status = cgribexDecode(memtype, gribbuffer, gribsize, data, datasize, unreduced, nmiss, missval);
     }
   else
 #endif
@@ -39,7 +39,7 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
       if ( memtype == MEMTYPE_FLOAT )
         datap = Malloc(datasize*sizeof(double));
 
-      status = gribapiDecode(gribbuffer, gribsize, datap, (long) datasize, unreduced, nmiss, missval, vlistID, varID);
+      status = gribapiDecode(gribbuffer, gribsize, datap, datasize, unreduced, nmiss, missval, vlistID, varID);
 
       if ( memtype == MEMTYPE_FLOAT )
         {
@@ -111,7 +111,7 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 }
 
 
-void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
+void grb_read_record(stream_t * streamptr, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -127,7 +127,7 @@ void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
   int varID   = streamptr->tsteps[tsID].records[recID].varID;
 
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   streamptr->numvals += gridsize;
 
@@ -140,11 +140,11 @@ void grb_read_record(stream_t * streamptr, int memtype, void *data, int *nmiss)
 
   streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
-  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 }
 
 
-void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int *nmiss)
+void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -155,14 +155,14 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
   int tsID    = streamptr->curTsID;
 
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   off_t currentfilepos = fileGetPos(fileID);
 
   int isub     = subtypeInqActiveIndex(streamptr->vars[varID].subtypeID);
   int nlevs    = streamptr->vars[varID].recordTable[0].nlevs;
   if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d", nlevs, gridID, gridsize);
+    Message("nlevs = %d gridID = %d gridsize = %zu", nlevs, gridID, gridsize);
   *nmiss = 0;
   for (int levelID = 0; levelID < nlevs; levelID++ )
     {
@@ -176,7 +176,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
 
       double missval = vlistInqVarMissval(vlistID, varID);
 
-      int imiss;
+      size_t imiss;
 
       streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
@@ -186,7 +186,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
       else
         datap = (double*)data + levelID*gridsize;
 
-      grbDecode(filetype, memtype, gribbuffer, (int)recsize, datap, (size_t)gridsize,
+      grbDecode(filetype, memtype, gribbuffer, recsize, datap, gridsize,
                 streamptr->unreduced, &imiss, missval, vlistID, varID);
 
       *nmiss += imiss;
@@ -196,7 +196,7 @@ void grb_read_var(stream_t * streamptr, int varID, int memtype, void *data, int
 }
 
 
-void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss)
+void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss)
 {
   int filetype = streamptr->filetype;
 
@@ -204,11 +204,11 @@ void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
 
   int vlistID = streamptr->vlistID;
   int gridID   = vlistInqVarGrid(vlistID, varID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
   int tsID = streamptr->curTsID;
 
   if ( CDI_Debug )
-    Message("gridID = %d gridsize = %d", gridID, gridsize);
+    Message("gridID = %d gridsize = %zu", gridID, gridsize);
 
   int fileID = streamptr->fileID;
 
@@ -230,7 +230,7 @@ void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
   streamptr->tsteps[tsID].records[recID].zip = grbUnzipRecord(gribbuffer, &recsize);
 
   double missval = vlistInqVarMissval(vlistID, varID);
-  grbDecode(filetype, memtype, gribbuffer, (int)recsize, data, (size_t)gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
+  grbDecode(filetype, memtype, gribbuffer, recsize, data, gridsize, streamptr->unreduced, nmiss, missval, vlistID, varID);
 
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 }
diff --git a/libcdi/src/grb_write.c b/libcdi/src/grb_write.c
index c868ac6..d1c689f 100644
--- a/libcdi/src/grb_write.c
+++ b/libcdi/src/grb_write.c
@@ -19,7 +19,7 @@
 static
 size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		 int date, int time, int tsteptype, int numavg,
-		 size_t datasize, const void *data, int nmiss, void **gribbuffer,
+		 size_t datasize, const void *data, size_t nmiss, void **gribbuffer,
 		 int comptype, void *gribContainer)
 {
   size_t nbytes = 0;
@@ -32,7 +32,7 @@ size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID,
 
       nbytes = cgribexEncode(memtype, varID, levelID, vlistID, gridID, zaxisID,
 			     date, time, tsteptype, numavg,
-			     (long) datasize, data, nmiss, *gribbuffer, gribbuffersize);
+			     datasize, data, nmiss, *gribbuffer, gribbuffersize);
     }
   else
 #endif
@@ -152,23 +152,19 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
 
     if (scanModeIN != cdiGribDataScanningMode.value)
     {
-        int gridID;
-        int varID, levelID;
-        int vlistID;
         //int zip;
-        int gridsize, nmiss = 0;
+        size_t nmiss = 0;
 
-        vlistID = streamptr1->vlistID;
-        varID   = streamptr1->tsteps[tsID].records[recID].varID;
-        levelID   = streamptr1->tsteps[tsID].records[recID].levelID;
+        int vlistID = streamptr1->vlistID;
+        int varID   = streamptr1->tsteps[tsID].records[recID].varID;
+        int levelID = streamptr1->tsteps[tsID].records[recID].levelID;
         //gribbuffer = (unsigned char *) streamptr->record->buffer;
         // allocate above ..
-        gridID   = vlistInqVarGrid(vlistID, varID);
-        gridsize = gridInqSize(gridID);
+        int gridID   = vlistInqVarGrid(vlistID, varID);
 
-        gridsize = vlistGridsizeMax(vlistID);
+        size_t gridsize = vlistGridsizeMax(vlistID);
         if ( vlistNumber(vlistID) != CDI_REAL ) gridsize *= 2;
-        double * data = (double *) malloc(gridsize*sizeof(double));
+        double *data = (double *) malloc(gridsize*sizeof(double));
         //int missval = vlistInqVarMissval(vlistID, varID);
 
         //streamptr->numvals += gridsize;
@@ -176,7 +172,7 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
         // memtype: MEMTYPE_FLOAT or MEMTYPE_DOUBLE
         //int statusDC = grbDecode(filetype, MEMTYPE_DOUBLE, gribbuffer, recsize, data, gridsize, streamptr1->unreduced, &nmiss, missval, vlistID, varID);
         //int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *data, size_t datasize,
-        //              int unreduced, int *nmiss, double missval, int vlistID, int varID);
+        //              int unreduced, size_t *nmiss, double missval, int vlistID, int varID);
 
         //streamptr1->tsteps[tsID].records[recID].zip = zip;
         //gribapiSetScanningMode(gh, cdoGribDataScanningMode);  // T.B.D. this will be done by grbDecode..
@@ -190,7 +186,7 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
         //grb_write_var_slice(streamptr, varID, levelID, memtype, ((double*)data)+levelID*gridsize, nmiss);
 
         //grb_write_var(streamptr2, varID, MEMTYPE_DOUBLE, data, nmiss);
-        //grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+        //grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
         //grb_write_var_slice(streamptr2, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 
         free(data);
@@ -221,7 +217,7 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
 }
 
 
-void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss)
+void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
   void *gribbuffer = NULL;
   void *gc = NULL;
@@ -241,7 +237,7 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   if ( CDI_Debug )
     Message("gridID = %d zaxisID = %d", gridID, zaxisID);
 
-  size_t datasize = (size_t)gridInqSize(gridID);
+  size_t datasize = gridInqSize(gridID);
 
 #ifdef HAVE_LIBCGRIBEX
   if ( filetype == CDI_FILETYPE_GRB )
@@ -289,22 +285,22 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
 }
 
 
-void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss)
+void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss)
 {
   int vlistID  = streamptr->vlistID,
     gridID   = vlistInqVarGrid(vlistID, varID),
-    gridsize = gridInqSize(gridID),
     zaxisID  = vlistInqVarZaxis(vlistID, varID),
     nlevs    = zaxisInqSize(zaxisID);
+  size_t gridsize = gridInqSize(gridID);
   double missval = vlistInqVarMissval(vlistID, varID);
 
-  size_t chunkLen = (size_t)gridsize;
+  size_t chunkLen = gridsize;
   if ( memtype == MEMTYPE_FLOAT )
     for ( int levelID = 0; levelID < nlevs; levelID++ )
       {
         const float *restrict fdata = ((const float *)data)+levelID*gridsize;
         
-        int nmiss_slice = 0;
+        size_t nmiss_slice = 0;
         if ( nmiss )
           for ( size_t i = 0; i < chunkLen; ++i )
             nmiss_slice += DBL_IS_EQUAL(fdata[i], missval);
@@ -316,7 +312,7 @@ void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data
       {
         const double *restrict ddata = ((const double *)data)+levelID*gridsize;
         
-        int nmiss_slice = 0;
+        size_t nmiss_slice = 0;
         if ( nmiss )
           for ( size_t i = 0; i < chunkLen; ++i )
             nmiss_slice += DBL_IS_EQUAL(ddata[i], missval);
@@ -326,7 +322,7 @@ void grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data
 }
 
 
-void grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss)
+void grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss)
 {
   int varID   = streamptr->record->varID;
   int levelID = streamptr->record->levelID;
diff --git a/libcdi/src/gribapi_utilities.c b/libcdi/src/gribapi_utilities.c
index 5e88cd9..dd583c2 100644
--- a/libcdi/src/gribapi_utilities.c
+++ b/libcdi/src/gribapi_utilities.c
@@ -527,16 +527,17 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
 
   size_t datasize;
   FAIL_ON_GRIB_ERROR(grib_get_size, gh, "values", &datasize);
-  long numberOfPoints;
-  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &numberOfPoints);
-
   long lpar;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &lpar);
+  size_t numberOfPoints = (size_t) lpar;
+
 
   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
     {
-      long nlon, nlat;
-      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &nlon);
-      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &nlat);
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &lpar);
+      size_t nlon = (size_t) lpar;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
+      size_t nlat = (size_t) lpar;
 
       if ( gridtype == GRID_GAUSSIAN )
         {
@@ -545,11 +546,11 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
         }
 
       if ( numberOfPoints != nlon*nlat )
-        Error("numberOfPoints (%ld) and gridSize (%ld) differ!", numberOfPoints, nlon*nlat);
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
 
-      grid->size   = (int)numberOfPoints;
-      grid->x.size = (int)nlon;
-      grid->y.size = (int)nlat;
+      grid->size   = numberOfPoints;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
       grid->x.inc  = 0;
       grid->y.inc  = 0;
       grid->x.flag = 0;
@@ -611,7 +612,7 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
       int nlat = (int)lpar;
 
-      grid->size   = (int)numberOfPoints;
+      grid->size   = numberOfPoints;
 
       grid->nrowlon = nlat;
       grid->rowlon = (int *) Malloc((size_t)nlat * sizeof (int));
@@ -621,7 +622,7 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
       for ( int i = 0; i < nlat; ++i ) grid->rowlon[i] = (int)pl[i];
       Free(pl);
 
-      grid->y.size  = nlat;
+      grid->y.size  = (size_t)nlat;
       grid->x.inc   = 0;
       grid->y.inc   = 0;
       grid->x.flag  = 0;
@@ -670,14 +671,14 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
   else if ( projtype == CDI_PROJ_LCC )
     {
       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nx", &lpar);
-      int nlon = (int)lpar;
+      size_t nlon = (size_t)lpar;
       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ny", &lpar);
-      int nlat = (int)lpar;
+      size_t nlat = (size_t)lpar;
 
       if ( numberOfPoints != nlon*nlat )
-        Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", numberOfPoints, nlon*nlat);
 
-      grid->size  = (int)numberOfPoints;
+      grid->size  = numberOfPoints;
       grid->x.size = nlon;
       grid->y.size = nlat;
 
@@ -702,14 +703,14 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
       grid->lcomplex = 0;
       if ( strncmp(typeOfPacking, "spectral_complex", len) == 0 ) grid->lcomplex = 1;
 
-      grid->size  = (int)datasize;
+      grid->size = datasize;
 
       FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
       grid->trunc = (int)lpar;
     }
   else if ( gridtype == GRID_GME )
     {
-      grid->size  = (int)numberOfPoints;
+      grid->size = numberOfPoints;
       if ( grib_get_long(gh, "nd", &lpar) == 0 ) grid->gme.nd  = (int)lpar;
       if ( grib_get_long(gh, "Ni", &lpar) == 0 ) grid->gme.ni  = (int)lpar;
       if ( grib_get_long(gh, "n2", &lpar) == 0 ) grid->gme.ni2 = (int)lpar;
@@ -723,7 +724,7 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
         size_t len = sizeof(reference_link);
         reference_link[0] = 0;
       */
-      grid->size  = (int)numberOfPoints;
+      grid->size = numberOfPoints;
 
       if ( grib_get_long(gh, "numberOfGridUsed", &lpar) == 0 )
         {
@@ -746,11 +747,11 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
     }
   else if ( gridtype == GRID_GENERIC )
     {
-      int nlon = 0, nlat = 0;
-      if ( grib_get_long(gh, "Ni", &lpar) == 0 ) nlon = (int)lpar;
-      if ( grib_get_long(gh, "Nj", &lpar) == 0 ) nlat = (int)lpar;
+      size_t nlon = 0, nlat = 0;
+      if ( grib_get_long(gh, "Ni", &lpar) == 0 ) nlon = (size_t)lpar;
+      if ( grib_get_long(gh, "Nj", &lpar) == 0 ) nlat = (size_t)lpar;
 
-      grid->size  = (int)numberOfPoints;
+      grid->size = numberOfPoints;
 
       if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
         {
diff --git a/libcdi/src/grid.c b/libcdi/src/grid.c
index d87ccd6..405e095 100644
--- a/libcdi/src/grid.c
+++ b/libcdi/src/grid.c
@@ -4,8 +4,6 @@
 
 #include <assert.h>
 #include <string.h>
-#include <float.h>  /* FLT_EPSILON */
-#include <limits.h> /* INT_MAX     */
 
 #include "dmemory.h"
 #include "cdi.h"
@@ -290,7 +288,7 @@ void gridSetName(char *gridstrname, const char *name)
 }
 
 
-void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size)
 {
   gridptr->type = gridtype;
   gridptr->size = size;
@@ -379,18 +377,18 @@ void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *r
 }
 
 static
-void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
+void calc_gaussgrid(double *restrict yvals, size_t ysize, double yfirst, double ylast)
 {
-  double *restrict yw = (double *) Malloc((size_t)ysize * sizeof(double));
-  gaussaw(yvals, yw, (size_t)ysize);
+  double *restrict yw = (double *) Malloc(ysize * sizeof(double));
+  gaussaw(yvals, yw, ysize);
   Free(yw);
-  for (int i = 0; i < ysize; i++ )
+  for (size_t i = 0; i < ysize; i++ )
     yvals[i] = asin(yvals[i])/M_PI*180.0;
 
   if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
     {
-      int yhsize = ysize/2;
-      for (int i = 0; i < yhsize; i++ )
+      size_t yhsize = ysize/2;
+      for (size_t i = 0; i < yhsize; i++ )
         {
           double ytmp = yvals[i];
           yvals[i] = yvals[ysize-i-1];
@@ -414,7 +412,8 @@ void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double y
 	    if ( fabs(yvals[0] - yfirst) > deleps || fabs(yvals[ysize-1] - ylast) > deleps )
 	      {
 		double *restrict ytmp = NULL;
-		int nstart, lfound = 0;
+		int nstart;
+                bool lfound = false;
 		int ny = (int) (180./(fabs(ylast-yfirst)/(ysize-1)) + 0.5);
 		ny -= ny%2;
 		if ( ny > ysize && ny < 4096 )
@@ -494,7 +493,7 @@ void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double y
 @Function  gridCreate
 @Title     Create a horizontal Grid
 
- at Prototype int gridCreate(int gridtype, int size)
+ at Prototype int gridCreate(int gridtype, size_t size)
 @Parameter
     @Item  gridtype  The type of the grid, one of the set of predefined CDI grid types.
                      The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
@@ -530,11 +529,9 @@ gridDefYvals(gridID, lats);
 @EndSource
 @EndFunction
 */
-int gridCreate(int gridtype, int size)
+int gridCreate(int gridtype, size_t size)
 {
-  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
-
-  if ( size < 0 || size > INT_MAX ) Error("Grid size (%d) out of bounds (0 - %d)!", size, INT_MAX);
+  if ( CDI_Debug ) Message("gridtype=%s  size=%zu", gridNamePtr(gridtype), size);
 
   gridInit();
 
@@ -1082,7 +1079,7 @@ int gridInqType(int gridID)
 @Function  gridInqSize
 @Title     Get the size of a Grid
 
- at Prototype int gridInqSize(int gridID)
+ at Prototype size_t gridInqSize(int gridID)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
@@ -1094,21 +1091,18 @@ The function @func{gridInqSize} returns the size of a Grid.
 
 @EndFunction
 */
-int gridInqSize(int gridID)
+size_t gridInqSize(int gridID)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
 
-  int size = gridptr->size;
+  size_t size = gridptr->size;
 
   if ( size == 0 )
     {
-      int xsize = gridptr->x.size;
-      int ysize = gridptr->y.size;
+      size_t xsize = gridptr->x.size;
+      size_t ysize = gridptr->y.size;
 
-      if ( ysize )
-        size = xsize * ysize;
-      else
-        size = xsize;
+      size = ysize ? xsize * ysize : xsize;
 
       gridptr->size = size;
     }
@@ -1163,7 +1157,7 @@ void gridDefTrunc(int gridID, int trunc)
 @Function  gridDefXsize
 @Title     Define the number of values of a X-axis
 
- at Prototype void gridDefXsize(int gridID, int xsize)
+ at Prototype void gridDefXsize(int gridID, size_t xsize)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
     @Item  xsize    Number of values of a X-axis.
@@ -1173,17 +1167,17 @@ The function @func{gridDefXsize} defines the number of values of a X-axis.
 
 @EndFunction
 */
-void gridDefXsize(int gridID, int xsize)
+void gridDefXsize(int gridID, size_t xsize)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
 
-  int gridSize = gridInqSize(gridID);
+  size_t gridSize = gridInqSize(gridID);
   if ( xsize > gridSize )
-    Error("xsize %d is greater then gridsize %d", xsize, gridSize);
+    Error("xsize %zu is greater then gridsize %zu", xsize, gridSize);
 
   int gridType = gridInqType(gridID);
   if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
-    Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
+    Error("xsize %zu must be equal to gridsize %zu for gridtype: UNSTRUCTURED", xsize, gridSize);
 
   if ( gridptr->x.size != xsize )
     {
@@ -1193,9 +1187,9 @@ void gridDefXsize(int gridID, int xsize)
 
   if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
     {
-      long axisproduct = gridptr->x.size*gridptr->y.size;
+      size_t axisproduct = gridptr->x.size*gridptr->y.size;
       if ( axisproduct > 0 && axisproduct != gridSize )
-        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
+        Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
               gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
@@ -1241,7 +1235,7 @@ int gridInqDatatype(int gridID)
 @Function  gridInqXsize
 @Title     Get the number of values of a X-axis
 
- at Prototype int gridInqXsize(int gridID)
+ at Prototype size_t gridInqXsize(int gridID)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
@@ -1253,7 +1247,7 @@ The function @func{gridInqXsize} returns the number of values of a X-axis.
 
 @EndFunction
 */
-int gridInqXsize(int gridID)
+size_t gridInqXsize(int gridID)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->x.size;
@@ -1263,7 +1257,7 @@ int gridInqXsize(int gridID)
 @Function  gridDefYsize
 @Title     Define the number of values of a Y-axis
 
- at Prototype void gridDefYsize(int gridID, int ysize)
+ at Prototype void gridDefYsize(int gridID, size_t ysize)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
     @Item  ysize    Number of values of a Y-axis.
@@ -1273,18 +1267,18 @@ The function @func{gridDefYsize} defines the number of values of a Y-axis.
 
 @EndFunction
 */
-void gridDefYsize(int gridID, int ysize)
+void gridDefYsize(int gridID, size_t ysize)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
 
-  int gridSize = gridInqSize(gridID);
+  size_t gridSize = gridInqSize(gridID);
 
   if ( ysize > gridSize )
-    Error("ysize %d is greater then gridsize %d", ysize, gridSize);
+    Error("ysize %zu is greater then gridsize %zu", ysize, gridSize);
 
   int gridType = gridInqType(gridID);
   if ( gridType == GRID_UNSTRUCTURED && ysize != gridSize )
-    Error("ysize %d must be equal gridsize %d for gridtype: UNSTRUCTURED", ysize, gridSize);
+    Error("ysize %zu must be equal gridsize %zu for gridtype: UNSTRUCTURED", ysize, gridSize);
 
   if ( gridptr->y.size != ysize )
     {
@@ -1294,9 +1288,9 @@ void gridDefYsize(int gridID, int ysize)
 
   if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
     {
-      long axisproduct = gridptr->x.size*gridptr->y.size;
+      size_t axisproduct = gridptr->x.size*gridptr->y.size;
       if ( axisproduct > 0 && axisproduct != gridSize )
-        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
+        Error("Inconsistent grid declaration! (xsize=%zu ysize=%zu gridsize=%zu)",
               gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
@@ -1305,7 +1299,7 @@ void gridDefYsize(int gridID, int ysize)
 @Function  gridInqYsize
 @Title     Get the number of values of a Y-axis
 
- at Prototype int gridInqYsize(int gridID)
+ at Prototype size_t gridInqYsize(int gridID)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
@@ -1317,7 +1311,7 @@ The function @func{gridInqYsize} returns the number of values of a Y-axis.
 
 @EndFunction
 */
-int gridInqYsize(int gridID)
+size_t gridInqYsize(int gridID)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->y.size;
@@ -1411,11 +1405,11 @@ void gridInqRowlon(int gridID, int *rowlon)
   memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
 }
 
-static int
+static size_t
 gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
                         int *restrict mask)
 {
-  long size = gridptr->size;
+  size_t size = gridptr->size;
 
   if ( CDI_Debug && size == 0 )
     Warning("Size undefined for gridID = %d", gridptr->self);
@@ -1424,16 +1418,16 @@ gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
   if ( mask_src )
     {
       if (mask && size > 0)
-        for (size_t i = 0; i < (size_t)size; ++i)
+        for (size_t i = 0; i < size; ++i)
           mask[i] = (int)mask_src[i];
     }
   else
     size = 0;
 
-  return (int)size;
+  return size;
 }
 
-static int
+static size_t
 gridInqMaskSerial(grid_t *gridptr, int *mask)
 {
   return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
@@ -1449,7 +1443,7 @@ int gridInqMask(int gridID, int *mask)
 static void
 gridDefMaskSerial(grid_t *gridptr, const int *mask)
 {
-  long size = gridptr->size;
+  size_t size = gridptr->size;
 
   if ( size == 0 )
     Error("Size undefined for gridID = %d", gridptr->self);
@@ -1465,11 +1459,11 @@ gridDefMaskSerial(grid_t *gridptr, const int *mask)
   else
     {
       if ( gridptr->mask == NULL )
-	gridptr->mask = (mask_t *) Malloc((size_t)size*sizeof(mask_t));
+	gridptr->mask = (mask_t *) Malloc(size*sizeof(mask_t));
       else if ( CDI_Debug )
 	Warning("grid mask already defined!");
 
-      for (long i = 0; i < size; ++i )
+      for (size_t i = 0; i < size; ++i )
 	gridptr->mask[i] = (mask_t)(mask[i] != 0);
     }
 }
@@ -1496,17 +1490,17 @@ int gridInqMaskGME(int gridID, int *mask)
 static void
 gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
 {
-  long size = gridptr->size;
+  size_t size = gridptr->size;
 
   if ( size == 0 )
     Error("Size undefined for gridID = %d", gridptr->self);
 
   if ( gridptr->mask_gme == NULL )
-    gridptr->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
+    gridptr->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
   else if ( CDI_Debug )
     Warning("mask already defined!");
 
-  for (long i = 0; i < size; ++i)
+  for (size_t i = 0; i < size; ++i)
     gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
 }
 
@@ -1518,9 +1512,9 @@ void gridDefMaskGME(int gridID, const int *mask)
 }
 
 static
-int gridInqXValsSerial(grid_t *gridptr, double *xvals)
+size_t gridInqXValsSerial(grid_t *gridptr, double *xvals)
 {
-  long size;
+  size_t size;
   if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
     size = gridptr->size;
   else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
@@ -1536,30 +1530,30 @@ int gridInqXValsSerial(grid_t *gridptr, double *xvals)
       if ( size && xvals )
         {
           const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
-          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
+          memcpy(xvals, gridptr_xvals, size * sizeof (double));
         }
     }
   else
     size = 0;
 
-  return (int)size;
+  return size;
 }
 
 static
-int gridInqXCvalsSerial(grid_t *gridptr, char **xcvals)
+size_t gridInqXCvalsSerial(grid_t *gridptr, char **xcvals)
 {
   if ( gridptr->type != GRID_CHARXY )
     Error("Function only valid for grid type 'GRID_CHARXY'.");
 
-  int size = gridptr->x.size;
-  int maxclength = 0;
+  size_t size = gridptr->x.size;
+  size_t maxclength = 0;
 
   const char **gridptr_xcvals = gridptr->vtable->inqXCvalsPtr(gridptr);
   if ( gridptr_xcvals && size && xcvals )
     {
       maxclength = gridptr->x.clength;
-      for ( int i = 0; i < size; i++ )
-        memcpy(xcvals[i], gridptr_xcvals[i], (size_t)maxclength*sizeof(char));
+      for ( size_t i = 0; i < size; i++ )
+        memcpy(xcvals[i], gridptr_xcvals[i], maxclength*sizeof(char));
     }
 
   return maxclength;
@@ -1580,7 +1574,7 @@ int gridInqXIscSerial(grid_t *gridptr)
 @Function  gridInqXvals
 @Title     Get all values of a X-axis
 
- at Prototype int gridInqXvals(int gridID, double *xvals)
+ at Prototype size_t gridInqXvals(int gridID, double *xvals)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
     @Item  xvals    Pointer to the location into which the X-values are read.
@@ -1596,14 +1590,14 @@ Otherwise, 0 is returned and @func{xvals} is empty.
 
 @EndFunction
 */
-int gridInqXvals(int gridID, double *xvals)
+size_t gridInqXvals(int gridID, double *xvals)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXVals(gridptr, xvals);
 }
 
 
-int gridInqXCvals(int gridID, char **xcvals)
+size_t gridInqXCvals(int gridID, char **xcvals)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXCvals(gridptr, xcvals);
@@ -1621,7 +1615,7 @@ void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
 {
   int gridtype = gridptr->type;
 
-  long size;
+  size_t size;
   if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
     size = gridptr->size;
   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
@@ -1635,25 +1629,25 @@ void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
   if (gridptr->x.vals && CDI_Debug)
     Warning("values already defined!");
   gridptr->x.vals = (double *)Realloc(gridptr->x.vals,
-                                      (size_t)size * sizeof(double));
-  memcpy(gridptr->x.vals, xvals, (size_t)size * sizeof (double));
+                                      size * sizeof(double));
+  memcpy(gridptr->x.vals, xvals, size * sizeof (double));
 }
 
 static
-int gridInqYCvalsSerial(grid_t *gridptr, char **ycvals)
+size_t gridInqYCvalsSerial(grid_t *gridptr, char **ycvals)
 {
   if ( gridptr->type != GRID_CHARXY )
     Error("Function only valid for grid type 'GRID_CHARXY'.");
 
-  int size = gridptr->y.size;
-  int maxclength = 0;
+  size_t size = gridptr->y.size;
+  size_t maxclength = 0;
 
   const char **gridptr_ycvals = gridptr->vtable->inqYCvalsPtr(gridptr);
   if ( gridptr_ycvals && size && ycvals )
     {
       maxclength = gridptr->y.clength;
-      for ( int i = 0; i < size; i++ )
-        memcpy(ycvals[i], gridptr_ycvals[i], (size_t)maxclength*sizeof(char));
+      for ( size_t i = 0; i < size; i++ )
+        memcpy(ycvals[i], gridptr_ycvals[i], maxclength*sizeof(char));
     }
 
   return maxclength;
@@ -1692,10 +1686,10 @@ void gridDefXvals(int gridID, const double *xvals)
 }
 
 static
-int gridInqYValsSerial(grid_t *gridptr, double *yvals)
+size_t gridInqYValsSerial(grid_t *gridptr, double *yvals)
 {
   int gridtype = gridptr->type;
-  long size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+  size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
             ? gridptr->size : gridptr->y.size;
 
   if ( CDI_Debug && size == 0 )
@@ -1706,20 +1700,20 @@ int gridInqYValsSerial(grid_t *gridptr, double *yvals)
       if ( size && yvals )
         {
           const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
-          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
+          memcpy(yvals, gridptr_yvals, size * sizeof (double));
         }
     }
   else
     size = 0;
 
-  return (int)size;
+  return size;
 }
 
 /*
 @Function  gridInqYvals
 @Title     Get all values of a Y-axis
 
- at Prototype int gridInqYvals(int gridID, double *yvals)
+ at Prototype size_t gridInqYvals(int gridID, double *yvals)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
     @Item  yvals    Pointer to the location into which the Y-values are read.
@@ -1735,14 +1729,14 @@ Otherwise, 0 is returned and @func{yvals} is empty.
 
 @EndFunction
 */
-int gridInqYvals(int gridID, double *yvals)
+size_t gridInqYvals(int gridID, double *yvals)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYVals(gridptr, yvals);
 }
 
 
-int gridInqYCvals(int gridID, char **ycvals)
+size_t gridInqYCvals(int gridID, char **ycvals)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYCvals(gridptr, ycvals);
@@ -1759,7 +1753,7 @@ static
 void gridDefYValsSerial(grid_t *gridptr, const double *yvals)
 {
   int gridtype = gridptr->type;
-  long size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+  size_t size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
             ? gridptr->size : gridptr->y.size;
 
   if ( size == 0 )
@@ -1768,8 +1762,8 @@ void gridDefYValsSerial(grid_t *gridptr, const double *yvals)
   if ( gridptr->y.vals && CDI_Debug )
     Warning("Values already defined!");
 
-  gridptr->y.vals = (double *)Realloc(gridptr->y.vals, (size_t)size * sizeof (double));
-  memcpy(gridptr->y.vals, yvals, (size_t)size * sizeof (double));
+  gridptr->y.vals = (double *)Realloc(gridptr->y.vals, size * sizeof (double));
+  memcpy(gridptr->y.vals, yvals, size * sizeof (double));
 }
 
 
@@ -1795,21 +1789,21 @@ void gridDefYvals(int gridID, const double *yvals)
 }
 
 static double
-gridInqXValSerial(grid_t *gridptr, int index)
+gridInqXValSerial(grid_t *gridptr, size_t index)
 {
   double xval = gridptr->x.vals ? gridptr->x.vals[index] : 0;
   return xval;
 }
 
 
-double gridInqXval(int gridID, int index)
+double gridInqXval(int gridID, size_t index)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXVal(gridptr, index);
 }
 
 static double
-gridInqYValSerial(grid_t *gridptr, int index)
+gridInqYValSerial(grid_t *gridptr, size_t index)
 {
   double yval = gridptr->y.vals ? gridptr->y.vals[index] : 0;
   return yval;
@@ -1825,7 +1819,7 @@ gridInqYValSerial(grid_t *gridptr, int index)
 
 @EndFunction
 */
-double gridInqYval(int gridID, int index)
+double gridInqYval(int gridID, size_t index)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYVal(gridptr, index);
@@ -1849,11 +1843,11 @@ double gridInqXinc(int gridID)
 
   if ( (! (fabs(xinc) > 0)) && xvals )
     {
-      int xsize = gridptr->x.size;
+      size_t xsize = gridptr->x.size;
       if ( xsize > 1 )
         {
           xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-          for ( int i = 2; i < xsize; i++ )
+          for ( size_t i = 2; i < xsize; i++ )
             if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
               {
                 xinc = 0;
@@ -1885,12 +1879,12 @@ double gridInqYinc(int gridID)
 
   if ( (! (fabs(yinc) > 0)) && yvals )
     {
-      int ysize = gridptr->y.size;
+      size_t ysize = gridptr->y.size;
       if ( ysize > 1 )
         {
           yinc = yvals[1] - yvals[0];
           double abs_yinc = fabs(yinc);
-          for ( size_t i = 2; i < (size_t)ysize; i++ )
+          for ( size_t i = 2; i < ysize; i++ )
             if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
               {
                 yinc = 0;
@@ -2047,8 +2041,8 @@ void grid_check_cyclic(grid_t *gridptr)
 {
   gridptr->isCyclic = 0;
   enum { numVertices = 4 };
-  size_t xsize = gridptr->x.size >= 0 ? (size_t)gridptr->x.size : 0,
-         ysize = gridptr->y.size >= 0 ? (size_t)gridptr->y.size : 0;
+  size_t xsize = gridptr->x.size,
+         ysize = gridptr->y.size;
   const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
                *yvals = gridptr->vtable->inqYValsPtr(gridptr),
     (*xbounds)[numVertices]
@@ -2162,13 +2156,13 @@ bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
 {
   bool differ = false;
 
-  int xsizeTest = gridTest->x.size, ysizeTest = gridTest->y.size;
+  size_t xsizeTest = gridTest->x.size, ysizeTest = gridTest->y.size;
   if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, NULL) )
     {
       const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
         *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
 
-      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
+      for ( size_t i = 0; i < xsizeTest; ++i )
 	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = true;
@@ -2180,7 +2174,7 @@ bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
     {
       const double *restrict yvalsRef = gridRef->vtable->inqYValsPtr(gridRef),
         *restrict yvalsTest = gridTest->vtable->inqYValsPtr(gridTest);
-      for ( size_t i = 0; i < (size_t)ysizeTest; ++i )
+      for ( size_t i = 0; i < ysizeTest; ++i )
 	if ( fabs(yvalsTest[i] - yvalsRef[i]) > 1.e-10 )
 	  {
 	    differ = true;
@@ -2194,11 +2188,11 @@ bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
 static
 bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
 {
-  int gridsize = gridTest->size;
+  size_t gridsize = gridTest->size;
   bool differ = ((gridTest->x.vals == NULL) ^ (gridRef->x.vals == NULL))
              || ((gridTest->y.vals == NULL) ^ (gridRef->y.vals == NULL));
 
-  typedef double (*inqVal)(grid_t *grid, int index);
+  typedef double (*inqVal)(grid_t *grid, size_t index);
   inqVal inqXValRef = gridRef->vtable->inqXVal,
          inqYValRef = gridRef->vtable->inqYVal,
          inqXValTest = gridTest->vtable->inqXVal,
@@ -2232,8 +2226,8 @@ bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
 	      printf("gridID      %d\n", gridID);
 	      printf("grid.xdef   %d\n", grid->x.flag);
 	      printf("grid.ydef   %d\n", grid->y.flag);
-	      printf("grid.xsize  %d\n", grid->x.size);
-	      printf("grid.ysize  %d\n", grid->y.size);
+	      printf("grid.xsize  %zu\n", grid->x.size);
+	      printf("grid.ysize  %zu\n", grid->y.size);
 	      printf("grid.xfirst %f\n", grid->x.first);
 	      printf("grid.yfirst %f\n", grid->y.first);
 	      printf("grid.xfirst %f\n", gridInqXval(gridID, 0));
@@ -2399,7 +2393,7 @@ int gridCompareP(void *gridptr1, void *gridptr2)
   grid_t *g2 = ( grid_t * ) gridptr2;
   enum { equal = 0,
          differ = -1 };
-  int i, size;
+  size_t i, size;
 
   xassert ( g1 );
   xassert ( g2 );
@@ -2545,7 +2539,7 @@ int gridCompareP(void *gridptr1, void *gridptr2)
     {
       xassert ( g1->size );
       if ( !g2->mask ) return differ;
-      if ( memcmp ( g1->mask, g2->mask, (size_t)g1->size * sizeof(mask_t)) ) return differ;
+      if ( memcmp ( g1->mask, g2->mask, g1->size * sizeof(mask_t)) ) return differ;
     }
   else if ( g2->mask )
     return differ;
@@ -2554,7 +2548,7 @@ int gridCompareP(void *gridptr1, void *gridptr2)
     {
       xassert ( g1->size );
       if ( !g2->mask_gme ) return differ;
-      if ( memcmp ( g1->mask_gme, g2->mask_gme, (size_t)g1->size * sizeof(mask_t)) ) return differ;
+      if ( memcmp ( g1->mask_gme, g2->mask_gme, g1->size * sizeof(mask_t)) ) return differ;
     }
   else if ( g2->mask_gme )
     return differ;
@@ -2593,7 +2587,7 @@ void gridComplete(grid_t *grid)
 	if ( grid->x.flag == 2 )
 	  {
             assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
-	    double *xvals = (double *) Malloc((size_t)grid->x.size * sizeof (double));
+	    double *xvals = (double *) Malloc(grid->x.size * sizeof (double));
 	    gridGenXvals(grid->x.size, grid->x.first, grid->x.last, grid->x.inc, xvals);
 	    grid->x.vals = xvals;
 	    // gridDefXinc(gridID, grid->x.inc);
@@ -2602,7 +2596,7 @@ void gridComplete(grid_t *grid)
 	if ( grid->y.flag == 2 )
 	  {
             assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
-	    double *yvals = (double *) Malloc((size_t)grid->y.size * sizeof (double));
+	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
 	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
 	    grid->y.vals = yvals;
 	    // gridDefYinc(gridID, grid->y.inc);
@@ -2642,7 +2636,7 @@ void gridComplete(grid_t *grid)
 
         if ( grid->y.flag == 2 )
 	  {
-	    double *yvals = (double *) Malloc((size_t)grid->y.size * sizeof (double));
+	    double *yvals = (double *) Malloc(grid->y.size * sizeof (double));
 	    gridGenYvals(gridtype, grid->y.size, grid->y.first, grid->y.last, grid->y.inc, yvals);
             grid->y.vals = yvals;
 	    /*
@@ -2779,7 +2773,7 @@ static void
 grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
   size_t nrowlon = (size_t)gridptrOrig->nrowlon;
-  size_t gridsize = (size_t)gridptrOrig->size;
+  size_t gridsize = gridptrOrig->size;
   int gridtype = gridptrOrig->type;
   int irregular = gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED;
   if ( nrowlon )
@@ -2790,7 +2784,7 @@ grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 
   if ( gridptrOrig->x.vals != NULL )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
+      size_t size = irregular ? gridsize : gridptrOrig->x.size;
 
       gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
       memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
@@ -2798,7 +2792,7 @@ grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 
   if ( gridptrOrig->y.vals != NULL )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->y.size;
+      size_t size  = irregular ? gridsize : gridptrOrig->y.size;
 
       gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
       memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
@@ -2806,8 +2800,8 @@ grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 
   if ( gridptrOrig->x.bounds != NULL )
     {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->x.size)
-        * (size_t)gridptrOrig->nvertex;
+      size_t size  = (irregular ? gridsize : gridptrOrig->x.size)
+        * gridptrOrig->nvertex;
 
       gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
       memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
@@ -2815,8 +2809,8 @@ grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 
   if ( gridptrOrig->y.bounds != NULL )
     {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
-        * (size_t)gridptrOrig->nvertex;
+      size_t size = (irregular ? gridsize : gridptrOrig->y.size)
+        * gridptrOrig->nvertex;
 
       gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
       memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
@@ -2887,7 +2881,7 @@ void gridCompress(int gridID)
     {
       if ( gridptr->mask_gme != NULL )
 	{
-          size_t gridsize = (size_t)gridInqSize(gridID);
+          size_t gridsize = gridInqSize(gridID);
 	  size_t nv = (size_t)gridptr->nvertex;
           double *restrict area
             = (double *)gridptr->vtable->inqAreaPtr(gridptr),
@@ -2951,7 +2945,7 @@ void gridCompress(int gridID)
 static void
 gridDefAreaSerial(grid_t *gridptr, const double *area)
 {
-  size_t size = (size_t)gridptr->size;
+  size_t size = gridptr->size;
 
   if ( size == 0 )
     Error("size undefined for gridID = %d", gridptr->self);
@@ -2976,7 +2970,7 @@ static void
 gridInqAreaSerial(grid_t *gridptr, double *area)
 {
   if (gridptr->area)
-    memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
+    memcpy(area, gridptr->area, gridptr->size * sizeof (double));
 }
 
 
@@ -3030,7 +3024,7 @@ int gridInqNvertex(int gridID)
 }
 
 static void
-gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
+gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, size_t regularSize,
                      double **field)
 {
   int irregular = gridptr->type == GRID_CURVILINEAR
@@ -3042,7 +3036,7 @@ gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
               gridptr->self);
       return;
     }
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : regularSize);
+  size_t size = nvertex * (irregular ? gridptr->size : regularSize);
   if ( size == 0 )
     Error("size undefined for gridID = %d", gridptr->self);
 
@@ -3082,14 +3076,14 @@ void gridDefXbounds(int gridID, const double *xbounds)
   gridMark4Update(gridID);
 }
 
-static int
+static size_t
 gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
 {
   size_t nvertex = (size_t)gridptr->nvertex;
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->x.size);
+  size_t size = nvertex * (irregular ? gridptr->size : gridptr->x.size);
 
   const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
   if ( gridptr_xbounds )
@@ -3100,14 +3094,14 @@ gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
   else
     size = 0;
 
-  return (int)size;
+  return size;
 }
 
 /*
 @Function  gridInqXbounds
 @Title     Get the bounds of a X-axis
 
- at Prototype int gridInqXbounds(int gridID, double *xbounds)
+ at Prototype size_t gridInqXbounds(int gridID, double *xbounds)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
     @Item  xbounds  Pointer to the location into which the X-bounds are read.
@@ -3123,7 +3117,7 @@ Otherwise, 0 is returned and @func{xbounds} is empty.
 
 @EndFunction
 */
-int gridInqXbounds(int gridID, double *xbounds)
+size_t gridInqXbounds(int gridID, double *xbounds)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXBounds(gridptr, xbounds);
@@ -3169,14 +3163,14 @@ void gridDefYbounds(int gridID, const double *ybounds)
   gridMark4Update(gridID);
 }
 
-static int
+static size_t
 gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
 {
   size_t nvertex = (size_t)gridptr->nvertex;
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->y.size);
+  size_t size = nvertex * (irregular ? gridptr->size : gridptr->y.size);
 
   const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
   if ( gridptr_ybounds )
@@ -3187,7 +3181,7 @@ gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
   else
     size = 0;
 
-  return (int)size;
+  return size;
 }
 
 
@@ -3195,7 +3189,7 @@ gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
 @Function  gridInqYbounds
 @Title     Get the bounds of a Y-axis
 
- at Prototype int gridInqYbounds(int gridID, double *ybounds)
+ at Prototype size_t gridInqYbounds(int gridID, double *ybounds)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
     @Item  ybounds  Pointer to the location into which the Y-bounds are read.
@@ -3211,7 +3205,7 @@ Otherwise, 0 is returned and @func{ybounds} is empty.
 
 @EndFunction
 */
-int gridInqYbounds(int gridID, double *ybounds)
+size_t gridInqYbounds(int gridID, double *ybounds)
 {
   grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYBounds(gridptr, ybounds);
@@ -3275,7 +3269,7 @@ printBounds(FILE *fp, int dig, const char prefix[], size_t nbyte0,
     {
       for ( size_t iv = 0; iv < nvertex; iv++ )
         fprintf(fp, "%.*g ", dig, bounds[iv]);
-      for ( size_t i = 1; i < (size_t)n; i++ )
+      for ( size_t i = 1; i < n; i++ )
         {
           fprintf(fp, "\n%*s", (int)nbyte0, "");
           for ( size_t iv = 0; iv < nvertex; iv++ )
@@ -3382,15 +3376,15 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
   unsigned char uuidOfHGrid[CDI_UUID_SIZE];
   const char  **xcvals  = gridInqXCvalsPtr(gridID);
   const char  **ycvals  = gridInqYCvalsPtr(gridID);
-  size_t nxvals = (size_t) gridInqXvals(gridID, NULL);
-  size_t nyvals = (size_t) gridInqYvals(gridID, NULL);
-  size_t nxbounds = (size_t) gridInqXbounds(gridID, NULL);
-  size_t nybounds = (size_t) gridInqYbounds(gridID, NULL);
+  size_t nxvals = gridInqXvals(gridID, NULL);
+  size_t nyvals = gridInqYvals(gridID, NULL);
+  size_t nxbounds = gridInqXbounds(gridID, NULL);
+  size_t nybounds = gridInqYbounds(gridID, NULL);
 
   int type     = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
-  int xsize    = gridInqXsize(gridID);
-  int ysize    = gridInqYsize(gridID);
+  size_t gridsize = gridInqSize(gridID);
+  size_t xsize    = gridInqXsize(gridID);
+  size_t ysize    = gridInqYsize(gridID);
   int xstrlen  = gridInqXIsc(gridID);
   int ystrlen  = gridInqYIsc(gridID);
   int nvertex  = gridInqNvertex(gridID);
@@ -3398,14 +3392,14 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
 
   int dig = (datatype == CDI_DATATYPE_FLT64) ? 15 : 7;
 
-  fprintf(fp, "gridtype  = %s\n" "gridsize  = %d\n", gridNamePtr(type), gridsize);
+  fprintf(fp, "gridtype  = %s\n" "gridsize  = %zu\n", gridNamePtr(type), gridsize);
 
   if ( type != GRID_GME )
     {
       if ( type != GRID_UNSTRUCTURED && type != GRID_SPECTRAL && type != GRID_FOURIER )
         {
-          if ( xsize > 0 ) fprintf(fp, "xsize     = %d\n", xsize);
-          if ( ysize > 0 ) fprintf(fp, "ysize     = %d\n", ysize);
+          if ( xsize > 0 ) fprintf(fp, "xsize     = %zu\n", xsize);
+          if ( ysize > 0 ) fprintf(fp, "ysize     = %zu\n", ysize);
         }
 
       if ( nxvals > 0 || xcvals )
@@ -3457,18 +3451,18 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
 
 	if ( type == GRID_CURVILINEAR || type == GRID_UNSTRUCTURED )
 	  {
-	    xdimLen = (size_t)gridsize;
-	    ydimLen = (size_t)gridsize;
+	    xdimLen = gridsize;
+	    ydimLen = gridsize;
 	  }
         else if ( type == GRID_GAUSSIAN_REDUCED )
           {
 	    xdimLen = 2;
-	    ydimLen = (size_t)ysize;
+	    ydimLen = ysize;
           }
 	else
 	  {
-	    xdimLen = (size_t)xsize;
-	    ydimLen = (size_t)ysize;
+	    xdimLen = xsize;
+	    ydimLen = ysize;
 	  }
 
 	if ( type == GRID_UNSTRUCTURED )
@@ -3529,7 +3523,7 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
               fprintf(fp, "x%ss = %.*s\n", attstr, xstrlen, xcvals[0]);
             else
               fprintf(fp, "xstrings  = %.*s\n", xstrlen, xcvals[0]);
-            for ( int i = 1; i < xsize; i++ )
+            for ( size_t i = 1; i < xsize; i++ )
               fprintf(fp, "          = %.*s\n", xstrlen, xcvals[i]);
           }
 
@@ -3575,7 +3569,7 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
               fprintf(fp, "x%ss = %.*s\n", attstr, ystrlen, ycvals[0]);
             else
               fprintf(fp, "ystrings  = %.*s\n", ystrlen, ycvals[0]);
-            for ( int i = 1; i < ysize; i++ )
+            for ( size_t i = 1; i < ysize; i++ )
               fprintf(fp, "          = %.*s\n", ystrlen, ycvals[i]);
           }
 
@@ -3590,20 +3584,20 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
 
 	if ( gridHasArea(gridID) )
 	  {
-            double *area = (double*) Malloc((size_t)gridsize*sizeof(double));
+            double *area = (double*) Malloc(gridsize*sizeof(double));
             gridInqArea(gridID, area);
             static const char prefix[] = "area      = ";
-            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, (size_t)gridsize, area);
+            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, gridsize, area);
             Free(area);
 	  }
 
         if ( type == GRID_GAUSSIAN_REDUCED )
           {
             static const char prefix[] = "rowlon    = ";
-            int *rowlon = (int *)Malloc((size_t)ysize*sizeof(int));
+            int *rowlon = (int *)Malloc(ysize*sizeof(int));
             gridInqRowlon(gridID, rowlon);
             printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
-                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
+                                   (ysize > 0 ? ysize : 0), rowlon);
             Free(rowlon);
           }
 
@@ -3647,11 +3641,11 @@ void gridPrintKernel(int gridID, int opt, FILE *fp)
 
   if ( gridInqMask(gridID, NULL) )
     {
-      int *mask = (gridsize>0) ? (int*) Malloc((size_t)gridsize*sizeof(int)) : NULL;
+      int *mask = (gridsize>0) ? (int*) Malloc(gridsize*sizeof(int)) : NULL;
       gridInqMask(gridID, mask);
       static const char prefix[] = "mask      = ";
       printMask(fp, prefix, sizeof(prefix)-1,
-                (size_t)(gridsize > 0 ? gridsize : 0), mask);
+                (gridsize > 0 ? gridsize : 0), mask);
       if ( mask ) Free(mask);
     }
 }
@@ -3697,12 +3691,12 @@ void gridPrintP(void *voidptr, FILE *fp)
 
   if ( gridInqMaskGME(gridID, NULL) )
     {
-      int gridsize = gridptr->size;
-      int *mask = (gridsize>0) ? (int*) Malloc((size_t)gridsize*sizeof(int)) : NULL;
+      size_t gridsize = gridptr->size;
+      int *mask = (gridsize>0) ? (int*) Malloc(gridsize*sizeof(int)) : NULL;
       gridInqMaskGME(gridID, mask);
       static const char prefix[] = "mask_gme  = ";
       printMask(fp, prefix, sizeof(prefix)-1,
-                (size_t)(gridptr->size > 0 ? gridptr->size : 0), mask);
+                (gridptr->size > 0 ? gridptr->size : 0), mask);
       if ( mask ) Free(mask);
     }
 }
@@ -4475,13 +4469,13 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     gridP->y.inc = doubleBuffer[GRID_PACK_DBL_IDX_Y_INC];
   }
 
-  int irregular = gridP->type == GRID_UNSTRUCTURED
+  bool irregular = gridP->type == GRID_UNSTRUCTURED
     || gridP->type == GRID_CURVILINEAR;
   if (memberMask & gridHasXValsFlag)
     {
       size = irregular ? gridP->size : gridP->x.size;
 
-      gridP->x.vals = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->x.vals = (double *) Malloc(size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->x.vals, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4493,7 +4487,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     {
       size = irregular ? gridP->size : gridP->y.size;
 
-      gridP->y.vals = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->y.vals = (double *) Malloc(size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->y.vals, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4505,7 +4499,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     {
       size = gridP->size;
       xassert(size);
-      gridP->area = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->area = (double *) Malloc(size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->area, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4518,7 +4512,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       size = gridP->nvertex * (irregular ? gridP->size : gridP->x.size);
       xassert(size);
 
-      gridP->x.bounds = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->x.bounds = (double *) Malloc(size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->x.bounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4531,7 +4525,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       size = gridP->nvertex * (irregular ? gridP->size : gridP->y.size);
       xassert(size);
 
-      gridP->y.bounds = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->y.bounds = (double *) Malloc(size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
 			  gridP->y.bounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4551,7 +4545,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       int referenceSize;
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       &referenceSize, 1, CDI_DATATYPE_INT, context);
-      gridP->reference = (char *) Malloc((size_t)referenceSize);
+      gridP->reference = (char *) Malloc(referenceSize);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->reference, referenceSize, CDI_DATATYPE_TXT, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4562,7 +4556,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
   if (memberMask & gridHasMaskFlag)
     {
       xassert((size = gridP->size));
-      gridP->mask = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
+      gridP->mask = (mask_t *) Malloc(size * sizeof (mask_t));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->mask, gridP->size, CDI_DATATYPE_UCHAR, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
@@ -4573,7 +4567,7 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
   if (memberMask & gridHasGMEMaskFlag)
     {
       xassert((size = gridP->size));
-      gridP->mask_gme = (mask_t *) Malloc((size_t)size * sizeof (mask_t));
+      gridP->mask_gme = (mask_t *) Malloc(size * sizeof (mask_t));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
                       gridP->mask_gme, gridP->size, CDI_DATATYPE_UCHAR, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
diff --git a/libcdi/src/grid.h b/libcdi/src/grid.h
index 65618ee..770cd5e 100644
--- a/libcdi/src/grid.h
+++ b/libcdi/src/grid.h
@@ -27,13 +27,13 @@ struct gridVirtTable
   void (*defXBounds)(grid_t *gridptr, const double *xbounds);
   void (*defYBounds)(grid_t *gridptr, const double *ybounds);
   void (*defArea)(grid_t *gridptr, const double *area);
-  double (*inqXVal)(grid_t *gridptr, int index);
-  double (*inqYVal)(grid_t *gridptr, int index);
-  int (*inqXVals)(grid_t *gridptr, double *xvals);
-  int (*inqXCvals)(grid_t *gridptr, char **xcvals);
+  double (*inqXVal)(grid_t *gridptr, size_t index);
+  double (*inqYVal)(grid_t *gridptr, size_t index);
+  size_t (*inqXVals)(grid_t *gridptr, double *xvals);
+  size_t (*inqXCvals)(grid_t *gridptr, char **xcvals);
   int (*inqXIsc)(grid_t *gridptr);
-  int (*inqYVals)(grid_t *gridptr, double *yvals);
-  int (*inqYCvals)(grid_t *gridptr, char **ycvals);
+  size_t (*inqYVals)(grid_t *gridptr, double *yvals);
+  size_t (*inqYCvals)(grid_t *gridptr, char **ycvals);
   int (*inqYIsc)(grid_t *gridptr);
   const double *(*inqXValsPtr)(grid_t *gridptr);
   const char **(*inqXCvalsPtr)(grid_t *gridptr);
@@ -47,10 +47,10 @@ struct gridVirtTable
   void (*inqArea)(grid_t *gridptr, double *area);
   const double *(*inqAreaPtr)(grid_t *gridptr);
   int (*hasArea)(grid_t *gridptr);
-  int (*inqMask)(grid_t *gridptr, int *mask);
+  size_t (*inqMask)(grid_t *gridptr, int *mask);
   int (*inqMaskGME)(grid_t *gridptr, int *mask_gme);
-  int (*inqXBounds)(grid_t *gridptr, double *xbounds);
-  int (*inqYBounds)(grid_t *gridptr, double *ybounds);
+  size_t (*inqXBounds)(grid_t *gridptr, double *xbounds);
+  size_t (*inqYBounds)(grid_t *gridptr, double *ybounds);
   const double *(*inqXBoundsPtr)(grid_t *gridptr);
   const double *(*inqYBoundsPtr)(grid_t *gridptr);
 };
@@ -61,7 +61,7 @@ struct gridaxis_t {
   char    units[CDI_MAX_NAME];
   char    dimname[CDI_MAX_NAME];
   const char *stdname;
-  int     size;                  // number of values
+  size_t  size;                  // number of values
   short   flag;                  // 0: undefined 1:vals 2:first+inc
   double  first, last, inc;
   double *vals;
@@ -81,7 +81,7 @@ struct grid_t {
   char    mapping[CDI_MAX_NAME];
   char   *name;
   int     self;
-  int     size;
+  size_t  size;
   int     type;                   /* grid type                      */
   int     datatype;               /* grid data type                 */
   int     proj;                   /* grid projection                */
@@ -122,7 +122,7 @@ struct grid_t {
 
 
 void grid_init(grid_t *gridptr);
-void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, size_t size);
 void grid_free(grid_t *gridptr);
 grid_t *grid_to_pointer(int gridID);
 extern const struct gridVirtTable cdiGridVtable;
diff --git a/libcdi/src/iterator_fallback.c b/libcdi/src/iterator_fallback.c
index 03749a3..6ee0167 100644
--- a/libcdi/src/iterator_fallback.c
+++ b/libcdi/src/iterator_fallback.c
@@ -378,7 +378,7 @@ char *cdiFallbackIterator_copyVariableName(CdiIterator *super)
 void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int missingValues = 0;
+  size_t missingValues = 0;
   streamReadVarSlice(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
   if(nmiss) *nmiss = (size_t)missingValues;
 }
@@ -386,7 +386,7 @@ void cdiFallbackIterator_readField(CdiIterator *super, double *buffer, size_t *n
 void cdiFallbackIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
 {
   CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  int missingValues = 0;
+  size_t missingValues = 0;
   streamReadVarSliceF(me->streamId, me->curVariable, me->curLevel, buffer, &missingValues);
   if(nmiss) *nmiss = (size_t)missingValues;
 }
diff --git a/libcdi/src/mo_cdi.f90 b/libcdi/src/mo_cdi.f90
index c126d09..5993554 100644
--- a/libcdi/src/mo_cdi.f90
+++ b/libcdi/src/mo_cdi.f90
@@ -1,6 +1,6 @@
 ! >>> Warning: This is a generated file. If you modify it, you get what you deserve. <<<
 !
-! Generated by "../../../../libcdi/interfaces/f2003/bindGen.rb" from input file "../../../../libcdi/src/cdi.h".
+! Generated by "../../../interfaces/f2003/bindGen.rb" from input file "../../../src/cdi.h".
 
 module mo_cdi
   use iso_c_binding
@@ -49,10 +49,9 @@ module mo_cdi
   integer(c_int), public, parameter :: CDI_FILETYPE_NC2 = 4
   integer(c_int), public, parameter :: CDI_FILETYPE_NC4 = 5
   integer(c_int), public, parameter :: CDI_FILETYPE_NC4C = 6
-  integer(c_int), public, parameter :: CDI_FILETYPE_NC5 = 7
-  integer(c_int), public, parameter :: CDI_FILETYPE_SRV = 8
-  integer(c_int), public, parameter :: CDI_FILETYPE_EXT = 9
-  integer(c_int), public, parameter :: CDI_FILETYPE_IEG = 10
+  integer(c_int), public, parameter :: CDI_FILETYPE_SRV = 7
+  integer(c_int), public, parameter :: CDI_FILETYPE_EXT = 8
+  integer(c_int), public, parameter :: CDI_FILETYPE_IEG = 9
   integer(c_int), public, parameter :: FILETYPE_GRB = 1
   integer(c_int), public, parameter :: FILETYPE_GRB2 = 2
   integer(c_int), public, parameter :: FILETYPE_NC = 3
@@ -179,8 +178,8 @@ module mo_cdi
   integer(c_int), public, parameter :: ZAXIS_CHAR = 26
   integer(c_int), public, parameter :: MAX_KV_PAIRS_MATCH = 10
   integer(c_int), public, parameter :: TIME_CONSTANT = 0
-  integer(c_int), public, parameter :: TIME_VARYING = 1
   integer(c_int), public, parameter :: TIME_VARIABLE = 1
+  integer(c_int), public, parameter :: TSTEP_CONSTANT = 0
   integer(c_int), public, parameter :: TSTEP_INSTANT = 1
   integer(c_int), public, parameter :: TSTEP_AVG = 2
   integer(c_int), public, parameter :: TSTEP_ACCUM = 3
@@ -273,6 +272,7 @@ module mo_cdi
   public :: streamInqCurTimestepID
   public :: streamFilename
   public :: streamFilesuffix
+  public :: streamNvals
   public :: streamInqNvars
   public :: streamWriteVar
   public :: streamWriteVarF
@@ -372,8 +372,6 @@ module mo_cdi
   public :: vlistInqVarGrid
   public :: vlistInqVarZaxis
   public :: vlistInqVarID
-  public :: vlistDefVarTimetype
-  public :: vlistInqVarTimetype
   public :: vlistDefVarTsteptype
   public :: vlistInqVarTsteptype
   public :: vlistDefVarCompType
@@ -622,7 +620,6 @@ module mo_cdi
   public :: taxisInqFdate
   public :: taxisInqFtime
   public :: taxisHasBounds
-  public :: taxisWithBounds
   public :: taxisDeleteBounds
   public :: taxisDefVdateBounds
   public :: taxisDefVtimeBounds
@@ -877,6 +874,13 @@ module mo_cdi
       integer(c_int) :: f_result
     end function streamInqCurTimestepID
 
+    function streamNvals(streamID_dummy) bind(c, name = 'streamNvals')&
+    & result(f_result)
+      import c_int, c_size_t
+      integer(c_int), value :: streamID_dummy
+      integer(c_size_t) :: f_result
+    end function streamNvals
+
     function streamInqNvars(streamID_dummy) bind(c, name = 'streamInqNvars')&
     & result(f_result)
       import c_int
@@ -886,88 +890,88 @@ module mo_cdi
 
     subroutine streamWriteVar(streamID_dummy, varID_dummy, data_dummy,&
     & nmiss_dummy) bind(c, name = 'streamWriteVar')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       real(c_double), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteVar
 
     subroutine streamWriteVarF(streamID_dummy, varID_dummy, data_dummy,&
     & nmiss_dummy) bind(c, name = 'streamWriteVarF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       real(c_float), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteVarF
 
     subroutine streamReadVar(streamID_dummy, varID_dummy, data_dummy,&
     & nmiss_dummy) bind(c, name = 'streamReadVar')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       real(c_double), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadVar
 
     subroutine streamReadVarF(streamID_dummy, varID_dummy, data_dummy,&
     & nmiss_dummy) bind(c, name = 'streamReadVarF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       real(c_float), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadVarF
 
     subroutine streamWriteVarSlice(streamID_dummy, varID_dummy, levelID_dummy,&
     & data_dummy, nmiss_dummy) bind(c, name = 'streamWriteVarSlice')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), value :: levelID_dummy
       real(c_double), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteVarSlice
 
     subroutine streamWriteVarSliceF(streamID_dummy, varID_dummy, levelID_dummy,&
     & data_dummy, nmiss_dummy) bind(c, name = 'streamWriteVarSliceF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), value :: levelID_dummy
       real(c_float), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteVarSliceF
 
     subroutine streamReadVarSlice(streamID_dummy, varID_dummy, levelID_dummy,&
     & data_dummy, nmiss_dummy) bind(c, name = 'streamReadVarSlice')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), value :: levelID_dummy
       real(c_double), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadVarSlice
 
     subroutine streamReadVarSliceF(streamID_dummy, varID_dummy, levelID_dummy,&
     & data_dummy, nmiss_dummy) bind(c, name = 'streamReadVarSliceF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), value :: levelID_dummy
       real(c_float), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadVarSliceF
 
     subroutine streamWriteVarChunk(streamID_dummy, varID_dummy, rect_dummy,&
     & data_dummy, nmiss_dummy) bind(c, name = 'streamWriteVarChunk')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), intent(in) :: rect_dummy(2, 3)
       real(c_double), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteVarChunk
 
     subroutine streamDefRecord(streamID_dummy, varID_dummy, levelID_dummy)&
@@ -988,34 +992,34 @@ module mo_cdi
 
     subroutine streamWriteRecord(streamID_dummy, data_dummy, nmiss_dummy)&
     & bind(c, name = 'streamWriteRecord')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       real(c_double), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteRecord
 
     subroutine streamWriteRecordF(streamID_dummy, data_dummy, nmiss_dummy)&
     & bind(c, name = 'streamWriteRecordF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       real(c_float), intent(in) :: data_dummy(*)
-      integer(c_int), value :: nmiss_dummy
+      integer(c_size_t), value :: nmiss_dummy
     end subroutine streamWriteRecordF
 
     subroutine streamReadRecord(streamID_dummy, data_dummy, nmiss_dummy)&
     & bind(c, name = 'streamReadRecord')
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       real(c_double), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadRecord
 
     subroutine streamReadRecordF(streamID_dummy, data_dummy, nmiss_dummy)&
     & bind(c, name = 'streamReadRecordF')
-      import c_float, c_int
+      import c_float, c_int, c_size_t
       integer(c_int), value :: streamID_dummy
       real(c_float), intent(inout) :: data_dummy(*)
-      integer(c_int), intent(inout) :: nmiss_dummy
+      integer(c_size_t), intent(inout) :: nmiss_dummy
     end subroutine streamReadRecordF
 
     subroutine streamCopyRecord(streamIDdest_dummy, streamIDsrc_dummy) bind(c,&
@@ -1131,9 +1135,9 @@ module mo_cdi
 
     function vlistGridsizeMax(vlistID_dummy) bind(c, name = 'vlistGridsizeMax')&
     & result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: vlistID_dummy
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function vlistGridsizeMax
 
     function vlistGrid(vlistID_dummy, index_dummy) bind(c, name = 'vlistGrid')&
@@ -1280,24 +1284,24 @@ module mo_cdi
     end function vlistInqModel
 
     function vlistDefVarTiles(vlistID_dummy, gridID_dummy, zaxisID_dummy,&
-    & timetype_dummy, tilesetID_dummy) bind(c, name = 'vlistDefVarTiles')&
+    & tsteptype_dummy, tilesetID_dummy) bind(c, name = 'vlistDefVarTiles')&
     & result(f_result)
       import c_int
       integer(c_int), value :: vlistID_dummy
       integer(c_int), value :: gridID_dummy
       integer(c_int), value :: zaxisID_dummy
-      integer(c_int), value :: timetype_dummy
+      integer(c_int), value :: tsteptype_dummy
       integer(c_int), value :: tilesetID_dummy
       integer(c_int) :: f_result
     end function vlistDefVarTiles
 
     function vlistDefVar(vlistID_dummy, gridID_dummy, zaxisID_dummy,&
-    & timetype_dummy) bind(c, name = 'vlistDefVar') result(f_result)
+    & tsteptype_dummy) bind(c, name = 'vlistDefVar') result(f_result)
       import c_int
       integer(c_int), value :: vlistID_dummy
       integer(c_int), value :: gridID_dummy
       integer(c_int), value :: zaxisID_dummy
-      integer(c_int), value :: timetype_dummy
+      integer(c_int), value :: tsteptype_dummy
       integer(c_int) :: f_result
     end function vlistDefVar
 
@@ -1318,13 +1322,13 @@ module mo_cdi
     end subroutine vlistChangeVarZaxis
 
     subroutine vlistInqVar(vlistID_dummy, varID_dummy, gridID_dummy,&
-    & zaxisID_dummy, timetype_dummy) bind(c, name = 'vlistInqVar')
+    & zaxisID_dummy, tsteptype_dummy) bind(c, name = 'vlistInqVar')
       import c_int
       integer(c_int), value :: vlistID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), intent(inout) :: gridID_dummy
       integer(c_int), intent(inout) :: zaxisID_dummy
-      integer(c_int), intent(inout) :: timetype_dummy
+      integer(c_int), intent(inout) :: tsteptype_dummy
     end subroutine vlistInqVar
 
     function vlistInqVarGrid(vlistID_dummy, varID_dummy) bind(c, name =&
@@ -1351,22 +1355,6 @@ module mo_cdi
       integer(c_int) :: f_result
     end function vlistInqVarID
 
-    subroutine vlistDefVarTimetype(vlistID_dummy, varID_dummy, timetype_dummy)&
-    & bind(c, name = 'vlistDefVarTimetype')
-      import c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      integer(c_int), value :: timetype_dummy
-    end subroutine vlistDefVarTimetype
-
-    function vlistInqVarTimetype(vlistID_dummy, varID_dummy) bind(c, name =&
-    & 'vlistInqVarTimetype') result(f_result)
-      import c_int
-      integer(c_int), value :: vlistID_dummy
-      integer(c_int), value :: varID_dummy
-      integer(c_int) :: f_result
-    end function vlistInqVarTimetype
-
     subroutine vlistDefVarTsteptype(vlistID_dummy, varID_dummy,&
     & tsteptype_dummy) bind(c, name = 'vlistDefVarTsteptype')
       import c_int
@@ -1667,10 +1655,10 @@ module mo_cdi
 
     function vlistInqVarSize(vlistID_dummy, varID_dummy) bind(c, name =&
     & 'vlistInqVarSize') result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: vlistID_dummy
       integer(c_int), value :: varID_dummy
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function vlistInqVarSize
 
     subroutine vlistDefIndex(vlistID_dummy, varID_dummy, levID_dummy,&
@@ -1832,9 +1820,9 @@ module mo_cdi
 
     function gridCreate(gridtype_dummy, size_dummy) bind(c, name =&
     & 'gridCreate') result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridtype_dummy
-      integer(c_int), value :: size_dummy
+      integer(c_size_t), value :: size_dummy
       integer(c_int) :: f_result
     end function gridCreate
 
@@ -1880,37 +1868,37 @@ module mo_cdi
 
     function gridInqSize(gridID_dummy) bind(c, name = 'gridInqSize')&
     & result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqSize
 
     subroutine gridDefXsize(gridID_dummy, xsize_dummy) bind(c, name =&
     & 'gridDefXsize')
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: xsize_dummy
+      integer(c_size_t), value :: xsize_dummy
     end subroutine gridDefXsize
 
     function gridInqXsize(gridID_dummy) bind(c, name = 'gridInqXsize')&
     & result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqXsize
 
     subroutine gridDefYsize(gridID_dummy, ysize_dummy) bind(c, name =&
     & 'gridDefYsize')
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: ysize_dummy
+      integer(c_size_t), value :: ysize_dummy
     end subroutine gridDefYsize
 
     function gridInqYsize(gridID_dummy) bind(c, name = 'gridInqYsize')&
     & result(f_result)
-      import c_int
+      import c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqYsize
 
     subroutine gridDefNP(gridID_dummy, np_dummy) bind(c, name = 'gridDefNP')
@@ -1935,10 +1923,10 @@ module mo_cdi
 
     function gridInqXvals(gridID_dummy, xvals_dummy) bind(c, name =&
     & 'gridInqXvals') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
       real(c_double), intent(inout) :: xvals_dummy(*)
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqXvals
 
     function gridInqXIsc(gridID_dummy) bind(c, name = 'gridInqXIsc')&
@@ -1957,10 +1945,10 @@ module mo_cdi
 
     function gridInqYvals(gridID_dummy, yvals_dummy) bind(c, name =&
     & 'gridInqYvals') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
       real(c_double), intent(inout) :: yvals_dummy(*)
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqYvals
 
     function gridInqYIsc(gridID_dummy) bind(c, name = 'gridInqYIsc')&
@@ -2004,17 +1992,17 @@ module mo_cdi
 
     function gridInqXval(gridID_dummy, index_dummy) bind(c, name =&
     & 'gridInqXval') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: index_dummy
+      integer(c_size_t), value :: index_dummy
       real(c_double) :: f_result
     end function gridInqXval
 
     function gridInqYval(gridID_dummy, index_dummy) bind(c, name =&
     & 'gridInqYval') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: index_dummy
+      integer(c_size_t), value :: index_dummy
       real(c_double) :: f_result
     end function gridInqYval
 
@@ -2215,10 +2203,10 @@ module mo_cdi
 
     function gridInqXbounds(gridID_dummy, xbounds_dummy) bind(c, name =&
     & 'gridInqXbounds') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
       real(c_double), intent(inout) :: xbounds_dummy(*)
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqXbounds
 
     subroutine gridDefYbounds(gridID_dummy, ybounds_dummy) bind(c, name =&
@@ -2230,10 +2218,10 @@ module mo_cdi
 
     function gridInqYbounds(gridID_dummy, ybounds_dummy) bind(c, name =&
     & 'gridInqYbounds') result(f_result)
-      import c_double, c_int
+      import c_double, c_int, c_size_t
       integer(c_int), value :: gridID_dummy
       real(c_double), intent(inout) :: ybounds_dummy(*)
-      integer(c_int) :: f_result
+      integer(c_size_t) :: f_result
     end function gridInqYbounds
 
     subroutine gridDefRowlon(gridID_dummy, nrowlon_dummy, rowlon_dummy) bind(c,&
@@ -2670,11 +2658,6 @@ module mo_cdi
       integer(c_int) :: f_result
     end function taxisHasBounds
 
-    subroutine taxisWithBounds(taxisID_dummy) bind(c, name = 'taxisWithBounds')
-      import c_int
-      integer(c_int), value :: taxisID_dummy
-    end subroutine taxisWithBounds
-
     subroutine taxisDeleteBounds(taxisID_dummy) bind(c, name =&
     & 'taxisDeleteBounds')
       import c_int
diff --git a/libcdi/src/pio_client.c b/libcdi/src/pio_client.c
index 7c2ee99..319ac36 100644
--- a/libcdi/src/pio_client.c
+++ b/libcdi/src/pio_client.c
@@ -129,12 +129,12 @@ cdiPioClientStreamDefVlist_(int streamID, int vlistID)
 
 static void
 cdiPioClientStreamWriteVar_(int streamID, int varID, int memtype,
-                            const void *data, int nmiss)
+                            const void *data, size_t nmiss)
   __attribute__((noreturn));
 
 static void
 cdiPioClientStreamWriteVar_(int streamID, int varID, int memtype,
-                            const void *data, int nmiss)
+                            const void *data, size_t nmiss)
 {
   (void)streamID; (void)varID; (void)memtype; (void)data; (void)nmiss;
   xabort("parallel writing requires explicit partition information,"
@@ -144,7 +144,7 @@ cdiPioClientStreamWriteVar_(int streamID, int varID, int memtype,
 static void
 cdiPioClientStreamWriteVarChunk_(int streamID, int varID, int memtype,
                                  const int rect[][2],
-                                 const void *data, int nmiss)
+                                 const void *data, size_t nmiss)
 {
   /* todo: handle transmission of float data */
   if (memtype != MEMTYPE_DOUBLE)
@@ -170,7 +170,7 @@ cdiPioClientStreamWriteVarChunk_(int streamID, int varID, int memtype,
 
 static void
 cdiPioClientStreamWriteVarPart(int streamID, int varID, const void *data,
-                               int nmiss, Xt_idxlist partDesc)
+                               size_t nmiss, Xt_idxlist partDesc)
 {
   pioBufferPartData(streamID, varID, data, nmiss, partDesc);
 }
@@ -180,7 +180,7 @@ cdiPioClientStreamWriteScatteredVarPart(int streamID, int varID,
                                         const void *data,
                                         int numBlocks, const int blocklengths[],
                                         const int displacements[],
-                                        int nmiss, Xt_idxlist partDesc)
+                                        size_t nmiss, Xt_idxlist partDesc)
 {
   cdiPioBufferPartDataGather(streamID, varID, data, numBlocks,
                              blocklengths, displacements, nmiss, partDesc);
diff --git a/libcdi/src/pio_interface.c b/libcdi/src/pio_interface.c
index da371c6..eefe499 100644
--- a/libcdi/src/pio_interface.c
+++ b/libcdi/src/pio_interface.c
@@ -286,7 +286,7 @@ cdiPioRDMAProgress(void)
 static void
 pioBufferPartData_(int streamID, int varID,
                    const void *packData, valPackFunc packDataFunc,
-                   int nmiss, Xt_idxlist partDesc)
+                   size_t nmiss, Xt_idxlist partDesc)
 {
   size_t streamIdx = indexOfID(&openStreams, streamID);
   xassert(streamIdx != SIZE_MAX);
@@ -309,7 +309,7 @@ pioBufferPartData_(int streamID, int varID,
 
 void
 pioBufferPartData(int streamID, int varID, const double *data,
-                  int nmiss, Xt_idxlist partDesc)
+                  size_t nmiss, Xt_idxlist partDesc)
 {
   int chunk = xt_idxlist_get_num_indices(partDesc);
   xassert(chunk <= INT_MAX);
@@ -368,7 +368,7 @@ void
 cdiPioBufferPartDataGather(int streamID, int varID, const double *data,
                            int numBlocks, const int blocklengths[],
                            const int displacements[],
-                           int nmiss, Xt_idxlist partDesc)
+                           size_t nmiss, Xt_idxlist partDesc)
 {
   xassert(numBlocks >= 0);
   pioBufferPartData_(streamID, varID,
@@ -684,7 +684,7 @@ void pioWriteTimestep(void)
 
 void
 streamWriteVarPart(int streamID, int varID, const void *data,
-                   int nmiss, Xt_idxlist partDesc)
+                   size_t nmiss, Xt_idxlist partDesc)
 {
   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
@@ -692,7 +692,7 @@ streamWriteVarPart(int streamID, int varID, const void *data,
   xassert(chunk == 0 || data);
 
   void (*myStreamWriteVarPart)(int streamID, int varID, const void *data,
-                               int nmiss, Xt_idxlist partDesc)
+                               size_t nmiss, Xt_idxlist partDesc)
     = (void (*)(int, int, const void *, int, Xt_idxlist))
     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_PART_).func;
 
@@ -706,7 +706,7 @@ void
 streamWriteScatteredVarPart(int streamID, int varID, const void *data,
                             int numBlocks, const int blocklengths[],
                             const int displacements[],
-                            int nmiss, Xt_idxlist partDesc)
+                            size_t nmiss, Xt_idxlist partDesc)
 {
   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
@@ -717,7 +717,7 @@ streamWriteScatteredVarPart(int streamID, int varID, const void *data,
                                         const void *data,
                                         int numBlocks, const int blocklengths[],
                                         const int displacements[],
-                                        int nmiss, Xt_idxlist partDesc)
+                                        size_t nmiss, Xt_idxlist partDesc)
     = (void (*)(int, int, const void *, int, const int[], const int[], int,
                 Xt_idxlist))
     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_SCATTERED_VAR_PART_).func;
diff --git a/libcdi/src/pio_interface.h b/libcdi/src/pio_interface.h
index 8a3b1cf..1e8be5b 100644
--- a/libcdi/src/pio_interface.h
+++ b/libcdi/src/pio_interface.h
@@ -13,12 +13,12 @@
 
 void
 pioBufferPartData(int streamID, int varID, const double *data,
-                  int nmiss, Xt_idxlist partDesc);
+                  size_t nmiss, Xt_idxlist partDesc);
 void
 cdiPioBufferPartDataGather(int streamID, int varID, const double *data,
                            int numBlocks, const int blocklengths[],
                            const int displacements[],
-                           int nmiss, Xt_idxlist partDesc);
+                           size_t nmiss, Xt_idxlist partDesc);
 
 void pioBufferFuncCall(int streamID,
                        struct winHeaderEntry header,
diff --git a/libcdi/src/pio_server.c b/libcdi/src/pio_server.c
index 5774a78..d18e583 100644
--- a/libcdi/src/pio_server.c
+++ b/libcdi/src/pio_server.c
@@ -303,7 +303,7 @@ countVarChunkMissingVals(int vlistID, int varID,
                          struct streamMapping *mapping,
                          int chunkLen, const double *restrict data)
 {
-  int nmiss = 0;
+  size_t nmiss = 0;
   if (mapping->hasMissing[varID])
     {
       double missval = vlistInqVarMissval(vlistID, varID);
@@ -450,7 +450,7 @@ writeNetCDFStream(size_t streamIdx,
           xt_idxlist_delete(preWriteChunk);
         }
         /* count missing values if appropriate */
-        int nmiss
+        size_t nmiss
           = countVarChunkMissingVals(vlistID, varID, mapping,
                                      PPM_extents_size(3, varChunk),
                                      data);
@@ -553,7 +553,7 @@ writeNetCDFStream(size_t streamIdx,
         gatherArray(headerIdx, streamIdx, data, dstList, conf);
         if (writerRank == collRank)
           {
-            int nmiss = countVarChunkMissingVals(vlistID, varID,
+            size_t nmiss = countVarChunkMissingVals(vlistID, varID,
                                                  mapping, varSize, data);
             streamWriteVar(streamID, varID, data, nmiss);
           }
@@ -1053,7 +1053,7 @@ writeGribStream(size_t streamIdx,
             varIdx += varID != prevVarID;
             size_t recordSize = writtenRecords[recordIdx].dataSize;
             size_t nvals = recordSize / sizeof (double);
-            int nmiss
+            size_t nmiss
               = countVarChunkMissingVals(vlistID, varID, mapping, (int)nvals,
                                          data + recordDataOfs);
             streamWriteVarSlice(streamID, varID, level, data + recordDataOfs, nmiss);
diff --git a/libcdi/src/stream.c b/libcdi/src/stream.c
index ad1c3eb..bb6b382 100644
--- a/libcdi/src/stream.c
+++ b/libcdi/src/stream.c
@@ -1381,9 +1381,9 @@ void streamWriteContents(int streamID, char *cname)
     {
       int gridID   = vlistGrid(vlistID, i);
       int gridtype = gridInqType(gridID);
-      int xsize    = gridInqXsize(gridID);
-      int ysize    = gridInqYsize(gridID);
-      fprintf(cnp, "%4d:%4d:%4d:%4d\n", i+1, gridtype, xsize, ysize);
+      size_t xsize    = gridInqXsize(gridID);
+      size_t ysize    = gridInqYsize(gridID);
+      fprintf(cnp, "%4d:%4d:%4zu:%4zu\n", i+1, gridtype, xsize, ysize);
     }
 
   fputs("#\nvarID:code:gridID:zaxisID:tsteptype:datatype\n", cnp);
@@ -1446,7 +1446,7 @@ void streamWriteContents(int streamID, char *cname)
 #endif
 
 // This function is used in CDO!
-off_t streamNvals(int streamID)
+size_t streamNvals(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
   return streamptr->numvals;
diff --git a/libcdi/src/stream_cdf.h b/libcdi/src/stream_cdf.h
index 8056b6e..3fc162a 100644
--- a/libcdi/src/stream_cdf.h
+++ b/libcdi/src/stream_cdf.h
@@ -18,17 +18,17 @@ void   cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
 void   cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID);
 
-void   cdf_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
-void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
+void   cdf_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
+void   cdf_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
 
-void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
-void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
+void   cdf_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
+void   cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
 
-void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
-void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
+void   cdf_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
+void   cdf_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
 
 void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
-                           const int rect[][2], const void *data, int nmiss);
+                           const int rect[][2], const void *data, size_t nmiss);
 
 void cdfDefVarDeflate(int ncid, int ncvarid, int deflate_level);
 void cdfDefTime(stream_t* streamptr);
diff --git a/libcdi/src/stream_cdf_i.c b/libcdi/src/stream_cdf_i.c
index 2c7fe11..3e7758c 100644
--- a/libcdi/src/stream_cdf_i.c
+++ b/libcdi/src/stream_cdf_i.c
@@ -89,7 +89,7 @@ typedef struct {
   int      ndims;
   int      dimids[8];
   int      dimtype[8];
-  int      chunks[8];
+  size_t   chunks[8];
   int      chunked;
   int      chunktype;
   int      natts;
@@ -1099,11 +1099,11 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi
               if ( storage_in == NC_CHUNKED )
                 {
                   ncvars[ncvarid].chunked = 1;
-                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = (int)chunks[i];
+                  for ( int i = 0; i < nvdims; ++i ) ncvars[ncvarid].chunks[i] = chunks[i];
                   if ( CDI_Debug )
                     {
                       fprintf(stderr, "%s: chunking %d %d %d  chunks ", name, storage_in, NC_CONTIGUOUS, NC_CHUNKED);
-                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%ld ", chunks[i]);
+                      for ( int i = 0; i < nvdims; ++i ) fprintf(stderr, "%zu ", chunks[i]);
                       fprintf(stderr, "\n");
                     }
                   {
@@ -1114,8 +1114,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi
                     pos += sizeof (prefix) - 1;
                     for ( int i = nvdims-1; i >= 0; --i )
                       {
-                        pos += (size_t)(sprintf(buf + pos, "%zu%s", chunks[i],
-                                                i > 0 ? "x" : ""));
+                        pos += (size_t)(sprintf(buf + pos, "%zu%s", chunks[i], i > 0 ? "x" : ""));
                       }
                     buf[pos] = ' '; buf[pos + 1] = 0;
                   }
@@ -1324,6 +1323,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi
                   char *varname = pstring;
                   while ( !isspace((int) *pstring) && *pstring != 0 ) pstring++;
                   if ( *pstring == 0 ) lstop = true;
+                  if ( *(pstring-1) == ',' ) *(pstring-1) = 0;
                   *pstring++ = 0;
 
                   int dimvarid;
@@ -1346,7 +1346,7 @@ void cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimi
                       if ( k == nchecked_vars )
                         {
                           if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
-                          Warning("%s - %s", nc_strerror(status), varname);
+                          Warning("%s - >%s<", nc_strerror(status), varname);
                         }
                     }
 
@@ -2122,7 +2122,7 @@ void cdf_check_gridtype(int *gridtype, bool islon, bool islat, size_t xsize, siz
   if ( islat && (islon || xsize == 0) )
     {
       double yinc = 0;
-      if ( islon && (int) ysize > 1 )
+      if ( islon && ysize > 1 )
         {
           yinc = fabs(grid->y.vals[0] - grid->y.vals[1]);
           for ( size_t i = 2; i < ysize; i++ )
@@ -2250,8 +2250,8 @@ bool cdf_read_ycoord(struct cdfLazyGrid *restrict lazyGrid, ncdim_t *ncdims, ncv
     }
   else if ( (ndims - ntdims) == 1 )
     {
-      if ( (int) *ysize == 0 ) size = xsize;
-      else                    size = *ysize;
+      if ( *ysize == 0 ) size = xsize;
+      else               size = *ysize;
 
       int dimid = axisvar->dimids[ndims-1];
       size_t dimsize = ncdims[dimid].len;
@@ -2370,8 +2370,8 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar,
                              xsize, &ysize, ntdims, start, count, &islat) )
           return true;
 
-      if      ( (int) ysize == 0 ) size = xsize;
-      else if ( (int) xsize == 0 ) size = ysize;
+      if      ( ysize == 0 ) size = xsize;
+      else if ( xsize == 0 ) size = ysize;
       else if ( ncvar->gridtype == GRID_UNSTRUCTURED ) size = xsize;
       else                         size = xsize*ysize;
 
@@ -2401,9 +2401,9 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar,
     case GRID_CURVILINEAR:
     case GRID_PROJECTION:
       {
-        grid->size  = (int)size;
-        grid->x.size = (int)xsize;
-        grid->y.size = (int)ysize;
+        grid->size  = size;
+        grid->x.size = xsize;
+        grid->y.size = ysize;
         if ( xvarid != CDI_UNDEFID )
           {
             grid->x.flag = 1;
@@ -2445,14 +2445,14 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar,
       }
     case GRID_SPECTRAL:
       {
-        grid->size = (int)size;
+        grid->size = size;
         grid->lcomplex = 1;
         grid->trunc = ncvar->truncation;
         break;
       }
     case GRID_FOURIER:
       {
-        grid->size = (int)size;
+        grid->size = size;
         grid->trunc = ncvar->truncation;
         break;
       }
@@ -2463,9 +2463,9 @@ bool cdf_read_coordinates(struct cdfLazyGrid *restrict lazyGrid, ncvar_t *ncvar,
       }
     case GRID_CHARXY:
       {
-        grid->size = (int)size;
-        grid->x.size = (int)xsize;
-        grid->y.size = (int)ysize;
+        grid->size = size;
+        grid->x.size = xsize;
+        grid->y.size = ysize;
         break;
       }
     }
@@ -2664,17 +2664,6 @@ int cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nva
 		}
 	    }
 
-          if ( xsize > INT_MAX )
-            {
-              Warning("Size limit exceeded for x-axis dimension (limit=%d)!", INT_MAX);
-              return CDI_EDIMSIZE;
-            }
-          if ( ysize > INT_MAX )
-            {
-              Warning("Size limit exceeded for y-axis dimension (limit=%d)!", INT_MAX);
-              return CDI_EDIMSIZE;
-            }
-
           int gmapvarid = ncvar->gmapid;
           bool lproj = gmapvarid != CDI_UNDEFID;
 
@@ -2733,10 +2722,10 @@ int cdf_define_all_grids(ncgrid_t *ncgrid, int vlistID, ncdim_t *ncdims, int nva
 
 	  if ( CDI_Debug )
 	    {
-	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
+	      Message("grid: type = %d, size = %zu, nx = %zu, ny = %zu",
 		      grid->type, grid->size, grid->x.size, grid->y.size);
               if ( proj )
-                Message("proj: type = %d, size = %d, nx = %d, ny %d",
+                Message("proj: type = %d, size = %zu, nx = %zu, ny = %zu",
                         proj->type, proj->size, proj->x.size, proj->y.size);
 	    }
 
@@ -2912,7 +2901,7 @@ int cdf_define_all_zaxes(stream_t *streamptr, int vlistID, ncdim_t *ncdims, int
 		  int nbdims = ncvars[ncvars[zvarid].bounds].ndims;
 		  if ( nbdims == 2 || is_scalar )
 		    {
-		      size_t nlevel  = is_scalar ? 1 : (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
+		      size_t nlevel  = is_scalar ? 1 : ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
 		      int nvertex = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[1-is_scalar]].len;
 		      if ( nlevel == zsize && nvertex == 2 )
 			{
diff --git a/libcdi/src/stream_cdf_o.c b/libcdi/src/stream_cdf_o.c
index e0268ad..ce70f9e 100644
--- a/libcdi/src/stream_cdf_o.c
+++ b/libcdi/src/stream_cdf_o.c
@@ -1,5 +1,5 @@
 #if defined (HAVE_CONFIG_H)
-#  include "config.h"
+#include "config.h"
 #endif
 
 #ifdef HAVE_LIBNETCDF
@@ -29,14 +29,13 @@ void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
   int recID    = streamptr1->tsteps[tsID].recIDs[vrecID];
   int ivarID   = streamptr1->tsteps[tsID].records[recID].varID;
   int gridID   = vlistInqVarGrid(vlistID1, ivarID);
-  int datasize = gridInqSize(gridID);
+  size_t datasize = gridInqSize(gridID);
   int datatype = vlistInqVarDatatype(vlistID1, ivarID);
   int memtype  = datatype != CDI_DATATYPE_FLT32 ? MEMTYPE_DOUBLE : MEMTYPE_FLOAT;
 
-  void *data = Malloc((size_t)datasize
-             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
+  void *data = Malloc(datasize * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
 
-  int nmiss;
+  size_t nmiss;
   cdf_read_record(streamptr1, memtype, data, &nmiss);
   cdf_write_record(streamptr2, memtype, data, nmiss);
 
@@ -144,7 +143,7 @@ struct idSearch
 static inline struct idSearch
 cdfSearchIDBySize(size_t startIdx, size_t numIDs, const ncgrid_t ncgrid[numIDs],
                   int ncIDType, int searchType, int searchSize,
-                  int (*typeInq)(int id), int (*sizeInq)(int id))
+                  int (*typeInq)(int id), size_t (*sizeInq)(int id))
 {
   int numNonMatching = 0,
     foundID = CDI_UNDEFID;
@@ -172,7 +171,7 @@ cdfSearchIDBySize(size_t startIdx, size_t numIDs, const ncgrid_t ncgrid[numIDs],
       .foundID = foundID, .foundIdx = foundIdx };
 }
 
-static int
+static size_t
 cdfGridInqHalfSize(int gridID)
 {
   return gridInqSize(gridID)/2;
@@ -185,7 +184,7 @@ cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex,
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  size_t dimlen = (size_t)(gridInqSize(gridID))/2;
+  size_t dimlen = gridInqSize(gridID)/2;
 
   int iz;
   int dimID;
@@ -235,13 +234,13 @@ void cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
 }
 
 static const struct cdfDefGridAxisInqs {
-  int (*axisSize)(int gridID);
+  size_t (*axisSize)(int gridID);
   int (*axisDimname)(int cdiID, int key, int size, char *mesg);
   int (*axisName)(int cdiID, int key, int size, char *mesg);
   int (*axisLongname)(int cdiID, int key, int size, char *mesg);
   int (*axisUnits)(int cdiID, int key, int size, char *mesg);
   void (*axisStdname)(int cdiID, char *dimstdname);
-  double (*axisVal)(int gridID, int index);
+  double (*axisVal)(int gridID, size_t index);
   const double *(*axisValsPtr)(int gridID);
   const double *(*axisBoundsPtr)(int gridID);
 } gridInqsX = {
@@ -300,7 +299,7 @@ cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex,
   nc_type xtype = (gridInqDatatype(gridID) == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  int dimlen = inqs->axisSize(gridID);
+  size_t dimlen = inqs->axisSize(gridID);
   if ( dimlen != 1 )
     Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID)));
 
@@ -452,7 +451,7 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims,
   int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
   int nvdimID = CDI_UNDEFID;
   int fileID  = streamptr->fileID;
-  size_t dimlen = (size_t)gridAxisInq->axisSize(gridID);
+  size_t dimlen = gridAxisInq->axisSize(gridID);
   nc_type xtype = (nc_type)cdfDefDatatype(gridInqDatatype(gridID), streamptr->filetype);
 
   ncgrid_t *ncgrid = streamptr->ncgrid;
@@ -472,15 +471,15 @@ cdfDefAxisCommon(stream_t *streamptr, int gridID, int gridindex, int ndims,
            gridtype0 == GRID_CURVILINEAR ||
            gridtype0 == GRID_GENERIC )
         {
-          size_t dimlen0 = (size_t)gridAxisInq->axisSize(gridID0);
+          size_t dimlen0 = gridAxisInq->axisSize(gridID0);
           char dimname0[CDI_MAX_NAME]; dimname0[0] = 0;
           if ( dimname[0] ) cdiGridInqKeyStr(gridID0, dimKey, CDI_MAX_NAME, dimname0);
           bool lname = dimname0[0] ? strcmp(dimname, dimname0) == 0 : true;
           if ( dimlen == dimlen0 && lname )
             {
-              double (*inqVal)(int gridID, int index) = gridAxisInq->axisVal;
+              double (*inqVal)(int gridID, size_t index) = gridAxisInq->axisVal;
               if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) &&
-                   IS_EQUAL(inqVal(gridID0, (int)dimlen-1), inqVal(gridID, (int)dimlen-1)) )
+                   IS_EQUAL(inqVal(gridID0, dimlen-1), inqVal(gridID, dimlen-1)) )
                 {
                   dimID = ncgrid[index].ncIDs[dimKey == CDI_KEY_XDIMNAME
                                               ? CDF_DIMID_X : CDF_DIMID_Y];
@@ -605,7 +604,7 @@ void cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
 }
 
 static
-void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
+void cdfGridCompress(int fileID, int ncvarid, size_t gridsize, int filetype, int comptype)
 {
 #if  defined  (HAVE_NETCDF4)
   if ( gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C) )
@@ -727,7 +726,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
       cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname);
       checkGridName(xaxisname, fileID);
       cdf_def_var(fileID, xaxisname, xtype, ndims-1, dimIDs, &ncxvarid);
-      cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+      cdfGridCompress(fileID, ncxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
       cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
 
@@ -741,7 +740,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
           xaxisname[xaxisnameLen] = '_';
           memcpy(xaxisname + xaxisnameLen + 1, bndsName, sizeof (bndsName));
           cdf_def_var(fileID, xaxisname, xtype, ndims, dimIDs, &ncbxvarid);
-          cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+          cdfGridCompress(fileID, ncbxvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
           cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
         }
@@ -756,7 +755,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
       checkGridName(yaxisname, fileID);
 
       cdf_def_var(fileID, yaxisname, xtype, ndims - 1, dimIDs, &ncyvarid);
-      cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+      cdfGridCompress(fileID, ncyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
       cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
 
@@ -770,7 +769,7 @@ cdfDefIrregularGridCommon(stream_t *streamptr, int gridID,
           yaxisname[yaxisnameLen] = '_';
           memcpy(yaxisname + yaxisnameLen + 1, bndsName, sizeof (bndsName));
           cdf_def_var(fileID, yaxisname, xtype, ndims, dimIDs, &ncbyvarid);
-          cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+          cdfGridCompress(fileID, ncbyvarid, xdimlen*ydimlen, streamptr->filetype, streamptr->comptype);
 
           cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
         }
@@ -811,9 +810,9 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
-  size_t xdimlen = (size_t)gridInqXsize(gridID);
-  size_t ydimlen = (size_t)gridInqYsize(gridID);
+  size_t dimlen = gridInqSize(gridID);
+  size_t xdimlen = gridInqXsize(gridID);
+  size_t ydimlen = gridInqYsize(gridID);
 
   int xdimID = CDI_UNDEFID, ydimID = CDI_UNDEFID;
   int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
@@ -829,11 +828,11 @@ void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
         {
           int gridID0 = ncgrid[index].gridID;
           if (    IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0))
-               && IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1),
-                           gridInqXval(gridID, (int)dimlen-1))
+               && IS_EQUAL(gridInqXval(gridID0, dimlen-1),
+                           gridInqXval(gridID, dimlen-1))
                && IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0))
-               && IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1),
-                           gridInqYval(gridID, (int)dimlen-1)) )
+               && IS_EQUAL(gridInqYval(gridID0, dimlen-1),
+                           gridInqYval(gridID, dimlen-1)) )
             {
               xdimID = ncgrid[index].ncIDs[CDF_DIMID_X];
               ydimID = ncgrid[index].ncIDs[CDF_DIMID_Y];
@@ -876,7 +875,7 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  size_t dimlen = gridInqSize(gridID);
 
   int dimID = CDI_UNDEFID;
   int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
@@ -893,11 +892,11 @@ void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
           int gridID0 = ncgrid[index].gridID;
           if ( gridInqNvertex(gridID0) == gridInqNvertex(gridID) &&
                IS_EQUAL(gridInqXval(gridID0, 0), gridInqXval(gridID, 0)) &&
-               IS_EQUAL(gridInqXval(gridID0, (int)dimlen-1),
-                        gridInqXval(gridID, (int)dimlen-1)) &&
+               IS_EQUAL(gridInqXval(gridID0, dimlen-1),
+                        gridInqXval(gridID, dimlen-1)) &&
                IS_EQUAL(gridInqYval(gridID0, 0), gridInqYval(gridID, 0)) &&
-               IS_EQUAL(gridInqYval(gridID0, (int)dimlen-1),
-                        gridInqYval(gridID, (int)dimlen-1)) )
+               IS_EQUAL(gridInqYval(gridID0, dimlen-1),
+                        gridInqYval(gridID, dimlen-1)) )
             {
               dimID = ncgrid[index].ncIDs[CDF_DIMID_X];
               ncxvarid = ncgrid[index].ncIDs[CDF_VARID_X];
@@ -1663,7 +1662,7 @@ void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, i
 {
   if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
 
-  int dimlen = ( xory == 0 ) ? gridInqXsize(gridID) : gridInqYsize(gridID);
+  size_t dimlen = ( xory == 0 ) ? gridInqXsize(gridID) : gridInqYsize(gridID);
   int dimID, strlenID;
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
@@ -1714,7 +1713,7 @@ void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, i
 
   char axisname[CDI_MAX_NAME]; axisname[0] = 0;
   char **cvals = (char **) Malloc(dimlen * sizeof(char *));
-  for ( int i = 0; i < dimlen; i++ )
+  for ( size_t i = 0; i < dimlen; i++ )
     cvals[i] = Malloc(strlen * sizeof(char) );
   int ncaxisid;
   if ( xory == 0 )
@@ -1746,7 +1745,7 @@ void cdfDefCharacter(stream_t *streamptr, int gridID, int gridindex, int xory, i
   start[1] = 0;
   count[0] = 1;
   count[1] = strlen;
-  for (int i = 0; i < dimlen; i++)
+  for (size_t i = 0; i < dimlen; i++)
     {
       start[0] = i;
       status = nc_put_vara_text(fileID, ncaxisid, start, count, cvals[i]);
@@ -1771,7 +1770,7 @@ void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
 {
   ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  size_t dimlen = gridInqSize(gridID);
 
   int iz;
   int dimID;
@@ -1818,7 +1817,7 @@ void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
   int iz = 0;
   int dimID = CDI_UNDEFID;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  size_t dimlen = gridInqSize(gridID);
 
   if ( gridInqYsize(gridID) == 0 )
     {
@@ -1866,10 +1865,10 @@ void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
   if ( streamptr->ncgrid[gridindex].ncIDs[CDF_DIMID_X] != CDI_UNDEFID ) return;
 
   int gridtype = gridInqType(gridID);
-  int size     = gridInqSize(gridID);
+  size_t size = gridInqSize(gridID);
 
   if ( CDI_Debug )
-    Message("gridtype = %d  size = %d", gridtype, size);
+    Message("gridtype = %d  size = %zu", gridtype, size);
 
   if ( CDI_reduce_dim && size == 1 )
     {
diff --git a/libcdi/src/stream_cgribex.c b/libcdi/src/stream_cgribex.c
index c5a0c6c..75e4642 100644
--- a/libcdi/src/stream_cgribex.c
+++ b/libcdi/src/stream_cgribex.c
@@ -165,14 +165,18 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, i
     {
       bool ijDirectionIncrementGiven = gribbyte_get_bit(ISEC2_ResFlag, 1);
       bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
-
       if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
-      if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-        Error("numberOfPoints (%d) and gridSize (%d) differ!", ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
 
-      grid->size   = ISEC4_NumValues;
-      grid->x.size = ISEC2_NumLon;
-      grid->y.size = ISEC2_NumLat;
+      size_t nvalues = (size_t) ISEC4_NumValues;
+      size_t nlon = (size_t) ISEC2_NumLon;
+      size_t nlat = (size_t) ISEC2_NumLat;
+      if ( nvalues != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
+
+      grid->size   = nvalues;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
+
       if ( gridtype == GRID_GAUSSIAN ) grid->np = ISEC2_NumPar;
       grid->x.inc  = 0;
       grid->y.inc  = 0;
@@ -241,10 +245,10 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, i
       bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
       if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
       grid->np      = ISEC2_NumPar;
-      grid->size    = ISEC4_NumValues;
+      grid->size    = (size_t)ISEC4_NumValues;
       grid->rowlon  = ISEC2_RowLonPtr;
-      grid->nrowlon = ISEC2_NumLat;
-      grid->y.size  = ISEC2_NumLat;
+      grid->nrowlon = (size_t)ISEC2_NumLat;
+      grid->y.size  = (size_t)ISEC2_NumLat;
       grid->x.inc   = 0;
       grid->y.inc   = 0;
       grid->x.flag  = 0;
@@ -283,12 +287,15 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, i
       bool uvRelativeToGrid = gribbyte_get_bit(ISEC2_ResFlag, 5);
       if ( uvRelativeToGrid ) grid->uvRelativeToGrid = 1;
 
-      if ( ISEC4_NumValues != ISEC2_NumLon*ISEC2_NumLat )
-        Error("numberOfPoints (%d) and gridSize (%d) differ!", ISEC4_NumValues, ISEC2_NumLon*ISEC2_NumLat);
+      size_t nvalues = (size_t) ISEC4_NumValues;
+      size_t nlon = (size_t) ISEC2_NumLon;
+      size_t nlat = (size_t) ISEC2_NumLat;
+      if ( nvalues != nlon*nlat )
+        Error("numberOfPoints (%zu) and gridSize (%zu) differ!", nvalues, nlon*nlat);
 
-      grid->size   = ISEC4_NumValues;
-      grid->x.size = ISEC2_NumLon;
-      grid->y.size = ISEC2_NumLat;
+      grid->size   = nvalues;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
 
       grid->x.first = 0;
       grid->x.last  = 0;
@@ -301,16 +308,13 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, i
     }
   else if ( gridtype == GRID_SPECTRAL )
     {
-      grid->size  = ISEC4_NumValues;
+      grid->size  = (size_t) ISEC4_NumValues;
       grid->trunc = ISEC2_PentaJ;
-      if ( ISEC2_RepMode == 2 )
-        grid->lcomplex = 1;
-      else
-        grid->lcomplex = 0;
-    }
+      grid->lcomplex = (ISEC2_RepMode == 2) ? 1 : 0;
+   }
   else if ( gridtype == GRID_GME )
     {
-      grid->size  = ISEC4_NumValues;
+      grid->size  = (size_t) ISEC4_NumValues;
       grid->gme.nd  = ISEC2_GME_ND;
       grid->gme.ni  = ISEC2_GME_NI;
       grid->gme.ni2 = ISEC2_GME_NI2;
@@ -318,7 +322,7 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, int *isec4, grid_t *grid, i
     }
   else if ( gridtype == GRID_GENERIC )
     {
-      grid->size  = ISEC4_NumValues;
+      grid->size  = (size_t) ISEC4_NumValues;
       grid->x.size = 0;
       grid->y.size = 0;
     }
@@ -1322,8 +1326,8 @@ int cgribexScanTimestep(stream_t * streamptr)
 #endif
 
 #if  defined  (HAVE_LIBCGRIBEX)
-int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
-		  int unreduced, int *nmiss, double missval)
+int cgribexDecode(int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval)
 {
   int status = 0;
   int iret = 0, iword = 0;
@@ -1339,10 +1343,10 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
 
   if ( memtype == MEMTYPE_FLOAT )
     gribExSP(isec0, isec1, isec2, fsec2f, isec3, fsec3f, isec4, (float*) data,
-             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+             (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
   else
     gribExDP(isec0, isec1, isec2, fsec2, isec3, fsec3, isec4, (double*) data,
-             (int) datasize, (int*) gribbuffer, gribsize, &iword, hoper, &iret);
+             (int) datasize, (int*) gribbuffer, (int)gribsize, &iword, hoper, &iret);
 
   *nmiss = (ISEC1_Sec2Or3Flag & 64) ? ISEC4_NumValues - ISEC4_NumNonMissValues : 0;
 
@@ -1355,7 +1359,7 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
       if ( memtype == MEMTYPE_FLOAT )
         {
           float *restrict dataf = (float*) data;
-          for ( long i = 0; i < datasize; i++ )
+          for ( size_t i = 0; i < datasize; i++ )
             if ( (fabs(dataf[i]-undef_pds) < undef_eps) || IS_EQUAL(dataf[i],FSEC3_MissVal) ) {
               dataf[i] = (float)missval;
               (*nmiss)++;
@@ -1364,7 +1368,7 @@ int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long
       else
         {
           double *restrict datad = (double*) data;
-          for ( long i = 0; i < datasize; i++ )
+          for ( size_t i = 0; i < datasize; i++ )
             if ( (fabs(datad[i]-undef_pds) < undef_eps) || IS_EQUAL(datad[i],FSEC3_MissVal) ) {
               datad[i] = missval;
               (*nmiss)++;
@@ -1610,9 +1614,9 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 
   if ( gridtype == GRID_GENERIC )
     {
-      int gridsize = gridInqSize(gridID);
-      int xsize = gridInqXsize(gridID);
-      int ysize = gridInqYsize(gridID);
+      int gridsize = (int)gridInqSize(gridID);
+      int xsize = (int)gridInqXsize(gridID);
+      int ysize = (int)gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -1688,8 +1692,8 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	else
 	  ISEC2_GridType = GRIB1_GTYPE_LATLON;
 
-	int nlon = gridInqXsize(gridID);
-	int nlat = gridInqYsize(gridID);
+	int nlon = (int)gridInqXsize(gridID);
+	int nlat = (int)gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
@@ -1773,8 +1777,8 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
       }
     case GRID_LCC:
       {
-	int xsize = gridInqXsize(gridID);
-        int ysize = gridInqYsize(gridID);
+	int xsize = (int)gridInqXsize(gridID);
+        int ysize = (int)gridInqYsize(gridID);
 
         double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
 	gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
@@ -2079,7 +2083,7 @@ void cgribexDefEnsembleVar(int *isec1, int vlistID, int varID)
 #if  defined  (HAVE_LIBCGRIBEX)
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize)
+		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize)
 {
   int iret = 0, iword = 0;
   int isec0[2], isec1[4096], isec2[4096], isec3[2], isec4[512];
@@ -2109,7 +2113,9 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
 
   cgribexDefEnsembleVar(isec1, vlistID, varID);
 
-  ISEC4_NumValues = gridInqSize(gridID);
+  cdi_check_gridsize_int_limit("GRIB1", datasize);
+
+  ISEC4_NumValues = (int) datasize;
   ISEC4_NumBits   = grbBitsPerValue(datatype);
 
   if ( nmiss > 0 )
diff --git a/libcdi/src/stream_cgribex.h b/libcdi/src/stream_cgribex.h
index 34f8f33..15490d6 100644
--- a/libcdi/src/stream_cgribex.h
+++ b/libcdi/src/stream_cgribex.h
@@ -1,23 +1,23 @@
-#ifndef _STREAM_CGRIBEX_H
-#define _STREAM_CGRIBEX_H
+#ifndef STREAM_CGRIBEX_H
+#define STREAM_CGRIBEX_H
 
 int cgribexScanTimestep1(stream_t * streamptr);
 int cgribexScanTimestep2(stream_t * streamptr);
 int cgribexScanTimestep(stream_t * streamptr);
 
-int cgribexDecode(int memtype, void *gribbuffer, int gribsize, void *data, long datasize,
-		  int unreduced, int *nmiss, double missval);
+int cgribexDecode(int memtype, void *gribbuffer, size_t gribsize, void *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval);
 
 size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const void *data, int nmiss, void *gribbuffer, size_t gribbuffersize);
+		     size_t datasize, const void *data, size_t nmiss, void *gribbuffer, size_t gribbuffersize);
 
 void *cgribex_handle_new_from_meassage(void *gribbuffer, size_t recsize);
 void cgribex_handle_delete(void *gh);
 
 void cgribexChangeParameterIdentification(void *gh, int code, int ltype, int lev);
 
-#endif  /* _STREAM_CGRIBEX_H */
+#endif  /* STREAM_CGRIBEX_H */
 /*
  * Local Variables:
  * c-file-style: "Java"
diff --git a/libcdi/src/stream_ext.c b/libcdi/src/stream_ext.c
index f5456ce..c50dff9 100644
--- a/libcdi/src/stream_ext.c
+++ b/libcdi/src/stream_ext.c
@@ -2,10 +2,6 @@
 #  include "config.h"
 #endif
 
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
 #include "dmemory.h"
 
 #include "error.h"
@@ -90,7 +86,7 @@ int extInqRecord(stream_t *streamptr, int *varID, int *levelID)
 }
 */
 
-void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void extReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
   int vlistID = streamptr->vlistID;
   int fileID  = streamptr->fileID;
@@ -112,14 +108,14 @@ void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
 
   double missval = vlistInqVarMissval(vlistID, varID);
   int gridID  = vlistInqVarGrid(vlistID, varID);
-  int size    = gridInqSize(gridID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( int i = 0; i < size; i++ )
+      for ( size_t i = 0; i < size; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -128,7 +124,7 @@ void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
     }
   else
     {
-      for ( int i = 0; i < 2*size; i+=2 )
+      for ( size_t i = 0; i < 2*size; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -154,7 +150,8 @@ void extDefRecord(stream_t *streamptr)
   header[1] = pnum;
   header[2] = streamptr->record->level;
   int gridID = streamptr->record->gridID;
-  header[3] = gridInqSize(gridID);
+  cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
+  header[3] = (int) gridInqSize(gridID);
 
   extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
@@ -172,7 +169,7 @@ void extWriteRecord(stream_t *streamptr, const double *data)
 }
 
 static
-void extAddRecord(stream_t *streamptr, int param, int level, int xysize,
+void extAddRecord(stream_t *streamptr, int param, int level, size_t xysize,
 		  size_t recsize, off_t position, int prec, int number)
 {
   int vlistID = streamptr->vlistID;
@@ -638,7 +635,7 @@ int extInqTimestep(stream_t *streamptr, int tsID)
 }
 
 
-void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
@@ -648,7 +645,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
   double missval = vlistInqVarMissval(vlistID, varID);
-  int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   int tsid     = streamptr->curTsID;
 
   off_t currentfilepos = fileGetPos(fileID);
@@ -667,7 +664,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( int i = 0; i < gridsize; i++ )
+      for ( size_t i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -676,7 +673,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
     }
   else
     {
-      for ( int i = 0; i < 2*gridsize; i+=2 )
+      for ( size_t i = 0; i < 2*gridsize; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -686,12 +683,12 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void extReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void extReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
   for ( size_t levID = 0; levID < nlevs; levID++)
@@ -714,7 +711,9 @@ void extWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   header[0] = streamptr->tsteps[tsID].taxis.vdate;
   header[1] = pnum;
   header[2] = (int)(zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levID));
-  header[3] = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  int gridID = vlistInqVarGrid(vlistID, varID);
+  cdi_check_gridsize_int_limit("EXTRA", gridInqSize(gridID));
+  header[3] = (int) gridInqSize(gridID);
 
   extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(vlistInqVarDatatype(vlistID, varID), &extp->prec, &extp->number);
@@ -730,7 +729,7 @@ void extWriteVarDP(stream_t *streamptr, int varID, const double *data)
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
 
   for ( size_t levID = 0;  levID < nlevs; levID++ )
diff --git a/libcdi/src/stream_ext.h b/libcdi/src/stream_ext.h
index 89c8e2e..6080695 100644
--- a/libcdi/src/stream_ext.h
+++ b/libcdi/src/stream_ext.h
@@ -11,13 +11,13 @@ int    extInqTimestep(stream_t *streamptr, int tsID);
 int    extInqRecord(stream_t *streamptr, int *varID, int *levelID);
 void   extDefRecord(stream_t *streamptr);
 void   extCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   extReadRecord(stream_t *streamptr, double *data, int *nmiss);
+void   extReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
 void   extWriteRecord(stream_t *streamptr, const double *data);
 
-void   extReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
+void   extReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
 void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
-void   extReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
+void   extReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
 void   extWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
 #endif  /* _STREAM_EXT_H */
diff --git a/libcdi/src/stream_grb.c b/libcdi/src/stream_grb.c
index c4c5c3b..0daecdd 100644
--- a/libcdi/src/stream_grb.c
+++ b/libcdi/src/stream_grb.c
@@ -279,9 +279,7 @@ int grbScanTimestep2(stream_t * streamptr)
   int filetype = streamptr->filetype;
 
   if ( filetype == CDI_FILETYPE_GRB )
-    {
-      status = cgribexScanTimestep2(streamptr);
-    }
+    status = cgribexScanTimestep2(streamptr);
 #endif
 #if defined(HAVE_LIBCGRIBEX) && defined (HAVE_LIBGRIB_API)
   else
@@ -297,9 +295,10 @@ static
 int grbScanTimestep(stream_t * streamptr)
 {
   int status = CDI_EUFTYPE;
-  int filetype  = streamptr->filetype;
 
 #if  defined  (HAVE_LIBCGRIBEX)
+  int filetype  = streamptr->filetype;
+
   if ( filetype == CDI_FILETYPE_GRB )
     status = cgribexScanTimestep(streamptr);
   else
diff --git a/libcdi/src/stream_grb.h b/libcdi/src/stream_grb.h
index 78eb8c5..e98c3ec 100644
--- a/libcdi/src/stream_grb.h
+++ b/libcdi/src/stream_grb.h
@@ -12,15 +12,15 @@ int   grbInqTimestep(stream_t *streamptr, int tsID);
 
 int   grbInqRecord(stream_t *streamptr, int *varID, int *levelID);
 void  grbDefRecord(stream_t *streamptr);
-void  grb_read_record(stream_t *streamptr, int memtype, void *data, int *nmiss);
-void  grb_write_record(stream_t *streamptr, int memtype, const void *data, int nmiss);
+void  grb_read_record(stream_t *streamptr, int memtype, void *data, size_t *nmiss);
+void  grb_write_record(stream_t *streamptr, int memtype, const void *data, size_t nmiss);
 void  grbCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
 
-void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, int *nmiss);
-void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, int nmiss);
+void  grb_read_var(stream_t *streamptr, int varID, int memtype, void *data, size_t *nmiss);
+void  grb_write_var(stream_t *streamptr, int varID, int memtype, const void *data, size_t nmiss);
 
-void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, int *nmiss);
-void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, int nmiss);
+void  grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, void *data, size_t *nmiss);
+void  grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtype, const void *data, size_t nmiss);
 
 int   grib1ltypeToZaxisType(int grib_ltype);
 int   grib2ltypeToZaxisType(int grib_ltype);
diff --git a/libcdi/src/stream_gribapi.c b/libcdi/src/stream_gribapi.c
index 88f40d8..368c724 100644
--- a/libcdi/src/stream_gribapi.c
+++ b/libcdi/src/stream_gribapi.c
@@ -1,11 +1,8 @@
 #if defined (HAVE_CONFIG_H)
-#  include "config.h"
+#include "config.h"
 #endif
 
 #ifdef HAVE_LIBGRIB_API
-#include <limits.h>
-#include <stdio.h>
-
 #include "dmemory.h"
 #include "cdi.h"
 #include "cdi_int.h"
@@ -1468,8 +1465,8 @@ int gribapiScanTimestep(stream_t * streamptr)
 #undef gribWarning
 #endif
 
-int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID)
+int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t gridsize,
+		  int unreduced, size_t *nmiss, double missval, int vlistID, int varID)
 {
   int status = 0;
   long lpar;
@@ -1500,8 +1497,8 @@ int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
 
   // printf("values_size = %d  numberOfPoints = %ld\n", datasize, numberOfPoints);
 
-  if ( gridsize != (long) datasize )
-    Error("Internal problem: gridsize(%ld) != datasize(%zu)!", gridsize, datasize);
+  if ( gridsize != datasize )
+    Error("Internal problem: gridsize(%zu) != datasize(%zu)!", gridsize, datasize);
   size_t dummy = datasize;
   GRIB_CHECK(grib_get_double_array(gh, "values", data, &dummy), 0);
 
@@ -1868,7 +1865,7 @@ struct gribApiMsg {
 };
 
 static struct gribApiMsg
-getGribApiCompTypeMsg(int comptype, int gridsize)
+getGribApiCompTypeMsg(int comptype, size_t gridsize)
 {
   const char *mesg;
   size_t len;
@@ -1897,14 +1894,14 @@ getGribApiCompTypeMsg(int comptype, int gridsize)
 
 
 static
-void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, int nmiss, int gcinit)
+void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, size_t nmiss, int gcinit)
 {
   UNUSED(nmiss);
   bool lrotated = false;
   bool lcurvi = false;
 
   int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   if ( editionNumber <= 1 )
     if ( gridtype == GRID_GME || gridtype == GRID_UNSTRUCTURED )
@@ -1912,8 +1909,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 
   if ( gridtype == GRID_GENERIC )
     {
-      int xsize = gridInqXsize(gridID);
-      int ysize = gridInqYsize(gridID);
+      int xsize = (int) gridInqXsize(gridID);
+      int ysize = (int) gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -2022,8 +2019,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
           }
         GRIB_CHECK(my_grib_set_string(gh, "gridType", mesg, &len), 0);
 
-	int nlon = gridInqXsize(gridID);
-	int nlat = gridInqYsize(gridID);
+	int nlon = (int) gridInqXsize(gridID);
+	int nlat = (int) gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
@@ -2129,8 +2126,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
       }
     case GRID_LCC:
       {
-	int xsize = gridInqXsize(gridID);
-	int ysize = gridInqYsize(gridID);
+	int xsize = (int) gridInqXsize(gridID);
+	int ysize = (int) gridInqYsize(gridID);
 
         double lon_0, lat_0, lat_1, lat_2, a, rf, xval_0, yval_0, x_0, y_0;
 	gridInqParamLCC(gridID, grid_missval, &lon_0, &lat_0, &lat_1, &lat_2, &a, &rf, &xval_0, &yval_0, &x_0, &y_0);
@@ -2185,19 +2182,19 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
           for (size_t i = 0; i < numTruncAtt; ++i)
             GRIB_CHECK(my_grib_set_long(gh, truncAttNames[i], trunc), 0);
         }
-	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
+	// GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", (long)gridsize), 0);
         /*
         if ( lieee )
           {
             printf("spectral_ieee\n");
-            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize, 0);
+            if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", (long)gridsize, 0);
             static const char mesg[] = "spectral_ieee";
             size_t len = sizeof (mesg) -1;
             GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
           }
         else */ if ( gridInqComplexPacking(gridID) )
 	  {
-	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", gridsize), 0);
+	    if ( editionNumber == 2 ) GRIB_CHECK(my_grib_set_long(gh, "numberOfValues", (long)gridsize), 0);
             static const char mesg[] = "spectral_complex";
             size_t len = sizeof (mesg) -1;
 	    GRIB_CHECK(my_grib_set_string(gh, "packingType", mesg, &len), 0);
@@ -2229,8 +2226,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	GRIB_CHECK(my_grib_set_long(gh, "latitudeOfThePolePoint", 90000000), 0);
 	GRIB_CHECK(my_grib_set_long(gh, "longitudeOfThePolePoint", 0), 0);
 
-	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", gridsize), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "numberOfDataPoints", (long)gridsize), 0);
+	GRIB_CHECK(my_grib_set_long(gh, "totalNumberOfGridPoints", (long)gridsize), 0);
 
         if ( comptype == CDI_COMPRESS_SZIP )
           {
@@ -2756,10 +2753,10 @@ verticallyFlipGridDefinitionWhenScanningModeChanged(grib_handle *gh, double yfir
 
 static void
 convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
-                        int gridsize, int iDim, int jDim)
+                        size_t gridsize, size_t iDim, size_t jDim)
 {
-  int i,j;
-  int idxIN, idxOUT;
+  size_t i,j;
+  size_t idxIN, idxOUT;
 
    // 127: reserved for testing; it will generate test data in 64 scanning mode
   if (scanModeOUT== 127)  // fill with testdata ...
@@ -2768,7 +2765,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
       if (cdiDebugExt>=30) printf("convertDataScanningMode(): Generating test data in 64 scanning mode..\n");
       for (j=0; j<jDim; j++)
       {
-        int jXiDim = j*iDim;
+        size_t jXiDim = j*iDim;
         for (i=0; i<iDim; i++)
         {
           idxIN = i + jXiDim;
@@ -2779,17 +2776,17 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
 
   if ( (iDim*jDim)!= gridsize)
   {
-    if (cdiDebugExt>=30) printf("convertDataScanningMode(): ERROR: (iDim*jDim)!= gridsize;  (%d * %d) != %d\n", iDim,jDim, gridsize);
+    if (cdiDebugExt>=30) printf("convertDataScanningMode(): ERROR: (iDim*jDim)!= gridsize;  (%zu * %zu) != %zu\n", iDim,jDim, gridsize);
     return;
   }
-  if (cdiDebugExt>=30) printf("convertDataScanningMode(): scanModeIN=%02d => scanModeOUT=%02d ; where: (iDim * jDim == gridsize)  (%d*%d == %d)\n",scanModeIN, scanModeOUT, iDim,jDim, gridsize);
+  if (cdiDebugExt>=30) printf("convertDataScanningMode(): scanModeIN=%02d => scanModeOUT=%02d ; where: (iDim * jDim == gridsize)  (%zu*%zu == %zu)\n",scanModeIN, scanModeOUT, iDim,jDim, gridsize);
 
   if (cdiDebugExt>=100)
   {
       printf("convertDataScanningMode(): data IN:\n");
       for (j=0; j<jDim; j++)
       {
-        int jXiDim = j*iDim;
+        size_t jXiDim = j*iDim;
         for (i=0; i<iDim; i++)
         {
           idxIN = i + jXiDim;
@@ -2815,9 +2812,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
           return;
       }
   }
-  double *dataCopy = NULL;
-  dataCopy = (double *) malloc(gridsize*sizeof(double));
-
+  double *dataCopy = (double *) malloc(gridsize*sizeof(double));
   memcpy((void*)dataCopy,(void*) data, gridsize*sizeof(double));
 
   if (scanModeIN==64)           // Scanning Mode (00 dec)  +i, -j; i direction consecutive (row-major    order West->East   & South->North )
@@ -2846,7 +2841,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
             {
               for (j=0; j<jDim; j++)
               {
-                int jXiDim = j*iDim;
+                size_t jXiDim = j*iDim;
                 idxIN  = i           + jXiDim;
                 //data[idxIN] = (double) (100.0*j +i);  // just some testdata ..
                 idxOUT = iDim - i -1 + jXiDim;
@@ -2860,10 +2855,10 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
 
       if (scanModeOUT==96)
       { // transpose the data
-        if (cdiDebugExt>=30) printf("convertDataScanningMode():  transpose data rows=>columns nr. (%04d : %04d) => (%04d : %04d);\n", 0, iDim-1, 0, jDim-1);
+        if (cdiDebugExt>=30) printf("convertDataScanningMode():  transpose data rows=>columns nr. (%04d : %04zu) => (%04d : %04zu);\n", 0, iDim-1, 0, jDim-1);
         for (j=0; j<jDim; j++)
         {
-          int jXiDim = j*iDim;
+          size_t jXiDim = j*iDim;
           for (i=0; i<iDim; i++)
           {
             idxIN  = i + jXiDim;
@@ -2884,7 +2879,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
         idxIN= 0; idxOUT= (jDim-1)*iDim;
         for (j=0; j<jDim; j++)
         {
-          if (cdiDebugExt>=25) printf("convertDataScanningMode():  copying row nr. %04d; [idxIN=%08d] => [idxOUT=%08d]\n",j, idxIN, idxOUT);
+          if (cdiDebugExt>=25) printf("convertDataScanningMode():  copying row nr. %04zu; [idxIN=%08zu] => [idxOUT=%08zu]\n",j, idxIN, idxOUT);
           memcpy((void*)&data[idxOUT], (void*)&dataCopy[idxIN], iDim*sizeof(double));
           idxIN  += iDim; idxOUT -= iDim;
         }
@@ -2892,10 +2887,10 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
 
       if (scanModeOUT==96)
       { // transpose the data
-        int jInv;
+        size_t jInv;
         for (j=0; j<jDim; j++)
         {
-          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04d;\n", j);
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
           jInv = (jDim-1) -j;
           for (i=0; i<iDim; i++)
             data[j + i*jDim] =  dataCopy[i + jInv*iDim];  // source data has -j
@@ -2910,8 +2905,8 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
       { // transpose the data
         for (j=0; j<jDim; j++)
         {
-          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04d;\n", j);
-          int jXiDim = j*iDim;
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
+          size_t jXiDim = j*iDim;
           for (i=0; i<iDim; i++)
             //data[j + i*jDim] =  dataCopy[i + j*iDim];
             data[i + jXiDim] =  dataCopy[j + i*jDim];
@@ -2921,12 +2916,12 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
       if (scanModeOUT==00)
       { // transpose the data
         idxIN= 0; idxOUT= 0;
-        int jInv;
+        size_t jInv;
         for (j=0; j<jDim; j++)
         {
-          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04d;\n", j);
+          if (cdiDebugExt>=30) printf("convertDataScanningMode():  processing row nr. %04zu;\n", j);
           jInv = (jDim-1) -j;
-          int jXiDim = j*iDim;
+          size_t jXiDim = j*iDim;
           for (i=0; i<iDim; i++)
             //data[jInv + iXjDim] =  dataCopy[i + jXiDim];  // target data has -j
             data[i + jXiDim] =  dataCopy[jInv + i*jDim];  // target data has -j
@@ -2939,7 +2934,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
       printf("convertDataScanningMode(): data OUT (new scanning mode):\n");
       for (j=0; j<jDim; j++)
       {
-        int jXiDim = j*iDim;
+        size_t jXiDim = j*iDim;
         for (i=0; i<iDim; i++)
         {
           idxIN = i + jXiDim;
@@ -2954,7 +2949,7 @@ convertDataScanningMode(int scanModeIN, int scanModeOUT, double *data,
 #endif //HIRLAM_EXTENSIONS
 
 static
-void gribapiSetExtMode(grib_handle *gh, int gridID, long datasize, const double *data)
+void gribapiSetExtMode(grib_handle *gh, int gridID, size_t datasize, const double *data)
 {
   /*
   Nj = 550;
@@ -2977,14 +2972,14 @@ void gribapiSetExtMode(grib_handle *gh, int gridID, long datasize, const double
 
       if (cdiDebugExt>=100)
         {
-          int gridsize = gridInqSize(gridID);
-          Message("(scanModeIN=%d; gridsize=%d", scanModeIN, gridsize);
+          size_t gridsize = gridInqSize(gridID);
+          Message("(scanModeIN=%d; gridsize=%zu", scanModeIN, gridsize);
         }
 
       if ( cdiGribDataScanningMode.active )   // allowed modes: <0, 64, 96>; Default is 64
         {
-          int iDim = gridInqXsize(gridID);
-          int jDim = gridInqYsize(gridID);
+          size_t iDim = gridInqXsize(gridID);
+          size_t jDim = gridInqYsize(gridID);
 
           double yfirst = gridInqYval(gridID,      0);
           double ylast  = gridInqYval(gridID, jDim-1);
@@ -3026,7 +3021,7 @@ void gribapiSetExtMode(grib_handle *gh, int gridID, long datasize, const double
 
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int comptype, void *gribContainer)
 {
   size_t recsize = 0;
@@ -3041,6 +3036,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
   char stdname[256];
 
   // extern unsigned char _grib_template_GRIB2[];
+  cdi_check_gridsize_int_limit("GRIB", datasize);
 
   int param    = vlistInqVarParam(vlistID, varID);
   int datatype = vlistInqVarDatatype(vlistID, varID);
@@ -3144,7 +3140,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 
   gribapiSetExtMode(gh, gridID, datasize, data);
 
-  GRIB_CHECK(grib_set_double_array(gh, "values", data, (size_t)datasize), 0);
+  GRIB_CHECK(grib_set_double_array(gh, "values", data, datasize), 0);
 
   /* get the size of coded message  */
   GRIB_CHECK(grib_get_message(gh, (const void **)&dummy, &recsize), 0);
diff --git a/libcdi/src/stream_gribapi.h b/libcdi/src/stream_gribapi.h
index 9b4e980..5da3bba 100644
--- a/libcdi/src/stream_gribapi.h
+++ b/libcdi/src/stream_gribapi.h
@@ -1,5 +1,5 @@
-#ifndef _STREAM_GRIBAPI_H
-#define _STREAM_GRIBAPI_H
+#ifndef STREAM_GRIBAPI_H
+#define STREAM_GRIBAPI_H
 
 #ifdef HAVE_LIBGRIB_API
 
@@ -9,12 +9,12 @@ int gribapiScanTimestep1(stream_t * streamptr);
 int gribapiScanTimestep2(stream_t * streamptr);
 int gribapiScanTimestep(stream_t * streamptr);
 
-int gribapiDecode(void *gribbuffer, int gribsize, double *data, long datasize,
-		  int unreduced, int *nmiss, double missval, int vlistID, int varID);
+int gribapiDecode(void *gribbuffer, size_t gribsize, double *data, size_t datasize,
+		  int unreduced, size_t *nmiss, double missval, int vlistID, int varID);
 
 size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisID,
 		     int vdate, int vtime, int tsteptype, int numavg,
-		     long datasize, const double *data, int nmiss, void **gribbuffer, size_t *gribbuffersize,
+		     size_t datasize, const double *data, size_t nmiss, void **gribbuffer, size_t *gribbuffersize,
 		     int ljpeg, void *gribContainer);
 
 int gribapiGetScanningMode(grib_handle *gh);
diff --git a/libcdi/src/stream_ieg.c b/libcdi/src/stream_ieg.c
index 8850336..f6ad8c3 100644
--- a/libcdi/src/stream_ieg.c
+++ b/libcdi/src/stream_ieg.c
@@ -2,13 +2,7 @@
 #  include "config.h"
 #endif
 
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <float.h>
-#include <math.h>
 
 #include "dmemory.h"
 
@@ -87,7 +81,7 @@ int iegInqRecord(stream_t *streamptr, int *varID, int *levelID)
 }
 */
 
-void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
   int vlistID = streamptr->vlistID;
   int fileID  = streamptr->fileID;
@@ -108,12 +102,12 @@ void iegReadRecord(stream_t *streamptr, double *data, int *nmiss)
 
   double missval = vlistInqVarMissval(vlistID, varID);
   int gridID  = vlistInqVarGrid(vlistID, varID);
-  int size    = gridInqSize(gridID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( int i = 0; i < size; i++ )
+  for ( size_t i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -249,8 +243,10 @@ void iegDefGrid(int *gdb, int gridID)
   int projtype = CDI_UNDEFID;
   if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL ) projtype = CDI_PROJ_RLL;
 
-  int xsize = gridInqXsize(gridID);
-  int ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
+
+  cdi_check_gridsize_int_limit("IEG", xsize*ysize);
 
   if ( gridtype == GRID_GENERIC )
     {
@@ -313,8 +309,8 @@ void iegDefGrid(int *gdb, int gridID)
 
       IEG_G_ResFac(gdb)   = iresfac;
 
-      IEG_G_NumLon(gdb)   = xsize;
-      IEG_G_NumLat(gdb)   = ysize;
+      IEG_G_NumLon(gdb)   = (int)xsize;
+      IEG_G_NumLat(gdb)   = (int)ysize;
       IEG_G_FirstLat(gdb) = (int)lround(yfirst*resfac);
       IEG_G_LastLat(gdb)  = (int)lround(ylast*resfac);
       IEG_G_FirstLon(gdb) = (int)lround(xfirst*resfac);
@@ -324,7 +320,7 @@ void iegDefGrid(int *gdb, int gridID)
 	IEG_G_LonIncr(gdb) = 0;
 
       if ( gridtype == GRID_GAUSSIAN )
-	IEG_G_LatIncr(gdb) = ysize/2;
+	IEG_G_LatIncr(gdb) = (int)ysize/2;
       else
 	{
 	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
@@ -535,10 +531,10 @@ void iegWriteRecord(stream_t *streamptr, const double *data)
   iegrec_t *iegp = (iegrec_t*) record->exsep;
 
   int fileID = streamptr->fileID;
-  int gridsize = gridInqSize(record->gridID);
+  size_t gridsize = gridInqSize(record->gridID);
 
   double refval = data[0];
-  for ( int i = 1; i < gridsize; i++ )
+  for ( size_t i = 1; i < gridsize; i++ )
     if ( data[i] < refval ) refval = data[i];
 
   iegp->refval = refval;
@@ -583,8 +579,8 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
   grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
   grid_init(grid);
   cdiGridTypeInit(grid, gridtype, IEG_G_NumLon(gdb)*IEG_G_NumLat(gdb));
-  int xsize = IEG_G_NumLon(gdb);
-  int ysize = IEG_G_NumLat(gdb);
+  size_t xsize = (size_t)IEG_G_NumLon(gdb);
+  size_t ysize = (size_t)IEG_G_NumLat(gdb);
   grid->x.size = xsize;
   grid->y.size = ysize;
   grid->x.inc  = 0;
@@ -683,7 +679,7 @@ void iegAddRecord(stream_t *streamptr, int param, int *pdb, int *gdb, double *vc
 #if 0
 static
 void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int param,
-		  int level, int xsize, int ysize)
+		  int level, size_t xsize, size_t ysize)
 {
   int varID = 0;
   int levelID = 0;
@@ -1164,7 +1160,7 @@ int iegInqTimestep(stream_t *streamptr, int tsID)
 }
 
 
-void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
@@ -1174,7 +1170,7 @@ void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
   double missval = vlistInqVarMissval(vlistID, varID);
-  int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   int tsid     = streamptr->curTsID;
 
   off_t currentfilepos = fileGetPos(fileID);
@@ -1189,7 +1185,7 @@ void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 
   *nmiss = 0;
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -1198,12 +1194,12 @@ void iegReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void iegReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
   for ( size_t levID = 0; levID < nlevs; levID++)
@@ -1239,10 +1235,10 @@ void iegWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
 
   iegp->dprec = iegDefDatatype(vlistInqVarDatatype(vlistID, varID));
 
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   double refval = data[0];
-  for ( int i = 1; i < gridsize; i++ )
+  for ( size_t i = 1; i < gridsize; i++ )
     if ( data[i] < refval ) refval = data[i];
 
   iegp->refval = refval;
@@ -1257,7 +1253,7 @@ void iegWriteVarDP(stream_t *streamptr, int varID, const double *data)
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
 
   for ( size_t levID = 0;  levID < nlevs; levID++ )
diff --git a/libcdi/src/stream_ieg.h b/libcdi/src/stream_ieg.h
index 2012792..d50ee04 100644
--- a/libcdi/src/stream_ieg.h
+++ b/libcdi/src/stream_ieg.h
@@ -11,13 +11,13 @@ int    iegInqTimestep(stream_t *streamptr, int tsID);
 int    iegInqRecord(stream_t *streamptr, int *varID, int *levelID);
 void   iegDefRecord(stream_t *streamptr);
 void   iegCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   iegReadRecord(stream_t *streamptr, double *data, int *nmiss);
+void   iegReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
 void   iegWriteRecord(stream_t *streamptr, const double *data);
 
-void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
+void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
 void   iegWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
-void   iegReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
+void   iegReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
 void   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
 #endif  /* _STREAM_IEG_H */
diff --git a/libcdi/src/stream_read.c b/libcdi/src/stream_read.c
index 031ef34..2f82c32 100644
--- a/libcdi/src/stream_read.c
+++ b/libcdi/src/stream_read.c
@@ -15,7 +15,7 @@
 
 /* the single image implementation */
 static
-int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
+int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, size_t *nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -90,7 +90,7 @@ int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmis
 @Function  streamReadVar
 @Title     Read a variable
 
- at Prototype void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+ at Prototype void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
     @Item  varID     Variable identifier.
@@ -103,7 +103,7 @@ The function streamReadVar reads all the values of one time step of a variable
 from an open dataset.
 @EndFunction
 */
-void streamReadVar(int streamID, int varID, double *data, int *nmiss)
+void streamReadVar(int streamID, int varID, double *data, size_t *nmiss)
 {
   cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
 }
@@ -112,7 +112,7 @@ void streamReadVar(int streamID, int varID, double *data, int *nmiss)
 @Function  streamReadVarF
 @Title     Read a variable
 
- at Prototype void streamReadVar(int streamID, int varID, float *data, int *nmiss)
+ at Prototype void streamReadVar(int streamID, int varID, float *data, size_t *nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
     @Item  varID     Variable identifier.
@@ -125,13 +125,13 @@ The function streamReadVar reads all the values of one time step of a variable
 from an open dataset.
 @EndFunction
 */
-void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
+void streamReadVarF(int streamID, int varID, float *data, size_t *nmiss)
 {
   if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
     {
       // In case the file format does not support single precision reading,
       // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(streamInqVlist(streamID), varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       streamReadVar(streamID, varID, conversionBuffer, nmiss);
@@ -142,7 +142,7 @@ void streamReadVarF(int streamID, int varID, float *data, int *nmiss)
 
 
 static
-int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
+int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, size_t *nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -218,7 +218,7 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
 @Function  streamReadVarSlice
 @Title     Read a horizontal slice of a variable
 
- at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
+ at Prototype void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
     @Item  varID     Variable identifier.
@@ -232,12 +232,12 @@ The function streamReadVarSlice reads all the values of a horizontal slice of a
 from an open dataset.
 @EndFunction
 */
-void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int *nmiss)
+void streamReadVarSlice(int streamID, int varID, int levelID, double *data, size_t *nmiss)
 {
   if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
     {
       Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       memset(data, 0, elementCount * sizeof(*data));
     }
 }
@@ -246,7 +246,7 @@ void streamReadVarSlice(int streamID, int varID, int levelID, double *data, int
 @Function  streamReadVarSliceF
 @Title     Read a horizontal slice of a variable
 
- at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+ at Prototype void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead}.
     @Item  varID     Variable identifier.
@@ -260,13 +260,13 @@ The function streamReadVarSliceF reads all the values of a horizontal slice of a
 from an open dataset.
 @EndFunction
 */
-void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int *nmiss)
+void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, size_t *nmiss)
 {
   if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, data, nmiss) )
     {
       // In case the file format does not support single precision reading,
       // we fall back to double precision reading, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       streamReadVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
       for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
@@ -275,7 +275,7 @@ void streamReadVarSliceF(int streamID, int varID, int levelID, float *data, int
 }
 
 static
-int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
+int stream_read_record(int streamID, int memtype, void *data, size_t *nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision reading.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -334,13 +334,13 @@ int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
 }
 
 
-void streamReadRecord(int streamID, double *data, int *nmiss)
+void streamReadRecord(int streamID, double *data, size_t *nmiss)
 {
   stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
 }
 
 
-void streamReadRecordF(int streamID, float *data, int *nmiss)
+void streamReadRecordF(int streamID, float *data, size_t *nmiss)
 {
   if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
     {
@@ -351,7 +351,7 @@ void streamReadRecordF(int streamID, float *data, int *nmiss)
       int vrecID = streamptr->tsteps[tsID].curRecID;
       int recID  = streamptr->tsteps[tsID].recIDs[vrecID];
       int varID  = streamptr->tsteps[tsID].records[recID].varID;
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       streamReadRecord(streamID, conversionBuffer, nmiss);
       for ( size_t i = elementCount; i--; ) data[i] = (float) conversionBuffer[i];
diff --git a/libcdi/src/stream_srv.c b/libcdi/src/stream_srv.c
index cae8a90..2e824d8 100644
--- a/libcdi/src/stream_srv.c
+++ b/libcdi/src/stream_srv.c
@@ -2,11 +2,6 @@
 #  include "config.h"
 #endif
 
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "dmemory.h"
 
 #include "error.h"
@@ -84,7 +79,7 @@ int srvInqRecord(stream_t *streamptr, int *varID, int *levelID)
 }
 */
 
-void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
+void srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss)
 {
   int vlistID  = streamptr->vlistID;
   int fileID   = streamptr->fileID;
@@ -107,12 +102,12 @@ void srvReadRecord(stream_t *streamptr, double *data, int *nmiss)
 
   double missval = vlistInqVarMissval(vlistID, varID);
   int gridID  = vlistInqVarGrid(vlistID, varID);
-  int size    = gridInqSize(gridID);
+  size_t size = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( int i = 0; i < size; i++ )
+  for ( size_t i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -142,8 +137,8 @@ void srvDefRecord(stream_t *streamptr)
   header[3] = record->time;
 
   int gridID = record->gridID;
-  int xsize = gridInqXsize(gridID),
-      ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID),
+         ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -153,8 +148,10 @@ void srvDefRecord(stream_t *streamptr)
   if ( gridInqSize(gridID) != xsize*ysize )
     Error("Internal problem with gridsize!");
 
-  header[4] = xsize;
-  header[5] = ysize;
+  cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
+
+  header[4] = (int)xsize;
+  header[5] = (int)ysize;
   header[6] = 0;
   header[7] = 0;
 
@@ -175,7 +172,7 @@ void srvWriteRecord(stream_t *streamptr, const double *data)
 }
 
 static
-void srv_add_record(stream_t *streamptr, int param, int level, int xsize, int ysize,
+void srv_add_record(stream_t *streamptr, int param, int level, size_t xsize, size_t ysize,
                     size_t recsize, off_t position, int prec)
 {
   int vlistID = streamptr->vlistID;
@@ -636,7 +633,7 @@ int srvInqTimestep(stream_t *streamptr, int tsID)
 }
 
 
-void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, int *nmiss)
+void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
 
@@ -646,7 +643,7 @@ void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   int fileID   = streamptr->fileID;
   /* NOTE: tiles are not supported here! */
   double missval = vlistInqVarMissval(vlistID, varID);
-  int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   int tsid     = streamptr->curTsID;
 
   off_t currentfilepos = fileGetPos(fileID);
@@ -663,7 +660,7 @@ void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
   fileSetPos(fileID, currentfilepos, SEEK_SET);
 
   *nmiss = 0;
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -672,12 +669,12 @@ void srvReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
 }
 
 
-void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *nmiss)
+void srvReadVarDP(stream_t *streamptr, int varID, double *data, size_t *nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) streamptr->vars[varID].recordTable[0].nlevs;
 
   for ( size_t levID = 0; levID < nlevs; levID++)
@@ -703,8 +700,8 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   header[2] = streamptr->tsteps[tsID].taxis.vdate;
   header[3] = streamptr->tsteps[tsID].taxis.vtime;
 
-  int xsize = gridInqXsize(gridID);
-  int ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -714,6 +711,8 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   if ( gridInqSize(gridID) != xsize*ysize )
     Error("Internal problem with gridsize!");
 
+  cdi_check_gridsize_int_limit("SERVICE", gridInqSize(gridID));
+
   header[4] = xsize;
   header[5] = ysize;
   header[6] = 0;
@@ -735,7 +734,7 @@ void srvWriteVarDP(stream_t *streamptr, int varID, const double *data)
   if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
   int vlistID = streamptr->vlistID;
-  size_t gridsize = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   size_t nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
 
   for ( size_t levID = 0; levID < nlevs; levID++ )
diff --git a/libcdi/src/stream_srv.h b/libcdi/src/stream_srv.h
index 3d776ba..0cc2665 100644
--- a/libcdi/src/stream_srv.h
+++ b/libcdi/src/stream_srv.h
@@ -11,13 +11,13 @@ int    srvInqTimestep(stream_t *streamptr, int tsID);
 int    srvInqRecord(stream_t *streamptr, int *varID, int *levelID);
 void   srvDefRecord(stream_t *streamptr);
 void   srvCopyRecord(stream_t *streamptr2, stream_t *streamptr1);
-void   srvReadRecord(stream_t *streamptr, double *data, int *nmiss);
+void   srvReadRecord(stream_t *streamptr, double *data, size_t *nmiss);
 void   srvWriteRecord(stream_t *streamptr, const double *data);
 
-void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
+void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, size_t *nmiss);
 void   srvWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
-void   srvReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, int *nmiss);
+void   srvReadVarSliceDP (stream_t *streamptr, int varID, int levelID,       double *data, size_t *nmiss);
 void   srvWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
 
 #endif  /* _STREAM_SRV_H */
diff --git a/libcdi/src/stream_write.c b/libcdi/src/stream_write.c
index dd8cf2e..bf186d5 100644
--- a/libcdi/src/stream_write.c
+++ b/libcdi/src/stream_write.c
@@ -14,7 +14,7 @@
 
 
 /* the single image implementation */
-int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, int nmiss)
+int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, size_t nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -92,7 +92,7 @@ int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, i
 @Function  streamWriteVar
 @Title     Write a variable
 
- at Prototype void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+ at Prototype void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
     @Item  varID     Variable identifier.
@@ -104,10 +104,10 @@ The function streamWriteVar writes the values of one time step of a variable to
 The values are converted to the external data type of the variable, if necessary.
 @EndFunction
 */
-void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+void streamWriteVar(int streamID, int varID, const double *data, size_t nmiss)
 {
-  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, int nmiss)
-    = (void (*)(int, int, int, const void *, int))
+  void (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
+    = (void (*)(int, int, int, const void *, size_t))
     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
 
   myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
@@ -117,7 +117,7 @@ void streamWriteVar(int streamID, int varID, const double *data, int nmiss)
 @Function  streamWriteVarF
 @Title     Write a variable
 
- at Prototype void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+ at Prototype void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
     @Item  varID     Variable identifier.
@@ -129,10 +129,10 @@ The function streamWriteVarF writes the values of one time step of a variable to
 The values are converted to the external data type of the variable, if necessary.
 @EndFunction
 */
-void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+void streamWriteVarF(int streamID, int varID, const float *data, size_t nmiss)
 {
-  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, int nmiss)
-    = (int (*)(int, int, int, const void *, int))
+  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype, const void *data, size_t nmiss)
+    = (int (*)(int, int, int, const void *, size_t))
     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_).func;
 
   if ( myCdiStreamWriteVar_(streamID, varID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
@@ -141,7 +141,7 @@ void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
       // we fall back to double precision writing, converting the data
       // on the fly.
       int vlistID = streamInqVlist(streamID);
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(vlistID, varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(vlistID, varID));
       elementCount *= (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
@@ -151,7 +151,7 @@ void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
 }
 
 static
-int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
+int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, size_t nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -227,7 +227,7 @@ int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, co
 @Function  streamWriteVarSlice
 @Title     Write a horizontal slice of a variable
 
- at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+ at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
     @Item  varID     Variable identifier.
@@ -240,7 +240,7 @@ The function streamWriteVarSlice writes the values of a horizontal slice of a va
 The values are converted to the external data type of the variable, if necessary.
 @EndFunction
 */
-void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, size_t nmiss)
 {
   cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 }
@@ -249,7 +249,7 @@ void streamWriteVarSlice(int streamID, int varID, int levelID, const double *dat
 @Function  streamWriteVarSliceF
 @Title     Write a horizontal slice of a variable
 
- at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+ at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
     @Item  varID     Variable identifier.
@@ -262,13 +262,13 @@ The function streamWriteVarSliceF writes the values of a horizontal slice of a v
 The values are converted to the external data type of the variable, if necessary.
 @EndFunction
 */
-void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, size_t nmiss)
 {
   if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
       // In case the file format does not support single precision writing,
       // we fall back to double precision writing, converting the data on the fly.
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
       streamWriteVarSlice(streamID, varID, levelID, conversionBuffer, nmiss);
@@ -278,18 +278,18 @@ void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *dat
 
 
 void streamWriteVarChunk(int streamID, int varID,
-                         const int rect[][2], const double *data, int nmiss)
+                         const int rect[][2], const double *data, size_t nmiss)
 {
   void (*myCdiStreamWriteVarChunk_)(int streamID, int varID, int memtype,
-                                    const int rect[][2], const void *data, int nmiss)
-    = (void (*)(int, int, int, const int [][2], const void *, int))
+                                    const int rect[][2], const void *data, size_t nmiss)
+    = (void (*)(int, int, int, const int [][2], const void *, size_t))
     namespaceSwitchGet(NSSWITCH_STREAM_WRITE_VAR_CHUNK_).func;
   myCdiStreamWriteVarChunk_(streamID, varID, MEMTYPE_DOUBLE, rect, data, nmiss);
 }
 
 /* single image implementation */
 void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                             const int rect[][2], const void *data, int nmiss)
+                             const int rect[][2], const void *data, size_t nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
@@ -336,7 +336,7 @@ void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
 }
 
 static
-int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
+int stream_write_record(int streamID, int memtype, const void *data, size_t nmiss)
 {
   // May fail if memtype == MEMTYPE_FLOAT and the file format does not support single precision writing.
   // A value > 0 is returned in this case, otherwise it returns zero.
@@ -397,7 +397,7 @@ int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
 @Function  streamWriteRecord
 @Title     Write a horizontal slice of a variable
 
- at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
+ at Prototype void streamWriteRecord(int streamID, const double *data, size_t nmiss)
 @Parameter
     @Item  streamID  Stream ID, from a previous call to @fref{streamOpenWrite}.
     @Item  data      Pointer to a block of double precision floating point data values to be written.
@@ -408,13 +408,13 @@ The function streamWriteRecord writes the values of a horizontal slice (record)
 The values are converted to the external data type of the variable, if necessary.
 @EndFunction
 */
-void streamWriteRecord(int streamID, const double *data, int nmiss)
+void streamWriteRecord(int streamID, const double *data, size_t nmiss)
 {
   stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
 }
 
 
-void streamWriteRecordF(int streamID, const float *data, int nmiss)
+void streamWriteRecordF(int streamID, const float *data, size_t nmiss)
 {
   if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
@@ -422,7 +422,7 @@ void streamWriteRecordF(int streamID, const float *data, int nmiss)
       // we fall back to double precision writing, converting the data on the fly.
       stream_t *streamptr = stream_to_pointer(streamID);
       int varID = streamptr->record->varID;
-      size_t elementCount = (size_t) gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      size_t elementCount = gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
       double *conversionBuffer = (double *) Malloc(elementCount*sizeof(*conversionBuffer));
       for ( size_t i = elementCount; i--; ) conversionBuffer[i] = (double) data[i];
       streamWriteRecord(streamID, conversionBuffer, nmiss);
diff --git a/libcdi/src/varscan.c b/libcdi/src/varscan.c
index 98328a3..130cde2 100644
--- a/libcdi/src/varscan.c
+++ b/libcdi/src/varscan.c
@@ -1013,7 +1013,7 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, c
 	      zaxisDefUbounds(zaxisID, levels2);
 	    }
 
-          if ( cvals != NULL && nlevels != 0 && clength != 0 ) zaxisDefCvals(zaxisID, cvals, clength);
+          if ( cvals != NULL && nlevels != 0 && clength != 0 ) zaxisDefCvals(zaxisID, cvals, (int)clength);
 
 	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
             zaxisDefVct(zaxisID, vctsize, vct);
diff --git a/libcdi/src/vlist.c b/libcdi/src/vlist.c
index ab654e0..5dc859d 100644
--- a/libcdi/src/vlist.c
+++ b/libcdi/src/vlist.c
@@ -488,7 +488,7 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
 	  zaxisDefLevels(zaxisID, levels);
 
           if ( zaxistype == ZAXIS_CHAR )
-            zaxisDefCvals(zaxisID, cvals, clen);
+            zaxisDefCvals(zaxisID, cvals, (int)clen);
 
 	  if ( has_bounds )
 	    {
@@ -819,8 +819,8 @@ void vlistMerge(int vlistID2, int vlistID1)
     {
       for ( varID = 0; varID < nvars2; varID++ )
 	{
-          int ngp1 = gridInqSize(vars1[varID].gridID);
-          int ngp2 = gridInqSize(vars2[varID].gridID);
+          size_t ngp1 = gridInqSize(vars1[varID].gridID);
+          size_t ngp2 = gridInqSize(vars2[varID].gridID);
           if ( ngp1 != ngp2 ) break;
 
 	  if ( vars1[varID].name && vars2[varID].name )
@@ -1137,7 +1137,7 @@ void vlistPrintKernel(vlist_t *vlistptr, FILE *fp)
       fputs("\n"
             " varID  size iorank\n", fp);
       for ( int varID = 0; varID < nvars; varID++ )
-        fprintf(fp, "%3d %8d %6d\n", varID,
+        fprintf(fp, "%3d %8zu %6d\n", varID,
                 zaxisInqSize(vlistptr->vars[varID].zaxisID)
                 * gridInqSize(vlistptr->vars[varID].gridID),
                 vlistptr->vars[varID].iorank);
@@ -1293,15 +1293,15 @@ int vlistInqModel(int vlistID)
 }
 
 
-int vlistGridsizeMax(int vlistID)
+size_t vlistGridsizeMax(int vlistID)
 {
-  int gridsizemax = 0;
+  size_t gridsizemax = 0;
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
   for ( int index = 0 ; index < vlistptr->ngrids ; index++ )
     {
       int gridID = vlistptr->gridIDs[index];
-      int gridsize = gridInqSize(gridID);
+      size_t gridsize = gridInqSize(gridID);
       if ( gridsize > gridsizemax ) gridsizemax = gridsize;
     }
 
diff --git a/libcdi/src/vlist_var.c b/libcdi/src/vlist_var.c
index 9990cf7..92e1efc 100644
--- a/libcdi/src/vlist_var.c
+++ b/libcdi/src/vlist_var.c
@@ -1,9 +1,7 @@
 #if defined (HAVE_CONFIG_H)
-#  include "config.h"
+#include "config.h"
 #endif
 
-#include <limits.h>
-
 #include "dmemory.h"
 #include "cdi.h"
 #include "cdi_int.h"
@@ -17,8 +15,8 @@
 #include "error.h"
 
 #if  defined  (HAVE_LIBGRIB_API)
-#  include "file.h"
-#  include <grib_api.h>
+#include "file.h"
+#include <grib_api.h>
 #endif
 
 
@@ -694,18 +692,18 @@ int vlistInqVarID(int vlistID, int code)
 }
 
 
-int vlistInqVarSize(int vlistID, int varID)
+size_t vlistInqVarSize(int vlistID, int varID)
 {
   vlistCheckVarID(__func__, vlistID, varID);
 
   int zaxisID, gridID, timetype;
   vlistInqVar(vlistID, varID, &gridID, &zaxisID, &timetype);
 
-  int nlevs = zaxisInqSize(zaxisID);
+  size_t nlevs = (size_t)zaxisInqSize(zaxisID);
 
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
-  int size = gridsize*nlevs;
+  size_t size = gridsize*nlevs;
 
   return size;
 }
diff --git a/libcdi/src/zaxis.c b/libcdi/src/zaxis.c
index 108714f..59600ca 100644
--- a/libcdi/src/zaxis.c
+++ b/libcdi/src/zaxis.c
@@ -783,20 +783,20 @@ void zaxisDefLevels(int zaxisID, const double *levels)
 }
 
 
-void zaxisDefCvals(int zaxisID, const char **cvals, size_t clen)
+void zaxisDefCvals(int zaxisID, const char **cvals, int clen)
 {
   zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
-  size_t size = (size_t)zaxisptr->size;
+  int size = zaxisptr->size;
 
   if ( cvals && clen )
     {
       zaxisptr->clength = clen;
-      zaxisptr->cvals = (char**) Malloc(size*sizeof(char *));
+      zaxisptr->cvals = (char**) Malloc((size_t)size*sizeof(char *));
 
-      for ( size_t ilev = 0; ilev < size; ++ilev )
+      for ( int ilev = 0; ilev < size; ++ilev )
         {
-          zaxisptr->cvals[ilev] = Malloc(clen*sizeof(char));
-          memcpy(zaxisptr->cvals[ilev],cvals[ilev], clen*sizeof(char));
+          zaxisptr->cvals[ilev] = Malloc((size_t)clen*sizeof(char));
+          memcpy(zaxisptr->cvals[ilev],cvals[ilev], (size_t)clen*sizeof(char));
         }
       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
     }
diff --git a/libcdi/tests/Makefile.in b/libcdi/tests/Makefile.in
index 4f0df77..ba1d819 100644
--- a/libcdi/tests/Makefile.in
+++ b/libcdi/tests/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -95,23 +105,6 @@ check_PROGRAMS = cksum_verify$(EXEEXT) test_grib$(EXEEXT) \
 @USE_MPI_TRUE at am__append_2 = test_resource_copy_mpi_run
 @USE_MPI_TRUE at am__append_3 = test_resource_copy_mpi
 subdir = tests
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs \
-	$(srcdir)/test_cksum_grib.in $(srcdir)/test_cksum_nc.in \
-	$(srcdir)/test_cksum_nc2.in $(srcdir)/test_cksum_nc4.in \
-	$(srcdir)/test_cksum_extra.in $(srcdir)/test_cksum_service.in \
-	$(srcdir)/test_cksum_ieg.in $(srcdir)/test_chunk_cksum.in \
-	$(srcdir)/test_f2003.in $(srcdir)/pio_write_run.in \
-	$(srcdir)/pio_write_deco2d_run.in \
-	$(srcdir)/pio_cksum_mpinonb.in \
-	$(srcdir)/pio_cksum_mpi_fw_ordered.in \
-	$(srcdir)/pio_cksum_mpi_fw_at_all.in \
-	$(srcdir)/pio_cksum_mpi_fw_at_reblock.in \
-	$(srcdir)/pio_cksum_fpguard.in $(srcdir)/pio_cksum_asynch.in \
-	$(srcdir)/pio_cksum_writer.in $(srcdir)/pio_cksum_cdf.in \
-	$(srcdir)/test_resource_copy_mpi_run.in \
-	$(srcdir)/test_cdf_transformation.in \
-	$(srcdir)/test_cdf_const.in $(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps =  \
 	$(top_srcdir)/m4/acx_assert_lang_is_fortran_variant.m4 \
@@ -143,6 +136,7 @@ am__aclocal_m4_deps =  \
 	$(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = test_cksum_grib test_cksum_nc test_cksum_nc2 \
@@ -325,6 +319,23 @@ am__tty_colors = { \
     std=''; \
   fi; \
 }
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/pio_cksum_asynch.in \
+	$(srcdir)/pio_cksum_cdf.in $(srcdir)/pio_cksum_fpguard.in \
+	$(srcdir)/pio_cksum_mpi_fw_at_all.in \
+	$(srcdir)/pio_cksum_mpi_fw_at_reblock.in \
+	$(srcdir)/pio_cksum_mpi_fw_ordered.in \
+	$(srcdir)/pio_cksum_mpinonb.in $(srcdir)/pio_cksum_writer.in \
+	$(srcdir)/pio_write_deco2d_run.in $(srcdir)/pio_write_run.in \
+	$(srcdir)/test_cdf_const.in \
+	$(srcdir)/test_cdf_transformation.in \
+	$(srcdir)/test_chunk_cksum.in $(srcdir)/test_cksum_extra.in \
+	$(srcdir)/test_cksum_grib.in $(srcdir)/test_cksum_ieg.in \
+	$(srcdir)/test_cksum_nc.in $(srcdir)/test_cksum_nc2.in \
+	$(srcdir)/test_cksum_nc4.in $(srcdir)/test_cksum_service.in \
+	$(srcdir)/test_f2003.in \
+	$(srcdir)/test_resource_copy_mpi_run.in \
+	$(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -571,7 +582,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign tests/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -1060,6 +1070,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 #
 clean-local: clean-local-dirs
 .PHONY: clean-local-dirs
diff --git a/libcdi/tests/stream_cksum.c b/libcdi/tests/stream_cksum.c
index 4f8e458..fa6eb53 100644
--- a/libcdi/tests/stream_cksum.c
+++ b/libcdi/tests/stream_cksum.c
@@ -159,7 +159,7 @@ cksum_stream(const char *fname, size_t *table_len)
         // Read var1 and var2
         for (int varIdx = 0; varIdx < nvars; ++varIdx)
           {
-            int nmiss;
+            size_t nmiss;
             streamReadVar(streamID, varIdx, buf, &nmiss);
             memcrc_r(checksum_state + varIdx, (const unsigned char *)vdatetime,
                      sizeof (vdatetime));
diff --git a/libcdi/tests/test_cdf_read.c b/libcdi/tests/test_cdf_read.c
index a3e2c60..2a8de8b 100644
--- a/libcdi/tests/test_cdf_read.c
+++ b/libcdi/tests/test_cdf_read.c
@@ -41,7 +41,7 @@ int main(int argc, const char **argv)
         {
           size_t memSize = (size_t)vlistInqVarSize(vlistID, (int)varID)
             * sizeof (double);
-          int nmiss;
+          size_t nmiss;
           if (memSize > bufSize)
             {
               double *temp = (double *)realloc(buf, memSize);
@@ -53,7 +53,7 @@ int main(int argc, const char **argv)
               buf = temp;
             }
           streamReadVar(streamID, (int)varID, buf, &nmiss);
-          allNmissSum += (size_t)nmiss;
+          allNmissSum += nmiss;
         }
     }
   if (countMissingValues)
diff --git a/libcdi/tests/test_grib.c b/libcdi/tests/test_grib.c
index f420278..5645c0f 100644
--- a/libcdi/tests/test_grib.c
+++ b/libcdi/tests/test_grib.c
@@ -26,7 +26,7 @@ int main()
   int tsID;
   int levelID;
   int vlistID, taxisID;
-  int nmiss;
+  size_t nmiss;
 
 
   size_t datasize = (size_t)nlon * (size_t)nlat;
diff --git a/m4/acx_cfortran_flags.m4 b/m4/acx_cfortran_flags.m4
new file mode 100644
index 0000000..35fe2cd
--- /dev/null
+++ b/m4/acx_cfortran_flags.m4
@@ -0,0 +1,171 @@
+dnl acx_fc_c_link.m4 --- transform library c flags into version
+dnl                      that suits the fortran compiler
+dnl
+dnl Copyright  (C)  2011  Thomas Jahns <jahns at dkrz.de>
+dnl
+dnl Version: 1.0
+dnl Keywords:
+dnl Author: Thomas Jahns <jahns at dkrz.de>
+dnl Maintainer: Thomas Jahns <jahns at dkrz.de>
+dnl URL: https://www.dkrz.de/redmine/projects/show/scales-ppm
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are  permitted provided that the following conditions are
+dnl met:
+dnl
+dnl Redistributions of source code must retain the above copyright notice,
+dnl this list of conditions and the following disclaimer.
+dnl
+dnl Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl
+dnl Neither the name of the DKRZ GmbH nor the names of its contributors
+dnl may be used to endorse or promote products derived from this software
+dnl without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+dnl IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+dnl TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+dnl PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+dnl OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+dnl
+dnl ACX_FC_XLF_QEXTNAME_ADD_APPENDUS
+dnl Test if compiler is xlf and if -qextname is in use.
+dnl Add -Dappendus to CPPFLAGS if the above applies.
+dnl
+AC_DEFUN([ACX_XLF_QEXTNAME_ADD_APPENDUS],
+  [AS_CASE([$host],
+     [*-ibm-aix*],
+     [AC_MSG_CHECKING([if -Dappendus needs to be added to CPPFLAGS for cfortran.h])
+      AS_IF([$CC -qversion 2>&1 | grep '^IBM XL C' >/dev/null],
+        [acx_temp_qextname_f77flags=`echo "$FFLAGS" | sed -n '/-qextname/{ s/^\(.* \)*-qextname\( .*\)*$/-qextname/;p;}'`
+         acx_temp_qextname_fcflags=`echo "$FCFLAGS" | sed -n '/-qextname/{ s/^\(.* \)*-qextname\( .*\)*$/-qextname/;p;}'`
+      dnl pretend the same option as for FC was used if F77 isn't used at all
+      dnl also in case a non-xl compiler is used it will append an underscore
+         AC_PROVIDE_IFELSE([AC_PROG_F77],,
+           [AC_PROVIDE_IFELSE([AC_PROG_FC],
+              [acx_temp_qextname_f77flags=$acx_temp_qextname_fcflags],
+              [m4_fatal([AC_PROG_F77 or AC_PROG_FC must have been invoked prior to ACX_XLF_QEXTNAME_ADD_APPENDUS])])])
+      dnl and vice versa for FC
+         AC_PROVIDE_IFELSE([AC_PROG_FC],
+           [AS_IF([$FC -qversion 2>&1 | grep '^IBM XL Fortran' >/dev/null],,
+              [acx_temp_qextname_fcflags=-qextname])],
+           [AC_PROVIDE_IFELSE([AC_PROG_F77],
+              [acx_temp_qextname_fcflags=$acx_temp_qextname_f77flags])])
+         AS_CASE([x"$acx_temp_qextname_fcflags$acx_temp_qextname_f77flags"],
+           [x-qextname],
+           [AC_MSG_ERROR([Option -qextname must be provided consistently to F77 and FC])],
+           [x-qextname-qextname],
+           [AC_MSG_RESULT([yes])
+            CPPFLAGS="${CPPFLAGS+$CPPFLAGS }-Dappendus"],
+           [AC_MSG_RESULT([no])])
+        ],[AC_MSG_RESULT([no])])])])
+dnl
+dnl automate flag elicitation for cfortran.h
+AC_DEFUN([_ACX_FIND_CFORTRAN_DEF],
+  [AC_REQUIRE([AC_CANONICAL_HOST])
+   _AC_FORTRAN_ASSERT
+   AC_LANG_CASE([Fortran],[save_FC=$FC ; acx_FC=$FC],
+     [Fortran 77],[save_F77=$F77 ; acx_FC=$F77])
+   AS_CASE([$host],
+     [x86_64-*-linux-*|i*86-*-linux-*|*-apple-darwin*|ia64-*-linux-*|x86_64-*-freebsd*|i*86-*-freebsd*],
+     [acx_temp=`$acx_FC -V 2>&1`
+      AS_IF([echo "$acx_temp" | grep '^Copyright.*\(The Portland Group\|NVIDIA CORPORATION\)' >/dev/null],
+        [AS_VAR_SET([acx_cf_flag],[-DgFortran])],
+        [echo "$acx_temp" | grep '^NAG Fortran Compiler Release' >/dev/null],
+        [AS_VAR_SET([acx_cf_flag],[-DNAGf90Fortran])],
+        [echo "$acx_temp" | grep '^Intel(R) Fortran.*Compiler' >/dev/null],
+        [AS_VAR_SET([acx_cf_flag],[-DgFortran])],
+        [echo "$acx_temp" | grep '^Cray Fortran' >/dev/null],
+        [AS_VAR_SET([acx_cf_flag],[-DgFortran])],
+        [acx_temp=`$acx_FC --version 2>&1` \
+         && echo $acx_temp | grep '^GNU Fortran' >/dev/null],
+        [AS_IF([echo $acx_temp | grep g77 >/dev/null],
+           [AS_VAR_SET([acx_cf_flag],[-Dg77Fortran])],
+           [dnl assume gfortran
+dnl check if compiling with f2c bindings or with default bindings
+            AS_IF([echo "]AC_LANG_CASE([Fortran],[$FCFLAGS],
+              [Fortran 77],[$FFLAGS])[" | grep '^\(.* \)*-ff2c\( .*\)*$' >/dev/null],
+              [AS_VAR_SET([acx_cf_flag],[-Df2cFortran])],
+              [AS_VAR_SET([acx_cf_flag],[-DgFortran])])])],
+        [acx_temp=`$acx_FC -v 2>&1` \
+         && echo $acx_temp | grep '^f2c'],
+        [AS_VAR_SET([acx_cf_flag],[-Df2cFortran])])],
+     [*-ibm-aix*],
+     [dnl xlc set _IBMR2 so nothing needs to be done
+      AS_IF([$CC -qversion 2>&1 | grep '^IBM XL C' >/dev/null],,
+        [dnl but for other compilers set IBMR2Fortran
+         AS_VAR_SET([acx_cf_flag],[-DIBMR2Fortran])])
+     ],
+     [*-*-hpux*],
+     [AS_VAR_SET([acx_cf_flag],[-DhpuxFortran])],
+     [sx*-*-*|es*-*-*],
+     [dnl fixme: make sure user is actually using sxf90
+dnl but currently there is no alternative I know of
+      AS_VAR_SET([acx_cf_flag],[-DSXFortran])])])
+
+AC_DEFUN([ACX_FIND_CFORTRAN_DEF],
+  [AC_CACHE_CHECK([C preprocessor flags for Fortran calling convention cfortran.h],
+     [acx_cv_cf_flag],
+     [acx_cv_cf_flag=''
+dnl test if user already provided a flag
+      AS_FOR([MACRO],[macro],[pgiFortran NAGf90Fortran f2cFortran hpuxFortran apolloFortran sunFortran IBMR2Fortran CRAYFortran PATHSCALE_COMPILER gFortran mipsFortran DECFortran vmsFortran CONVEXFortran PowerStationFortran AbsoftUNIXFortran AbsoftProFortran SXFortran],
+        [acx_temp=`echo "$CPPFLAGS $CFLAGS" | sed -n 's/^\(.* \)*-D\('"MACRO"'\)\( .*\)*$/\2/;t print
+b
+: print
+p'`
+         AS_IF([test x"$acx_temp" != x],
+           [AS_IF([test x"$acx_cv_cf_flag" = x],
+              [acx_cv_cf_flag="$acx_temp (user-specified)"],
+              [echo ; echo '"'"$acx_cv_cf_flag $acx_temp"'"'
+               AC_MSG_ERROR([Multiple specification of cfortran.h flags])])])])
+dnl find automatically from machine/compiler
+      AS_IF([test x"$acx_cv_cf_flag" = x],
+        [AC_PROVIDE_IFELSE([AC_PROG_FC],
+           [AS_IF([test -n "$FC" -a X"$FC" != Xno],
+              [AC_LANG_PUSH([Fortran])
+               AS_VAR_PUSHDEF([acx_cf_flag],[acx_cv_]_AC_LANG_ABBREV[_cf_flag])
+               _ACX_FIND_CFORTRAN_DEF
+               AS_VAR_POPDEF([acx_cf_flag])
+               AC_LANG_POP([Fortran])])])
+         AC_PROVIDE_IFELSE([AC_PROG_F77],
+           [AS_IF([test -n "$F77" -a X"$F77" != Xno],
+              [AC_LANG_PUSH([Fortran 77])
+               AS_VAR_PUSHDEF([acx_cf_flag],[acx_cv_]_AC_LANG_ABBREV[_cf_flag])
+               _ACX_FIND_CFORTRAN_DEF
+               AS_VAR_POPDEF([acx_cf_flag])
+               AC_LANG_POP([Fortran 77])])])
+dnl check f77 flag matches fc flag
+         AC_PROVIDE_IFELSE([AC_PROG_F77],
+           [AC_PROVIDE_IFELSE([AC_PROG_FC],
+              [dnl both FC and F77 are configured
+               AS_IF([test -z "$F77" -o X"$F77" = Xno],
+                 [acx_cv_cf_flag="$acx_cv_fc_cf_flag (probed)"],
+                 [test -z "$FC" -o X"$FC" = Xno],
+                 [acx_cv_cf_flag="$acx_cv_f77_cf_flag (probed)"],
+                 [AS_IF([test x"$acx_cv_f77_cf_flag" = x"$acx_cv_fc_cf_flag"],
+                    [acx_cv_cf_flag="$acx_cv_f77_cf_flag (probed)"],
+                    [AC_MSG_ERROR([cfortran.h flag for $F77 does not match the flag for $FC.
+Have you configured compatible compilers?])])])
+              ],
+              [acx_cv_cf_flag="$acx_cv_f77_cf_flag (probed)"])],
+           [acx_cv_cf_flag="$acx_cv_fc_cf_flag (probed)"])
+        ])
+     ])
+dnl now that flag is established, add (probed) defines to CPPFLAGS
+   AS_IF([echo "$acx_cv_cf_flag" | grep ' (probed)$' >/dev/null],
+     [CPPFLAGS="${CPPFLAGS+$CPPFLAGS }`echo "$acx_cv_cf_flag" | sed 's/ (probed)$//'`"])
+  ])
+dnl
+dnl Local Variables:
+dnl mode: autoconf
+dnl license-project-url: "https://www.dkrz.de/redmine/projects/show/scales-ppm"
+dnl license-default: "bsd"
+dnl End:
diff --git a/m4/acx_check_cfortran.m4 b/m4/acx_check_cfortran.m4
new file mode 100644
index 0000000..c69ebd0
--- /dev/null
+++ b/m4/acx_check_cfortran.m4
@@ -0,0 +1,275 @@
+dnl acx_check_cfortran.m4 --- test if a program compiled from
+dnl                           a main Fortran program and
+dnl                           C functions gives expected results
+dnl
+dnl Copyright  (C)  2013  Thomas Jahns <jahns at dkrz.de>
+dnl
+dnl Version: 1.0
+dnl Keywords:
+dnl Author: Thomas Jahns <jahns at dkrz.de>
+dnl Maintainer: Thomas Jahns <jahns at dkrz.de>
+dnl URL: https://www.dkrz.de/redmine/projects/show/scales-ppm
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are  permitted provided that the following conditions are
+dnl met:
+dnl
+dnl Redistributions of source code must retain the above copyright notice,
+dnl this list of conditions and the following disclaimer.
+dnl
+dnl Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl
+dnl Neither the name of the DKRZ GmbH nor the names of its contributors
+dnl may be used to endorse or promote products derived from this software
+dnl without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+dnl IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+dnl TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+dnl PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+dnl OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+dnl EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+dnl PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+dnl PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+dnl LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+dnl NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+dnl SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+dnl
+dnl helper function to emit Fortran test code
+AC_DEFUN([_ACX_CHECK_CFORTRAN_FC],
+  [AC_LANG_PUSH([Fortran])
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+[      MODULE conftest_data
+      IMPLICIT NONE
+      PRIVATE
+      REAL :: ri
+      PUBLIC :: ri
+      END MODULE conftest_data
+
+      FUNCTION cftstf(v) RESULT(r)
+      USE conftest_data, ONLY: ri
+      REAL, INTENT(in) :: v
+      REAL :: r
+      r = v * 100.0
+      ri = 1.0 / v
+      END FUNCTION cftstf])],
+           [_AC_RUN_LOG([mv "conftest.$ac_objext" "conftest_f.$ac_objext"],
+              [_AS_ECHO_LOG([Renaming Fortran object file.])])
+            save_LIBS=$LIBS
+            LIBS="conftest_c.$ac_objext conftest_f.$ac_objext $LIBS"
+            AC_RUN_IFELSE([AC_LANG_PROGRAM(,
+[      USE conftest_data, ONLY: ri
+      IMPLICIT NONE
+      INTERFACE
+       FUNCTION cftstc(i, v, p, q) RESULT(f)
+         INTEGER, INTENT(in) :: i
+         REAL, INTENT(in) :: v
+         INTEGER, INTENT(out) :: p
+         REAL, INTENT(out) :: q
+         REAL :: f
+       END FUNCTION cftstc
+       FUNCTION chtst() result(s)
+         CHARACTER(99) :: s
+       END FUNCTION chtst
+      END INTERFACE
+      REAL, PARAMETER :: eps = 10e-6
+      REAL :: foo, boo, too
+      INTEGER :: bar, baz, i
+      CHARACTER(99) :: aaaaaa
+      bar = 5
+      foo = 0.3
+      too = cftstc(bar, foo, baz, boo)
+      IF (ABS(baz - NINT(bar * foo)) /= 0) THEN
+        WRITE (0, '(2(a,i0))') "error checking, when baz, baz=", baz, &
+             ", NINT(bar * foo) =", NINT(bar * foo)
+        FLUSH(0)
+        CALL err_exit
+      END IF
+      IF (ABS((ri - 1.0 / (bar * foo)) / ABS(ri)) > eps)  THEN
+        WRITE (0, '(2(a,g24.15))') "error checking ri, ri=", ri, ", 1.0 / &
+             &(bar * foo) = ", 1.0 / (bar * foo)
+        FLUSH(0)
+        CALL err_exit
+      END IF
+      IF (ABS((boo - (bar * foo * 100.0))/ABS(boo)) > eps)  THEN
+        WRITE (0, '(2(a,g24.15))') "error checking boo, boo=", boo, &
+             ", bar * foo * 100.0 = ", bar * foo * 100.0
+        FLUSH(0)
+        CALL err_exit
+      END IF
+      IF (too /= boo) THEN
+        WRITE (0, '(2(a,g24.15))') "error checking too vs. boo, too=", too, &
+             ", boo = ", boo
+        FLUSH(0)
+        CALL err_exit
+      END IF
+      aaaaaa = chtst()
+      DO i = 1, 99
+        IF (aaaaaa(i:i) /= 'A') THEN
+          WRITE (0, '(a,i0,a)') "error checking aaaaaa(", i, ")=", &
+              aaaaaa(i:i)
+          FLUSH(0)
+          CALL err_exit
+        END IF
+      END DO])],
+              [acx_cv_cfortran_works=yes],
+              [acx_cv_cfortran_works="error"],
+              [AC_MSG_NOTICE([Skipping run test for cfortran.h in cross-compilation mode,])
+	       AC_MSG_NOTICE([link test succeeded.])
+               acx_cv_cfortran_works=yes])
+	    LIBS=$save_LIBS],
+           [acx_cv_cfortran_works="error compiling Fortran subroutine"])
+         AC_LANG_POP([Fortran])])
+
+dnl helper function to emit Fortran 77 test code
+AC_DEFUN([_ACX_CHECK_CFORTRAN_F77],
+  [AC_LANG_PUSH([Fortran 77])
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+[      REAL FUNCTION CFTSTF(v)
+      REAL RI
+      COMMON /CFTSTD/ RI
+      REAL V
+      REAL R
+      CFTSTF = V * 100.0
+      RI = 1.0 / V
+      END FUNCTION CFTSTF])],
+           [_AC_RUN_LOG([mv "conftest.$ac_objext" "conftest_f.$ac_objext"],
+              [_AS_ECHO_LOG([Renaming Fortran object file.])])
+            save_LIBS=$LIBS
+            LIBS="conftest_c.$ac_objext conftest_f.$ac_objext $LIBS"
+            AC_RUN_IFELSE([AC_LANG_PROGRAM(,
+[      REAL RI
+      COMMON /CFTSTD/ RI
+      REAL EPS
+      PARAMETER(EPS=10E-6)
+      REAL FOO, BOO, TOO
+      INTEGER BAR, BAZ, I
+      CHARACTER(99) AAAAAA
+      EXTERNAL CFTSTC, CFTSTF, CHTST, ERR_EXIT
+      REAL CFTSTC, CFTSTF
+      CHARACTER(99) CHTST
+      BAR = 5
+      FOO = 0.3
+      TOO = CFTSTC(BAR, FOO, BAZ, BOO)
+      IF (ABS(BAZ - NINT(BAR * FOO)) /= 0) THEN
+        WRITE (0, '(2(A,I0))') "ERROR CHECKING, WHEN BAZ, BAZ=", BAZ,
+     &       ", NINT(BAR * FOO) =", NINT(BAR * FOO)
+        CALL ERR_EXIT
+      END IF
+      IF (ABS((RI - 1.0 / (BAR * FOO)) / ABS(RI)) > EPS)  THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING RI, RI=", RI, ",
+     &       1.0 / (BAR * FOO) = ", 1.0 / (BAR * FOO)
+        CALL err_exit
+      END IF
+      IF (ABS((BOO - (BAR * FOO * 100.0))/ABS(BOO)) > EPS)  THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING BOO, BOO=", BOO,
+     &       ", BAR * FOO * 100.0 = ", BAR * FOO * 100.0
+        CALL ERR_EXIT
+      END IF
+      IF (TOO /= BOO) THEN
+        WRITE (0, '(2(A,F24.15))') "ERROR CHECKING TOO VS. BOO, TOO=",
+     &       TOO, ", BOO = ", BOO
+        CALL ERR_EXIT
+      END IF
+      AAAAAA = CHTST()
+      DO i = 1, 99
+        IF (AAAAAA(I:I) /= 'A') THEN
+          WRITE (0, '(A,I0,2A)') "ERROR CHECKING AAAAAA(", I, ")=",
+     &        AAAAAA(I:I)
+          CALL ERR_EXIT
+        END IF
+      END DO])],
+              [acx_cv_cfortran_works=yes],
+              [acx_cv_cfortran_works="error"],
+              [AC_MSG_NOTICE([Skipping run test for cfortran.h in cross-compilation mode,])
+	       AC_MSG_NOTICE([link test succeeded.])
+               acx_cv_cfortran_works=yes])
+	    LIBS=$save_LIBS],
+           [acx_cv_cfortran_works="error compiling Fortran subroutine"])
+         AC_LANG_POP([Fortran 77])])
+
+dnl ACX_CHECK_CFORTRAN([OPTIONAL-CFORTRAN-INC-DIR],[ACTION-IF-SUCCESS],
+dnl                    [ACTION-IF-FAILED])
+dnl Test if C compiler can produce objects that link fine to Fortran programs
+dnl when using cfortran.h.
+dnl
+AC_DEFUN([ACX_CHECK_CFORTRAN],
+  [AC_CACHE_CHECK([if C externals constructed with cfortran.h work],
+     [acx_cv_cfortran_works],
+     [acx_cv_cfortran_works=no
+      save_CPPFLAGS=$CPPFLAGS
+      CPPFLAGS="-I]m4_ifval([$1],[$1],[$srcdir/include])[ $CPPFLAGS"
+dnl build C function
+      AC_LANG_PUSH([C])
+      AC_COMPILE_IFELSE([AC_LANG_SOURCE([@%:@include "cfortran.h"
+@%:@include <math.h>
+@%:@include <stdio.h>
+@%:@include <stdlib.h>
+
+PROTOCCALLSFFUN1(FLOAT,CFTSTF,cftstf,FLOAT)
+#define conftest_F(v) \
+  CCALLSFFUN1(CFTSTF,cftstf,FLOAT,(v));
+
+static float
+cftstC(int i, float v, int *p, float *q)
+{
+  float f;
+  *p = (int)roundf(v * i);
+  *q = f = conftest_F(v * i);
+  return f;
+}
+
+FCALLSCFUN4(FLOAT,cftstC,CFTSTC,cftstc,INT,FLOAT,PINT,PFLOAT)
+
+/* test string returns */
+static const char *
+conftest_str_C(void)
+{
+  static const char msg@<:@100@:>@ = "AAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+  return msg;
+}
+
+FCALLSCFUN0(STRING,conftest_str_C,CHTST,chtst)
+
+/* This function is required simply because some Fortran compilers
+ * won't stop with exit code n when encountering STOP n */
+static void
+errExit(void)
+{
+  exit(1);
+}
+
+FCALLSCSUB0(errExit,ERR_EXIT,err_exit)
+
+])],
+        [_AC_RUN_LOG([mv "conftest.$ac_objext" "conftest_c.$ac_objext"],
+           [_AS_ECHO_LOG([Renaming C object file.])])
+         AC_PROVIDE_IFELSE([AC_PROG_FC],[_ACX_CHECK_CFORTRAN_FC])
+         AC_PROVIDE_IFELSE([AC_PROG_F77],[_ACX_CHECK_CFORTRAN_F77])
+        ],
+        [acx_cv_cfortran_works="compiling with cfortran.h failed"])
+      AC_LANG_POP([C])
+      CPPFLAGS=$save_CPPFLAGS
+     ])
+   m4_ifval([$3],
+     [AS_IF([test x"$acx_cv_cfortran_works" = xyes],[$2],[$3])],
+     [AS_CASE([x"$acx_cv_cfortran_works"],
+       [x"error"],
+       [AC_MSG_FAILURE([Linking/Running with C EXTERNAL built with cfortran.h does not work!])],
+       [x"compiling with cfortran.h failed"],
+       [AC_MSG_FAILURE([Compilation with cfortran.h is not working!])],
+       [x"error compiling Fortran subroutine"],
+       [AC_MSG_FAILURE([compilation of simple Fortran source failed!])],
+       [xyes],[$2],
+       [AC_MSG_FAILURE([Unexpected error when linking C and Fortran via cfortran.h!])])])
+  ])
+dnl
+dnl Local Variables:
+dnl mode: autoconf
+dnl license-project-url: "https://www.dkrz.de/redmine/projects/show/scales-ppm"
+dnl license-default: "bsd"
+dnl End:
diff --git a/src/Adisit.cc b/src/Adisit.cc
index aa4d6c8..f309515 100644
--- a/src/Adisit.cc
+++ b/src/Adisit.cc
@@ -160,7 +160,7 @@ void *Adisit(void *argument)
   int varID, levelID;
   int offset;
   int i;
-  int nmiss;
+  size_t nmiss;
   int thoID = -1, saoID = -1;
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
   double pin = -1;
diff --git a/src/Afterburner.cc b/src/Afterburner.cc
index 3feb434..530c145 100644
--- a/src/Afterburner.cc
+++ b/src/Afterburner.cc
@@ -391,7 +391,7 @@ static
 void *after_readTimestep(void *arg)
 {
   int varID, gridID, zaxisID, levelID, timeID;
-  int nmiss;
+  size_t nmiss;
   RARG *rarg = (RARG *) arg;
 
   int nrecs        = rarg->nrecs;
@@ -1707,7 +1707,7 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
 	  gridID = vars[code].igridID;
 	  zaxisID = vars[code].izaxisID;
           zaxisName(zaxisInqType(zaxisID), zaxistypename);
-	  fprintf(stderr," Detected Code %3d  grid %-8s size %5d  level %2d %-8s\n",
+	  fprintf(stderr," Detected Code %3d  grid %-8s size %5zu  level %2d %-8s\n",
 		  code, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID),
 		  zaxisInqSize(zaxisID), zaxistypename);
 	}
@@ -1812,7 +1812,7 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
 	  gridID  = vars[code].ogridID;
 	  zaxisID = vars[code].ozaxisID;
           zaxisName(zaxisInqType(zaxisID), zaxistypename);
-	  fprintf(stderr," Selected Code %3d  grid %-8s size %5d  level %2d %-8s\n",
+	  fprintf(stderr," Selected Code %3d  grid %-8s size %5zu  level %2d %-8s\n",
 		  code, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID),
 		  zaxisInqSize(zaxisID), zaxistypename);
 	}
diff --git a/src/Arith.cc b/src/Arith.cc
index 7e26534..d4256e1 100644
--- a/src/Arith.cc
+++ b/src/Arith.cc
@@ -37,13 +37,13 @@ void *Arith(void *argument)
 {
   enum {FILL_NONE, FILL_TS, FILL_VAR, FILL_VARTS, FILL_FILE};
   int filltype = FILL_NONE;
-  int nmiss;
+  size_t nmiss;
   int nrecs, nvars = 0;
   int nlevels2 = 1;
   int varID, levelID;
   int levelID2;
-  int *varnmiss2 = NULL;
-  int **varnmiss = NULL;
+  size_t *varnmiss2 = NULL;
+  size_t **varnmiss = NULL;
   double *vardata2 = NULL;
   double **vardata = NULL;
 
@@ -152,7 +152,7 @@ void *Arith(void *argument)
   if ( filltype == FILL_VAR || filltype == FILL_VARTS )
     {
       vardata2 = (double*) Malloc(gridsize*nlevels2*sizeof(double));
-      varnmiss2 = (int*) Malloc(nlevels2*sizeof(int));
+      varnmiss2 = (size_t*) Malloc(nlevels2*sizeof(size_t));
     }
 
   if ( cdoVerbose ) cdoPrint("Number of timesteps: file1 %d, file2 %d", ntsteps1, ntsteps2);
@@ -181,13 +181,13 @@ void *Arith(void *argument)
 	{
 	  nvars  = vlistNvars(vlistIDx2);
 	  vardata  = (double **) Malloc(nvars*sizeof(double *));
-	  varnmiss = (int **) Malloc(nvars*sizeof(int *));
+	  varnmiss = (size_t **) Malloc(nvars*sizeof(size_t *));
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      int gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
 	      int nlev     = zaxisInqSize(vlistInqVarZaxis(vlistIDx2, varID));
 	      vardata[varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	      varnmiss[varID] = (int*) Malloc(nlev*sizeof(int));
+	      varnmiss[varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	    }
 	}
     }
@@ -250,7 +250,7 @@ void *Arith(void *argument)
 	{
 	  pstreamInqRecord(streamIDx1, &varID, &levelID);
 	  pstreamReadRecord(streamIDx1, fieldx1->ptr, &nmiss);
-          fieldx1->nmiss = (size_t) nmiss;
+          fieldx1->nmiss = nmiss;
           int varID2 = varID;
           
 	  if ( tsID == 0 || filltype == FILL_NONE || filltype == FILL_FILE || filltype == FILL_VARTS )
@@ -261,7 +261,7 @@ void *Arith(void *argument)
 		{
 		  pstreamInqRecord(streamIDx2, &varID2, &levelID2);
 		  pstreamReadRecord(streamIDx2, fieldx2->ptr, &nmiss);
-                  fieldx2->nmiss = (size_t) nmiss;
+                  fieldx2->nmiss = nmiss;
                   if ( varID   != varID2 ) cdoAbort("Internal error, varIDs of input streams differ!");
                   if ( levelID != levelID2 ) cdoAbort("Internal error, levelIDs of input streams differ!");
 		}
@@ -311,7 +311,7 @@ void *Arith(void *argument)
 	  farfun(&field1, field2, operfunc);
 
 	  pstreamDefRecord(streamID3, varID, levelID);
-	  pstreamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID3, field1.ptr, field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Arithc.cc b/src/Arithc.cc
index bc0f2e7..2187b63 100644
--- a/src/Arithc.cc
+++ b/src/Arithc.cc
@@ -72,7 +72,7 @@ int *fill_vars(int vlistID)
 
 void *Arithc(void *argument)
 {
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   int varID, levelID;
 
@@ -125,7 +125,7 @@ void *Arithc(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field.ptr, &nmiss);
-          field.nmiss = (size_t) nmiss;
+          field.nmiss = nmiss;
 
 	  if ( vars[varID] )
 	    {
@@ -141,7 +141,7 @@ void *Arithc(void *argument)
 		if ( DBL_IS_EQUAL(field.ptr[i], field.missval) ) field.nmiss++;
 	    }
 
-          nmiss = (int) field.nmiss;
+          nmiss = field.nmiss;
 	  pstreamDefRecord(streamID2, varID, levelID);
 	  pstreamWriteRecord(streamID2, field.ptr, nmiss);
 	}
diff --git a/src/Arithdays.cc b/src/Arithdays.cc
index ad411a6..e580be1 100644
--- a/src/Arithdays.cc
+++ b/src/Arithdays.cc
@@ -73,7 +73,7 @@ void *Arithdays(void *argument)
   int nrecs;
   int varID, levelID;
   int year, month, day;
-  int nmiss;
+  size_t nmiss;
   double rconst;
 
   cdoInitialize(argument);
@@ -143,14 +143,14 @@ void *Arithdays(void *argument)
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field.ptr, &nmiss);
 
-          field.nmiss   = (size_t)nmiss;
+          field.nmiss   = nmiss;
 	  field.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field.missval = vlistInqVarMissval(vlistID1, varID);
 
 	  farcfun(&field, rconst, operfunc);
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, field.ptr, (int)field.nmiss);
+	  pstreamWriteRecord(streamID2, field.ptr, field.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Arithlat.cc b/src/Arithlat.cc
index 79cb79c..0c73f08 100644
--- a/src/Arithlat.cc
+++ b/src/Arithlat.cc
@@ -36,7 +36,7 @@ void *Arithlat(void *argument)
   int gridID0 = -1;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   long i;
   char units[CDI_MAX_NAME];
   double *scale = NULL;
diff --git a/src/CDIread.cc b/src/CDIread.cc
index fabeed1..e020ce4 100644
--- a/src/CDIread.cc
+++ b/src/CDIread.cc
@@ -83,7 +83,7 @@ void *CDIread(void *argument)
 {
   int memtype = CDO_Memtype;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   int filetype = -1, datatype = -1;
   int nruns = 1;
diff --git a/src/CDItest.cc b/src/CDItest.cc
index d893016..d0e008c 100644
--- a/src/CDItest.cc
+++ b/src/CDItest.cc
@@ -30,7 +30,7 @@ void *CDItest(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int max_copy = 3;
   double s_utime, s_stime;
   double e_utime, e_stime;
diff --git a/src/CMOR.cc b/src/CMOR.cc
index 68da1e4..86c919c 100644
--- a/src/CMOR.cc
+++ b/src/CMOR.cc
@@ -941,7 +941,8 @@ static void addcharvar(keyValues_t *charvars, int vlistID, const char *key, stru
     {
       while ( nrecs-- )
         {
-          int varIDrw, levelIDrw, nmiss;
+          int varIDrw, levelIDrw;
+          size_t nmiss;
           pstreamInqRecord(streamID2, &varIDrw, &levelIDrw);
           for ( int i = 0; i < charvars->nvalues; i++ )
             if ( varIDrw == varIDs[i] )
@@ -1256,7 +1257,7 @@ static int check_mem(list_t *kvl, char *project_id)
   char workchar[CMOR_MAX_STRING]; 
   int realization, initialization_method, physics_version, forcing;
   int ipos=0, ppos=0;
-
+*/
 /* Test for the right member, else abort or warn */
 /*
   
@@ -1286,6 +1287,7 @@ static int check_mem(list_t *kvl, char *project_id)
       for ( int i = 0; i < 3; i++ )   
         kv_insert_a_val(kvl, ripchar[i], (char *)"-1", 1);
     }
+*/
 /* Now abort or warn */
 /* 
   if (strcmp(project_id, "CMIP5") == 0 || strcmp(project_id, "CORDEX") == 0)
@@ -1833,7 +1835,7 @@ static void setup_dataset(list_t *kvl, int streamID, int *calendar)
 #elif ( CMOR_VERSION_MAJOR == 3 )
     {
 /***/
-/* Could not give CMOR all attributes separately because some are required to be in a json file (outpath,...). /
+/* Could not give CMOR all attributes separately because some are required to be in a json file (outpath,...). */
 /* Better collect them in this file. */
 /* todo this **/
 /* If a Json file is denoted, read this file and check attributes */
@@ -3680,7 +3682,7 @@ static void read_record(int streamID, struct mapping vars[], int vlistID)
       int latdim = gridInqYsize(gridID);
       int levdim = zaxisInqSize(zaxisID);
       int chardim = gridsize/latdim;
-      int nmiss;
+      size_t nmiss;
       pstreamReadRecord(streamID, buffer, &nmiss);
       for ( size_t i = 0; i < gridsize; i++ )
         {
@@ -4366,7 +4368,7 @@ static void read_maptab(list_t *kvl, int streamID, char *miptabfreq, struct mapp
 /***/
 /* However, if the mapping table contains a keyvalue pair for name or code with more than one value, */
 /* the corresponding variable has a character coordinate and requires special treatment */
-/* This is tested once before mapping. If the special variable equals the variable which is to map,
+/* This is tested once before mapping. If the special variable equals the variable which is to map, */
 /* the special treatment begins with fct addcharvar */
 /***/
 /* Different CMOR variables are built with one model variable. */
diff --git a/src/CMOR_lite.cc b/src/CMOR_lite.cc
index ae778ea..d1397d0 100644
--- a/src/CMOR_lite.cc
+++ b/src/CMOR_lite.cc
@@ -364,7 +364,7 @@ void *CMOR_lite(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   bool delvars = false;
   double missval;
 
diff --git a/src/Cat.cc b/src/Cat.cc
index 5868b88..2061194 100644
--- a/src/Cat.cc
+++ b/src/Cat.cc
@@ -36,7 +36,7 @@ void *Cat(void *argument)
   int streamID2 = CDI_UNDEFID;
   int vlistID2 = CDI_UNDEFID;
   int taxisID2 = CDI_UNDEFID;
-  int nmiss;
+  size_t nmiss;
   double tw0 = 0, tw = 0;
   double *array = NULL;
 
diff --git a/src/Change.cc b/src/Change.cc
index 0a2f6db..5197c01 100644
--- a/src/Change.cc
+++ b/src/Change.cc
@@ -48,7 +48,7 @@ void *Change(void *argument)
   int chcode = 0;
   int param;
   int code, tabnum, i;
-  int nmiss;
+  size_t nmiss;
   int nfound;
   int nzaxis, zaxisID1, zaxisID2, k, nlevs, index; 
   double chlevels[MAXARG];
diff --git a/src/Change_e5slm.cc b/src/Change_e5slm.cc
index a3d31b6..dbbe0e1 100644
--- a/src/Change_e5slm.cc
+++ b/src/Change_e5slm.cc
@@ -32,7 +32,7 @@ void *Change_e5slm(void *argument)
   char name[CDI_MAX_NAME];
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
@@ -60,7 +60,7 @@ void *Change_e5slm(void *argument)
 
   int vlistIDslm = pstreamInqVlist(streamIDslm);
 
-  long gridsize = gridInqSize(vlistInqVarGrid(vlistIDslm, 0));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistIDslm, 0));
 
   double *array = (double*) Malloc(gridsize*sizeof(double));
   double *cland = (double*) Malloc(gridsize*sizeof(double));
@@ -80,7 +80,7 @@ void *Change_e5slm(void *argument)
 
   pstreamClose(streamIDslm);
 
-  for ( long i = 0; i < gridsize; ++i ) lsea[i] = !(cland[i] > 0);
+  for ( size_t i = 0; i < gridsize; ++i ) lsea[i] = !(cland[i] > 0);
 
 
   int nvars = vlistNvars(vlistID1);
diff --git a/src/Cloudlayer.cc b/src/Cloudlayer.cc
index 7cb8fdd..359e14f 100644
--- a/src/Cloudlayer.cc
+++ b/src/Cloudlayer.cc
@@ -127,7 +127,7 @@ void *Cloudlayer(void *argument)
   bool zrev = false;
   int i;
   int offset;
-  int nmiss;
+  size_t nmiss;
   int aclcacID = -1;
   int nvars2 = 0;
   int aclcac_code_found = 0;
diff --git a/src/Collgrid.cc b/src/Collgrid.cc
index 39b6ee2..3f80b19 100644
--- a/src/Collgrid.cc
+++ b/src/Collgrid.cc
@@ -29,7 +29,7 @@ typedef struct
   int streamID;
   int vlistID;
   int gridID;
-  int nmiss;
+  size_t nmiss;
   int gridsize;
   int *gridindex;
   double *array;
@@ -451,7 +451,7 @@ void *Collgrid(void *argument)
   int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  int gridsize2 = 0;
+  size_t gridsize2 = 0;
   for ( int i = 0; i < ngrids2; ++i )
     {
       if ( gridIDs[i] != -1 ) 
@@ -514,7 +514,7 @@ void *Collgrid(void *argument)
 	      if ( cdoVerbose && tsID == 0 ) printf("varID %d %d levelID %d %d\n", varID, varID2, levelID, levelID2);
 
 	      double missval = vlistInqVarMissval(vlistID2, varID2);
-	      for ( int i = 0; i < gridsize2; i++ ) array2[i] = missval;
+	      for ( size_t i = 0; i < gridsize2; i++ ) array2[i] = missval;
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
@@ -525,8 +525,8 @@ void *Collgrid(void *argument)
 
 		  if ( vars[varID2] )
 		    {
-                      int gridsize = ef[fileID].gridsize;
-		      for ( int i = 0; i < gridsize; ++i )
+                      size_t gridsize = ef[fileID].gridsize;
+		      for ( size_t i = 0; i < gridsize; ++i )
 			array2[ef[fileID].gridindex[i]] = ef[fileID].array[i];
 		    }
 		}
@@ -535,8 +535,8 @@ void *Collgrid(void *argument)
 
 	      if ( vars[varID2] )
 		{
-		  int nmiss = 0;
-		  for ( int i = 0; i < gridsize2; i++ )
+		  size_t nmiss = 0;
+		  for ( size_t i = 0; i < gridsize2; i++ )
 		    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
 		  pstreamWriteRecord(streamID2, array2, nmiss);
diff --git a/src/Command.cc b/src/Command.cc
index 296485d..edde5a9 100644
--- a/src/Command.cc
+++ b/src/Command.cc
@@ -167,7 +167,7 @@ int com_stat(const char *arg)
       else
 	{
 	  int i;
-	  int nmiss;
+	  size_t nmiss;
 	  int gridsize;
 	  double fmin = 1.e50 , fmax = -1.e50, fmean = 0;
 	  counter_t counter;
@@ -321,7 +321,7 @@ void command_init()
 void *Command(void *argument)
 {
   // int recID, varID, levelID;
-  // int nmiss;
+  // size_t nmiss;
   double s_utime, s_stime;
   double e_utime, e_stime;
   double c_cputime = 0, c_usertime = 0, c_systime = 0;
diff --git a/src/Comp.cc b/src/Comp.cc
index b553b1e..92f5e28 100644
--- a/src/Comp.cc
+++ b/src/Comp.cc
@@ -103,11 +103,11 @@ void *Comp(void *argument)
   nospec(vlistID1);
   nospec(vlistID2);
 
-  int gridsize = vlistGridsizeMax(vlistIDx1);
+  size_t gridsizemax = vlistGridsizeMax(vlistIDx1);
 
-  double *array1 = (double*) Malloc(gridsize*sizeof(double));
-  double *array2 = (double*) Malloc(gridsize*sizeof(double));
-  double *array3 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsizemax*sizeof(double));
+  double *array2 = (double*) Malloc(gridsizemax*sizeof(double));
+  double *array3 = (double*) Malloc(gridsizemax*sizeof(double));
 
   double *arrayx1 = array1;
   double *arrayx2 = array2;
@@ -140,7 +140,7 @@ void *Comp(void *argument)
 	  vardata = (double **) Malloc(nvars*sizeof(double *));
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
+	      size_t gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
 	      nlev     = zaxisInqSize(vlistInqVarZaxis(vlistIDx2, varID));
 	      vardata[varID] = (double*) Malloc(nlev*gridsize*sizeof(double));
 	    }
@@ -179,7 +179,7 @@ void *Comp(void *argument)
 
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
-          int nmiss1;
+          size_t nmiss1;
 	  pstreamInqRecord(streamIDx1, &varID, &levelID);
 	  pstreamReadRecord(streamIDx1, arrayx1, &nmiss1);
 
@@ -187,77 +187,95 @@ void *Comp(void *argument)
 	    {
 	      if ( recID == 0 || filltype != FILL_REC )
 		{
-                  int nmiss2;
+                  size_t nmiss2;
 		  pstreamInqRecord(streamIDx2, &varID, &levelID);
 		  pstreamReadRecord(streamIDx2, arrayx2, &nmiss2);
 		}
 
 	      if ( filltype == FILL_TS )
 		{
-		  int gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
-		  int offset = gridsize*levelID;
+		  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
+		  size_t offset = gridsize*levelID;
 		  memcpy(vardata[varID]+offset, arrayx2, gridsize*sizeof(double));
 		}
 	    }
 	  else if ( filltype == FILL_TS )
 	    {
-	      int gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
-	      int offset = gridsize*levelID;
+	      size_t gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
+	      size_t offset = gridsize*levelID;
 	      memcpy(arrayx2, vardata[varID]+offset, gridsize*sizeof(double));
 	    }
 
+          int datatype1 = vlistInqVarDatatype(vlistIDx1, varID);
+          int datatype2 = CDI_UNDEFID;
 	  gridsize1 = gridInqSize(vlistInqVarGrid(vlistIDx1, varID));
 	  *missvalx1 = vlistInqVarMissval(vlistIDx1, varID);
 
 	  if ( filltype == FILL_REC )
 	    {
-	      gridsize2 = gridInqSize(vlistInqVarGrid(vlistIDx2, 0));
+              datatype2 = vlistInqVarDatatype(vlistIDx2, 0);
+              gridsize2 = gridInqSize(vlistInqVarGrid(vlistIDx2, 0));
 	      *missvalx2 = vlistInqVarMissval(vlistIDx2, 0);
 	    }
 	  else
 	    {
+              datatype2 = vlistInqVarDatatype(vlistIDx2, varID);
 	      gridsize2 = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
 	      *missvalx2 = vlistInqVarMissval(vlistIDx2, varID);
 	    }
 
-	  if ( gridsize1 != gridsize2 ) cdoAbort("Streams have different gridsize (gridsize1 = %d; gridsize2 = %d!",
+	  if ( gridsize1 != gridsize2 ) cdoAbort("Streams have different gridsize (gridsize1 = %zu; gridsize2 = %zu!",
 						 gridsize1, gridsize2);
 
-	  gridsize = gridsize1;
+	  size_t gridsize = gridsize1;
+
+          if ( datatype1 != datatype2 )
+            {
+              if ( datatype1 == CDI_DATATYPE_FLT32 && datatype2 == CDI_DATATYPE_FLT64 )
+                {
+                  missval2 = (float) missval2;
+                  for ( size_t i = 0; i < gridsize; i++ ) array2[i] = (float) array2[i];
+                }
+              else if ( datatype1 == CDI_DATATYPE_FLT64 && datatype2 == CDI_DATATYPE_FLT32 )
+                {
+                  missval1 = (float) missval1;
+                  for ( size_t i = 0; i < gridsize; i++ ) array1[i] = (float) array1[i];
+                }
+            }
 
 	  if ( operatorID == EQ )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
-			     missval1 : DBL_IS_EQUAL(array1[i], array2[i]));
+			     missval1 : IS_EQUAL(array1[i], array2[i]));
 	    }
 	  else if ( operatorID == NE )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
-			     missval1 : !DBL_IS_EQUAL(array1[i], array2[i]));
+			     missval1 : IS_NOT_EQUAL(array1[i], array2[i]));
 	    }
 	  else if ( operatorID == LE )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
 			     missval1 : array1[i] <= array2[i]);
 	    }
 	  else if ( operatorID == LT )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
 			     missval1 : array1[i] < array2[i]);
 	    }
 	  else if ( operatorID == GE )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
 			     missval1 : array1[i] >= array2[i]);
 	    }
 	  else if ( operatorID == GT )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
 			     missval1 : array1[i] > array2[i]);
 	    }
@@ -266,8 +284,8 @@ void *Comp(void *argument)
 	      cdoAbort("Operator not implemented!");
 	    }
 
-	  int nmiss3 = 0;
-	  for ( int i = 0; i < gridsize; i++ )
+	  size_t nmiss3 = 0;
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(array3[i], missval1) ) nmiss3++;
 
 	  pstreamDefRecord(streamID3, varID, levelID);
diff --git a/src/Compc.cc b/src/Compc.cc
index f815bf0..30d9e14 100644
--- a/src/Compc.cc
+++ b/src/Compc.cc
@@ -37,10 +37,7 @@ void *Compc(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss, nmiss2;
-  int i;
-  double missval;
-  int rc_is_missval;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
@@ -67,10 +64,10 @@ void *Compc(void *argument)
 
   nospec(vlistID1);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
+  size_t gridsizemax = vlistGridsizeMax(vlistID1);
 
-  double *array1 = (double*) Malloc(gridsize*sizeof(double));
-  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsizemax*sizeof(double));
+  double *array2 = (double*) Malloc(gridsizemax*sizeof(double));
 
   int streamID2 = pstreamOpenWrite(cdoStreamName(1), cdoFiletype());
   pstreamDefVlist(streamID2, vlistID2);
@@ -87,48 +84,51 @@ void *Compc(void *argument)
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, array1, &nmiss);
 
-	  missval  = vlistInqVarMissval(vlistID1, varID);
-	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
+	  double missval  = vlistInqVarMissval(vlistID1, varID);
+	  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 
-	  rc_is_missval = DBL_IS_EQUAL(rc, missval);
+	  bool rc_is_missval = DBL_IS_EQUAL(rc, missval);
+
+          int datatype = vlistInqVarDatatype(vlistID1, varID);
+          double rcv = (datatype == CDI_DATATYPE_FLT32) ? (float)rc : rc;
 
 	  if ( operatorID == EQC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : DBL_IS_EQUAL(array1[i], rc);
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : IS_EQUAL(array1[i], rcv);
 	    }
 	  else if ( operatorID == NEC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : !DBL_IS_EQUAL(array1[i], rc);
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : IS_NOT_EQUAL(array1[i], rcv);
 	    }
 	  else if ( operatorID == LEC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] <= rc;
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] <= rcv;
 	    }
 	  else if ( operatorID == LTC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] < rc;
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] < rcv;
 	    }
 	  else if ( operatorID == GEC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] >= rc;
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] >= rcv;
 	    }
 	  else if ( operatorID == GTC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
-		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] > rc;
+	      for ( size_t i = 0; i < gridsize; i++ )
+		array2[i] = DBL_IS_EQUAL(array1[i], missval) || rc_is_missval ? missval : array1[i] > rcv;
 	    }
 	  else
 	    {
 	      cdoAbort("Operator not implemented!");
 	    }
 
-	  nmiss2 = 0;
-	  for ( i = 0; i < gridsize; i++ )
+          size_t nmiss2 = 0;
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss2++;
 
 	  pstreamDefRecord(streamID2, varID, levelID);
diff --git a/src/Complextorect.cc b/src/Complextorect.cc
index 1e7bf2f..8027d98 100644
--- a/src/Complextorect.cc
+++ b/src/Complextorect.cc
@@ -28,7 +28,7 @@ void *Complextorect(void *argument)
   int varID, levelID;
   int i;
   int datatype;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Cond.cc b/src/Cond.cc
index 809da5f..2e20e9e 100644
--- a/src/Cond.cc
+++ b/src/Cond.cc
@@ -34,12 +34,11 @@ void *Cond(void *argument)
   int filltype = FILL_NONE;
   int nrecs, nrecs2, nvars = 0, nlev;
   int varID, levelID;
-  int offset;
-  int nmiss1, nmiss2, nmiss3;
-  int i;
+  size_t offset;
+  size_t nmiss1, nmiss2, nmiss3;
   double missval1 = -9.E33;
   double missval2 = -9.E33;
-  int **varnmiss1 = NULL;
+  size_t **varnmiss1 = NULL;
   double **vardata1 = NULL;
 
   cdoInitialize(argument);
@@ -82,7 +81,7 @@ void *Cond(void *argument)
   int streamID3 = pstreamOpenWrite(cdoStreamName(2), cdoFiletype());
   pstreamDefVlist(streamID3, vlistID3);
 
-  int gridsize = vlistGridsizeMax(vlistID2);
+  size_t gridsize = vlistGridsizeMax(vlistID2);
 
   if ( filltype == FILL_REC && gridsize != gridInqSize(vlistGrid(vlistID1, 0)) )
     cdoAbort("Stream1 >%s< has wrong gridsize!", cdoStreamName(0)->args);
@@ -103,13 +102,13 @@ void *Cond(void *argument)
 
 	  nvars  = vlistNvars(vlistID1);
 	  vardata1  = (double **) Malloc(nvars*sizeof(double *));
-	  varnmiss1 = (int **) Malloc(nvars*sizeof(int *));
+	  varnmiss1 = (size_t **) Malloc(nvars*sizeof(size_t *));
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 	      nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      vardata1[varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	      varnmiss1[varID] = (int*) Malloc(nlev*sizeof(int));
+	      varnmiss1[varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	    }
 	}
     }
@@ -166,12 +165,12 @@ void *Cond(void *argument)
 
 	  if ( operatorID == IFTHEN )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = !DBL_IS_EQUAL(array1[i], missval1) && !DBL_IS_EQUAL(array1[i], 0.) ? array2[i] : missval2;
 	    }
 	  else if ( operatorID == IFNOTTHEN )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array3[i] = !DBL_IS_EQUAL(array1[i], missval1) && DBL_IS_EQUAL(array1[i], 0.) ? array2[i] : missval2;
 	    }
 	  else
@@ -180,7 +179,7 @@ void *Cond(void *argument)
 	    }
 
 	  nmiss3 = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(array3[i], missval2) ) nmiss3++;
 
 	  pstreamDefRecord(streamID3, varID, levelID);
diff --git a/src/Cond2.cc b/src/Cond2.cc
index 6b4b33d..89e2047 100644
--- a/src/Cond2.cc
+++ b/src/Cond2.cc
@@ -33,12 +33,11 @@ void *Cond2(void *argument)
   int filltype = FILL_NONE;
   int nrecs, nrecs2, nvars = 0, nlev;
   int varID, levelID;
-  int offset;
-  int nmiss1, nmiss2, nmiss3, nmiss4;
-  int i;
+  size_t offset;
+  size_t nmiss1, nmiss2, nmiss3, nmiss4;
   double missval1 = -9.E33;
   double missval2 = -9.E33;
-  int **varnmiss1 = NULL;
+  size_t **varnmiss1 = NULL;
   double **vardata1 = NULL;
 
   cdoInitialize(argument);
@@ -83,7 +82,7 @@ void *Cond2(void *argument)
   int streamID4 = pstreamOpenWrite(cdoStreamName(3), cdoFiletype());
   pstreamDefVlist(streamID4, vlistID4);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
+  size_t gridsize = vlistGridsizeMax(vlistID1);
 
   if ( filltype == FILL_REC && gridsize != gridInqSize(vlistGrid(vlistID1, 0)) )
     cdoAbort("Stream1 >%s< has wrong gridsize!", cdoStreamName(0)->args);
@@ -106,13 +105,13 @@ void *Cond2(void *argument)
 
 	  nvars  = vlistNvars(vlistID1);
 	  vardata1  = (double **) Malloc(nvars*sizeof(double *));
-	  varnmiss1 = (int **) Malloc(nvars*sizeof(int *));
+	  varnmiss1 = (size_t **) Malloc(nvars*sizeof(size_t *));
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 	      nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      vardata1[varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	      varnmiss1[varID] = (int*) Malloc(nlev*sizeof(int));
+	      varnmiss1[varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	    }
 	}
     }
@@ -176,7 +175,7 @@ void *Cond2(void *argument)
 
 	  if ( operatorID == IFTHENELSE )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array4[i] = DBL_IS_EQUAL(array1[i], missval1) ?
 		  missval2 : !DBL_IS_EQUAL(array1[i], 0.) ? array2[i] : array3[i];
 	    }
@@ -186,7 +185,7 @@ void *Cond2(void *argument)
 	    }
 
 	  nmiss4 = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(array4[i], missval2) ) nmiss4++;
 
 	  pstreamDefRecord(streamID4, varID, levelID);
diff --git a/src/Condc.cc b/src/Condc.cc
index fdca47e..030c796 100644
--- a/src/Condc.cc
+++ b/src/Condc.cc
@@ -33,7 +33,7 @@ void *Condc(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss, nmiss2;
+  size_t nmiss, nmiss2;
   int i;
   double missval;
 
diff --git a/src/Consecstat.cc b/src/Consecstat.cc
index 63a4dea..3c4cd9d 100644
--- a/src/Consecstat.cc
+++ b/src/Consecstat.cc
@@ -127,7 +127,7 @@ void *Consecstat(void *argument)
   int nrecs;
   int varID;
   int levelID, nlevels;
-  int nmiss;
+  size_t nmiss;
   double refval = 0.0;
 
   cdoInitialize(argument);
@@ -197,7 +197,7 @@ void *Consecstat(void *argument)
     {
       pstreamInqRecord(istreamID, &varID, &levelID);
       pstreamReadRecord(istreamID, field.ptr, &nmiss);
-      field.nmiss   = (size_t)nmiss;
+      field.nmiss   = nmiss;
       field.grid    = vlistInqVarGrid(ovlistID, varID);
       field.missval = vlistInqVarMissval(ovlistID, varID);
 
@@ -207,14 +207,14 @@ void *Consecstat(void *argument)
       {
         case CONSECSUM:
           pstreamDefRecord(ostreamID, varID, levelID);
-          pstreamWriteRecord(ostreamID, vars[varID][levelID].ptr, (int)vars[varID][levelID].nmiss);
+          pstreamWriteRecord(ostreamID, vars[varID][levelID].ptr, vars[varID][levelID].nmiss);
           break;
         case CONSECTS:
           if ( itsID != 0 )
           {
             selEndOfPeriod(&periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], FALSE);
             pstreamDefRecord(ostreamID, varID, levelID);
-            pstreamWriteRecord(ostreamID, periods[varID][levelID].ptr, (int)periods[varID][levelID].nmiss);
+            pstreamWriteRecord(ostreamID, periods[varID][levelID].ptr, periods[varID][levelID].nmiss);
           }
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared) schedule(static)
@@ -249,7 +249,7 @@ void *Consecstat(void *argument)
       {
         selEndOfPeriod(&periods[varID][levelID], hist[varID][levelID], vars[varID][levelID], TRUE);
         pstreamDefRecord(ostreamID, varID, levelID);
-        pstreamWriteRecord(ostreamID, periods[varID][levelID].ptr, (int)periods[varID][levelID].nmiss);
+        pstreamWriteRecord(ostreamID, periods[varID][levelID].ptr, periods[varID][levelID].nmiss);
       }
     }
   }
diff --git a/src/Copy.cc b/src/Copy.cc
index a872280..12ea8ac 100644
--- a/src/Copy.cc
+++ b/src/Copy.cc
@@ -44,7 +44,7 @@ void *Copy(void *argument)
   int taxisID2 = CDI_UNDEFID;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int ntsteps, nvars;
   double *array = NULL;
   par_io_t parIO;
@@ -116,7 +116,7 @@ void *Copy(void *argument)
 
 	  pstreamDefVlist(streamID2, vlistID2);
 
-	  int gridsize = vlistGridsizeMax(vlistID1);
+	  size_t gridsize = vlistGridsizeMax(vlistID1);
 	  array = (double*) Malloc(gridsize*sizeof(double));
 	  if ( cdoParIO )
 	    {
diff --git a/src/Deltat.cc b/src/Deltat.cc
index 4c5ac1d..cda3352 100644
--- a/src/Deltat.cc
+++ b/src/Deltat.cc
@@ -31,7 +31,7 @@
 void *Deltat(void *argument)
 {
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Deltime.cc b/src/Deltime.cc
index 6a884d1..4a189ec 100644
--- a/src/Deltime.cc
+++ b/src/Deltime.cc
@@ -29,7 +29,7 @@ void *Deltime(void *argument)
   int vdate /*, vtime */;
   int copytimestep;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   int year, month, day;
   int dday, dmon;
   double *array = NULL;
diff --git a/src/Derivepar.cc b/src/Derivepar.cc
index aed1215..eb87393 100644
--- a/src/Derivepar.cc
+++ b/src/Derivepar.cc
@@ -50,7 +50,7 @@ void *Derivepar(void *argument)
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
   double *single2;
   // double *lwater = NULL, *iwater = NULL;
-  int nmiss, nmissout = 0;
+  size_t nmiss, nmissout = 0;
   double *full_press = NULL;
   double minval, maxval;
   int instNum, tableNum;
diff --git a/src/Detrend.cc b/src/Detrend.cc
index 27eaec9..26c6177 100644
--- a/src/Detrend.cc
+++ b/src/Detrend.cc
@@ -69,7 +69,7 @@ void *Detrend(void *argument)
   int gridID, varID, levelID;
   int i;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   double missval;
   field_type ***vars = NULL;
diff --git a/src/Diff.cc b/src/Diff.cc
index ecf0341..b0a86bd 100644
--- a/src/Diff.cc
+++ b/src/Diff.cc
@@ -34,7 +34,7 @@ void *Diff(void *argument)
   int nrecs, nrecs2;
   int varID1, varID2;
   int levelID;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   int ndrec = 0, nd2rec = 0, ngrec = 0;
   char varname[CDI_MAX_NAME];
   char paramstr[32];
@@ -65,7 +65,7 @@ void *Diff(void *argument)
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
+  size_t gridsize = vlistGridsizeMax(vlistID1);
 
   double *array1 = (double*) Malloc(gridsize*sizeof(double));
   double *array2 = (double*) Malloc(gridsize*sizeof(double));
@@ -97,7 +97,7 @@ void *Diff(void *argument)
 	  int code     = vlistInqVarCode(vlistID1, varID1);
 	  int gridID   = vlistInqVarGrid(vlistID1, varID1);
 	  int zaxisID  = vlistInqVarZaxis(vlistID1, varID1);
-	  int gridsize = gridInqSize(gridID);
+	  size_t gridsize = gridInqSize(gridID);
 	  double missval1 = vlistInqVarMissval(vlistID1, varID1);
 	  double missval2 = vlistInqVarMissval(vlistID2, varID2);
 
@@ -116,7 +116,7 @@ void *Diff(void *argument)
 	  double relm = 0.0;
           double absdiff;
 
-	  for ( int i = 0; i < gridsize; i++ )
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    {
 	      if ( (DBL_IS_NAN(array1[i]) && !DBL_IS_NAN(array2[i])) ||
 		  (!DBL_IS_NAN(array1[i]) &&  DBL_IS_NAN(array2[i])) )
@@ -185,7 +185,7 @@ void *Diff(void *argument)
 		  set_text_color(stdout, RESET, GREEN);
                   double level = cdoZaxisInqLevel(zaxisID, levelID);
 		  fprintf(stdout, "%7g ", level);
-		  fprintf(stdout, "%8d %7d ", gridsize, MAX(nmiss1, nmiss2));
+		  fprintf(stdout, "%8zu %7zu ", gridsize, MAX(nmiss1, nmiss2));
 		  fprintf(stdout, "%7d ", ndiff);
 		  reset_text_color(stdout);
 		
diff --git a/src/Distgrid.cc b/src/Distgrid.cc
index c96882d..2d2db36 100644
--- a/src/Distgrid.cc
+++ b/src/Distgrid.cc
@@ -24,8 +24,8 @@
 #define  MAX_BLOCKS  65536
 
 static
-void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, int nyblocks,
-	      int **gridindex, int *ogridsize, int nsplit)
+void genGrids(int gridID1, int *gridIDs, size_t nxvals, size_t nyvals, size_t nxblocks, size_t nyblocks,
+	      size_t **gridindex, size_t *ogridsize, size_t nsplit)
 {
   double *xpvals = NULL, *ypvals = NULL;
   int gridtype = gridInqType(gridID1);
@@ -37,8 +37,8 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
   else
     cdoAbort("Unsupported grid type: %s!", gridNamePtr(gridtype));
 
-  int nx = gridInqXsize(gridID1);
-  int ny = gridInqYsize(gridID1);
+  size_t nx = gridInqXsize(gridID1);
+  size_t ny = gridInqYsize(gridID1);
 
   bool lxcoord = gridInqXvals(gridID1, NULL) > 0;
   bool lycoord = gridInqYvals(gridID1, NULL) > 0;
@@ -76,30 +76,30 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
       gridInqYvals(gridID1, yvals);
     }
  
-  int *xlsize = (int*) Malloc(nxblocks*sizeof(int));
-  int *ylsize = (int*) Malloc(nyblocks*sizeof(int));
+  size_t *xlsize = (size_t*) Malloc(nxblocks*sizeof(size_t));
+  size_t *ylsize = (size_t*) Malloc(nyblocks*sizeof(size_t));
 
-  for ( int ix = 0; ix < nxblocks; ++ix ) xlsize[ix] = nxvals;
+  for ( size_t ix = 0; ix < nxblocks; ++ix ) xlsize[ix] = nxvals;
   if ( nx%nxblocks != 0 ) xlsize[nxblocks-1] = nx - (nxblocks-1)*nxvals;
-  if ( cdoVerbose ) for ( int ix = 0; ix < nxblocks; ++ix ) cdoPrint("xblock %d: %d", ix, xlsize[ix]);
+  if ( cdoVerbose ) for ( size_t ix = 0; ix < nxblocks; ++ix ) cdoPrint("xblock %zu: %zu", ix, xlsize[ix]);
 
-  for ( int iy = 0; iy < nyblocks; ++iy ) ylsize[iy] = nyvals;
+  for ( size_t iy = 0; iy < nyblocks; ++iy ) ylsize[iy] = nyvals;
   if ( ny%nyblocks != 0 ) ylsize[nyblocks-1] = ny - (nyblocks-1)*nyvals;
-  if ( cdoVerbose ) for ( int iy = 0; iy < nyblocks; ++iy ) cdoPrint("yblock %d: %d", iy, ylsize[iy]);
+  if ( cdoVerbose ) for ( size_t iy = 0; iy < nyblocks; ++iy ) cdoPrint("yblock %zu: %zu", iy, ylsize[iy]);
 
-  int index = 0;
-  for ( int iy = 0; iy < nyblocks; ++iy )
-    for ( int ix = 0; ix < nxblocks; ++ix )
+  size_t index = 0;
+  for ( size_t iy = 0; iy < nyblocks; ++iy )
+    for ( size_t ix = 0; ix < nxblocks; ++ix )
       {
-	int offset = iy*nyvals*nx + ix*nxvals;
+	size_t offset = iy*nyvals*nx + ix*nxvals;
 
-	int gridsize2 = xlsize[ix]*ylsize[iy];
-	gridindex[index] = (int*) Malloc(gridsize2*sizeof(int));
+	size_t gridsize2 = xlsize[ix]*ylsize[iy];
+	gridindex[index] = (size_t*) Malloc(gridsize2*sizeof(size_t));
 
 	gridsize2 = 0;
         // printf("iy %d, ix %d offset %d\n", iy, ix,  offset);
-	for ( int j = 0; j < ylsize[iy]; ++j )
-          for ( int i = 0; i < xlsize[ix]; ++i )
+	for ( size_t j = 0; j < ylsize[iy]; ++j )
+          for ( size_t i = 0; i < xlsize[ix]; ++i )
             {
               // printf(">> %d %d %d\n", j, i, offset + j*nx + i);
               if ( !lregular )
@@ -186,9 +186,9 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
 }
 
 static
-void window_cell(double *array1, double *array2, long gridsize2, int *cellidx)
+void window_cell(double *array1, double *array2, size_t gridsize2, size_t *cellidx)
 {
-  for ( long i = 0; i < gridsize2; ++i )
+  for ( size_t i = 0; i < gridsize2; ++i )
     array2[i] = array1[cellidx[i]];
 }
 
@@ -196,8 +196,8 @@ typedef struct
 {
   int gridID;
   int *gridIDs;
-  int *gridsize;
-  int **gridindex;
+  size_t *gridsize;
+  size_t **gridindex;
 } sgrid_t;
 
 
@@ -210,7 +210,7 @@ void *Distgrid(void *argument)
   char filename[8192];
   int index;
   int gridtype = -1;
-  int nmiss;
+  size_t nmiss;
   int i;
 
   cdoInitialize(argument);
@@ -218,12 +218,12 @@ void *Distgrid(void *argument)
   operatorInputArg("nxblocks, [nyblocks]");
   if ( operatorArgc() < 1 ) cdoAbort("Too few arguments!");
   if ( operatorArgc() > 2 ) cdoAbort("Too many arguments!");
-  int nxblocks = parameter2int(operatorArgv()[0]);
-  int nyblocks = 1;
+  size_t nxblocks = parameter2int(operatorArgv()[0]);
+  size_t nyblocks = 1;
   if ( operatorArgc() == 2 ) nyblocks = parameter2int(operatorArgv()[1]);
 
-  if ( nxblocks <= 0 ) cdoAbort("nxblocks has to be greater than 0!");
-  if ( nyblocks <= 0 ) cdoAbort("nyblocks has to be greater than 0!");
+  if ( nxblocks == 0 ) cdoAbort("nxblocks has to be greater than 0!");
+  if ( nyblocks == 0 ) cdoAbort("nyblocks has to be greater than 0!");
 
   int streamID1 = pstreamOpenRead(cdoStreamName(0));
 
@@ -244,9 +244,9 @@ void *Distgrid(void *argument)
     cdoAbort("No Lon/Lat, Gaussian, curvilinear or generic grid found (%s data unsupported)!", gridNamePtr(gridtype));
 
   gridID1 = vlistGrid(vlistID1, 0);
-  int gridsize = gridInqSize(gridID1);
-  int nx = gridInqXsize(gridID1);
-  int ny = gridInqYsize(gridID1);
+  size_t gridsize = gridInqSize(gridID1);
+  size_t nx = gridInqXsize(gridID1);
+  size_t ny = gridInqYsize(gridID1);
   for ( int i = 1; i < ngrids; i++ )
     {
       gridID1 = vlistGrid(vlistID1, i);
@@ -256,22 +256,22 @@ void *Distgrid(void *argument)
 
   if ( nxblocks > nx )
     {
-      cdoPrint("nxblocks (%d) greater than nx (%d), set to %d!", nxblocks, nx, nx);
+      cdoPrint("nxblocks (%zu) greater than nx (%zu), set to %zu!", nxblocks, nx, nx);
       nxblocks = nx;
     }
   if ( nyblocks > ny )
     {
-      cdoPrint("nyblocks (%d) greater than ny (%d), set to %d!", nyblocks, ny, ny);
+      cdoPrint("nyblocks (%zu) greater than ny (%zu), set to %zu!", nyblocks, ny, ny);
       nyblocks = ny;
     }
 
-  int xinc = nx/nxblocks;
-  int yinc = ny/nyblocks;
+  size_t xinc = nx/nxblocks;
+  size_t yinc = ny/nyblocks;
 
   if ( nx%xinc && nx%(xinc+1) ) xinc++;
   if ( ny%yinc && ny%(yinc+1) ) yinc++;
 
-  int nsplit = nxblocks*nyblocks;
+  size_t nsplit = nxblocks*nyblocks;
   if ( nsplit > MAX_BLOCKS ) cdoAbort("Too many blocks (max = %d)!", MAX_BLOCKS);
 
   double *array1 = (double*) Malloc(gridsize*sizeof(double));
@@ -284,13 +284,13 @@ void *Distgrid(void *argument)
     {  
       grids[i].gridID    = vlistGrid(vlistID1, i);
       grids[i].gridIDs   = (int*) Malloc(nsplit*sizeof(int));
-      grids[i].gridsize  = (int*) Malloc(nsplit*sizeof(int));
-      grids[i].gridindex = (int**) Malloc(nsplit*sizeof(int*));
+      grids[i].gridsize  = (size_t*) Malloc(nsplit*sizeof(size_t));
+      grids[i].gridindex = (size_t**) Malloc(nsplit*sizeof(size_t*));
 
-      for ( int index = 0; index < nsplit; index++ ) grids[i].gridindex[index] = NULL;
+      for ( size_t index = 0; index < nsplit; index++ ) grids[i].gridindex[index] = NULL;
     }
 
-  for ( int index = 0; index < nsplit; index++ )
+  for ( size_t index = 0; index < nsplit; index++ )
     vlistIDs[index] = vlistDuplicate(vlistID1);
 
   if ( cdoVerbose ) cdoPrint("ngrids=%d  nsplit=%d", ngrids, nsplit);
@@ -301,15 +301,15 @@ void *Distgrid(void *argument)
       genGrids(gridID1, grids[i].gridIDs, xinc, yinc, nxblocks, nyblocks, grids[i].gridindex, grids[i].gridsize, nsplit);
       /*
       if ( cdoVerbose )
-	for ( int index = 0; index < nsplit; index++ )
-	  cdoPrint("Block %d,  gridID %d,  gridsize %d", index+1, grids[i].gridIDs[index], gridInqSize(grids[i].gridIDs[index]));
+	for ( size_t index = 0; index < nsplit; index++ )
+	  cdoPrint("Block %d,  gridID %d,  gridsize %zu", index+1, grids[i].gridIDs[index], gridInqSize(grids[i].gridIDs[index]));
       */
-      for ( int index = 0; index < nsplit; index++ )
+      for ( size_t index = 0; index < nsplit; index++ )
 	vlistChangeGridIndex(vlistIDs[index], i, grids[i].gridIDs[index]);
     }
 
-  int gridsize2max = 0;
-  for ( int index = 0; index < nsplit; index++ )
+  size_t gridsize2max = 0;
+  for ( size_t index = 0; index < nsplit; index++ )
     if ( grids[0].gridsize[index] > gridsize2max ) gridsize2max = grids[0].gridsize[index];
 
   double *array2 = (double*) Malloc(gridsize2max*sizeof(double));
@@ -321,9 +321,9 @@ void *Distgrid(void *argument)
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), pstreamInqFiletype(streamID1), vlistID1, refname);
 
-  for ( int index = 0; index < nsplit; index++ )
+  for ( size_t index = 0; index < nsplit; index++ )
     {
-      sprintf(filename+nchars, "%05d", index);
+      sprintf(filename+nchars, "%05ld", (long)index);
       if ( filesuffix[0] )
 	sprintf(filename+nchars+5, "%s", filesuffix);
 
@@ -338,7 +338,7 @@ void *Distgrid(void *argument)
   int tsID = 0;
   while ( (nrecs = pstreamInqTimestep(streamID1, tsID)) )
     {
-      for ( int index = 0; index < nsplit; index++ )
+      for ( size_t index = 0; index < nsplit; index++ )
 	pstreamDefTimestep(streamIDs[index], tsID);
 
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -348,7 +348,7 @@ void *Distgrid(void *argument)
 
 	  double missval = vlistInqVarMissval(vlistID1, varID);
 
-	  for ( int index = 0; index < nsplit; index++ )
+	  for ( size_t index = 0; index < nsplit; index++ )
 	    {
 	      i = 0;
 	      window_cell(array1, array2, grids[i].gridsize[index], grids[i].gridindex[index]);
@@ -356,7 +356,7 @@ void *Distgrid(void *argument)
 	      if ( nmiss > 0 )
 		{
 		  nmiss = 0;
-		  for ( int k = 0; k < grids[i].gridsize[index]; ++k )
+		  for ( size_t k = 0; k < grids[i].gridsize[index]; ++k )
 		    if ( DBL_IS_EQUAL(array2[k], missval) ) nmiss++;
 		}
 	      pstreamWriteRecord(streamIDs[index], array2, nmiss);
@@ -368,7 +368,7 @@ void *Distgrid(void *argument)
 
   pstreamClose(streamID1);
 
-  for ( int index = 0; index < nsplit; index++ )
+  for ( size_t index = 0; index < nsplit; index++ )
     {
       pstreamClose(streamIDs[index]);
       vlistDestroy(vlistIDs[index]);
@@ -382,12 +382,12 @@ void *Distgrid(void *argument)
 
   for ( int i = 0; i < ngrids; i++ )
     {
-      for ( int index = 0; index < nsplit; index++ )
+      for ( size_t index = 0; index < nsplit; index++ )
 	gridDestroy(grids[i].gridIDs[index]);
       Free(grids[i].gridIDs);
       Free(grids[i].gridsize);
 
-      for ( int index = 0; index < nsplit; index++ )
+      for ( size_t index = 0; index < nsplit; index++ )
         Free(grids[i].gridindex[index]);
       Free(grids[i].gridindex);
     }
diff --git a/src/Duplicate.cc b/src/Duplicate.cc
index d9e10af..183697e 100644
--- a/src/Duplicate.cc
+++ b/src/Duplicate.cc
@@ -29,7 +29,7 @@ void *Duplicate(void *argument)
   int nrecs;
   int varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int *vdate = NULL, *vtime = NULL;
   int ndup = 2;
   field_type ***vars = NULL;
diff --git a/src/EOFs.cc b/src/EOFs.cc
index 3acf83b..7883990 100644
--- a/src/EOFs.cc
+++ b/src/EOFs.cc
@@ -32,7 +32,6 @@
 #include <omp.h>
 #endif
 
-#include <limits.h>  // LONG_MAX
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
@@ -168,7 +167,7 @@ void *EOFs(void * argument)
   enum {EOF_, EOF_TIME, EOF_SPATIAL};
 
   int nlevs = 0 ;
-  int nmiss;
+  size_t nmiss;
   int varID, levelID;
   int nts = 0;
   size_t n = 0;
@@ -279,7 +278,7 @@ void *EOFs(void * argument)
     }
   else if ( grid_space )
     {
-      if ( ((double)gridsize)*gridsize > (double)LONG_MAX ) cdoAbort("Grid space too large!");
+      if ( ((double)gridsize)*gridsize > (double)SIZE_MAX ) cdoAbort("Grid space too large!");
 
       if ( (size_t)n_eig > gridsize )
         {
@@ -310,7 +309,7 @@ void *EOFs(void * argument)
     }
 
   /* allocation of temporary fields and output structures */
-  size_t npack = ULONG_MAX;
+  size_t npack = SIZE_MAX;
   size_t *pack         = (size_t *) Malloc(gridsize*sizeof(size_t));
   double *in           = (double *) Malloc(gridsize*sizeof(double));
   eofdata_t **eofdata  = (eofdata_t **) Malloc(nvars*sizeof(eofdata_t*));
@@ -357,7 +356,7 @@ void *EOFs(void * argument)
 
 	  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
           double missval = vlistInqVarMissval(vlistID1, varID);
-	  if ( npack == ULONG_MAX )
+	  if ( npack == SIZE_MAX )
 	    {
 	      npack = 0;
 	      for ( size_t i = 0; i < gridsize; ++i )
diff --git a/src/Echam5ini.cc b/src/Echam5ini.cc
index b768c83..6d39033 100644
--- a/src/Echam5ini.cc
+++ b/src/Echam5ini.cc
@@ -1433,7 +1433,8 @@ void *Echam5ini(void *argument)
   int vlistID1, vlistID2;
   int nvars = 0;
   int iv, nlev;
-  int gridsize, nmiss;
+  int gridsize;
+  size_t nmiss;
   int taxisID, tsID;
 
   cdoInitialize(argument);
diff --git a/src/Enlarge.cc b/src/Enlarge.cc
index 478e73f..3e41c15 100644
--- a/src/Enlarge.cc
+++ b/src/Enlarge.cc
@@ -40,10 +40,10 @@ void *Enlarge(void *argument)
   int streamID1 = pstreamOpenRead(cdoStreamName(0));
 
   int gridID2 = cdoDefineGrid(operatorArgv()[0]);
-  int xsize2 = gridInqXsize(gridID2);
-  int ysize2 = gridInqYsize(gridID2);
+  size_t xsize2 = gridInqXsize(gridID2);
+  size_t ysize2 = gridInqYsize(gridID2);
 
-  if ( cdoVerbose ) fprintf(stderr, "gridID2 %d, xsize2 %d, ysize2 %d\n", gridID2, xsize2, ysize2);
+  if ( cdoVerbose ) fprintf(stderr, "gridID2 %d, xsize2 %zu, ysize2 %zu\n", gridID2, xsize2, ysize2);
 
 
   int vlistID1 = pstreamInqVlist(streamID1);
@@ -53,7 +53,7 @@ void *Enlarge(void *argument)
   int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  int gridsize2 = gridInqSize(gridID2);
+  size_t gridsize2 = gridInqSize(gridID2);
   if ( gridsize2 < vlistGridsizeMax(vlistID1) )
     cdoAbort("Gridsize of input stream is greater than new gridsize!");
 
@@ -79,15 +79,16 @@ void *Enlarge(void *argument)
 
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
-          int varID, levelID, nmiss;
+          int varID, levelID;
+          size_t nmiss;
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, array1, &nmiss);
 
 	  double missval = vlistInqVarMissval(vlistID1, varID);
 	  int gridID1 = vlistInqVarGrid(vlistID1, varID);
-	  int xsize1 = gridInqXsize(gridID1);
-	  int ysize1 = gridInqYsize(gridID1);
-	  int gridsize1 = gridInqSize(gridID1);
+	  size_t xsize1 = gridInqXsize(gridID1);
+	  size_t ysize1 = gridInqYsize(gridID1);
+	  size_t gridsize1 = gridInqSize(gridID1);
 
 	  if ( xsize1 == 0 ) xsize1 = 1;
 	  if ( ysize1 == 0 ) ysize1 = 1;
@@ -101,8 +102,8 @@ void *Enlarge(void *argument)
 		  linfo = false;
 		}
 	      
-	      for ( int iy = 0; iy < ysize2; iy++ )
-		for ( int ix = 0; ix < xsize2; ix++ )
+	      for ( size_t iy = 0; iy < ysize2; iy++ )
+		for ( size_t ix = 0; ix < xsize2; ix++ )
 		  array2[ix+iy*xsize2] = array1[iy];
 
 	      if ( nmiss ) nmiss *= xsize2;
@@ -115,8 +116,8 @@ void *Enlarge(void *argument)
 		  linfo = false;
 		}
 	      
-	      for ( int iy = 0; iy < ysize2; iy++ )
-		for ( int ix = 0; ix < xsize2; ix++ )
+	      for ( size_t iy = 0; iy < ysize2; iy++ )
+		for ( size_t ix = 0; ix < xsize2; ix++ )
 		  array2[ix+iy*xsize2] = array1[ix];
 
 	      if ( nmiss ) nmiss *= ysize2;
@@ -124,10 +125,8 @@ void *Enlarge(void *argument)
 	  else
 	    {
 	      memcpy(array2, array1, gridsize1*sizeof(double));
-	      for ( int i = gridsize1; i < gridsize2; i++ )
-		{
-		  array2[i] = array1[gridsize1-1];
-		}
+	      for ( size_t i = gridsize1; i < gridsize2; i++ )
+                array2[i] = array1[gridsize1-1];
 
 	      if ( nmiss && DBL_IS_EQUAL(array1[gridsize1-1], missval) ) nmiss += (gridsize2 - gridsize1);
 	    }
diff --git a/src/Enlargegrid.cc b/src/Enlargegrid.cc
index 1b0690a..9780ba9 100644
--- a/src/Enlargegrid.cc
+++ b/src/Enlargegrid.cc
@@ -215,7 +215,8 @@ void *Enlargegrid(void *argument)
 
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
-          int varID, levelID, nmiss1;
+          int varID, levelID;
+          size_t nmiss1;
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, array1, &nmiss1);
 
@@ -226,7 +227,7 @@ void *Enlargegrid(void *argument)
 	    if ( gindex[i] >= 0 )
 	      array2[gindex[i]] = array1[i];		
 
-	  int nmiss2 = 0;
+	  size_t nmiss2 = 0;
 	  for ( int i = 0; i < gridsize2; i++ )
 	    if ( DBL_IS_EQUAL(array2[i], missval1) ) nmiss2++;
 
diff --git a/src/Ensstat.cc b/src/Ensstat.cc
index 9472f5c..7d6f95b 100644
--- a/src/Ensstat.cc
+++ b/src/Ensstat.cc
@@ -43,7 +43,7 @@ typedef struct
 {
   int streamID;
   int vlistID;
-  int nmiss[2];
+  size_t nmiss[2];
   double missval[2];
   double *array[2];
 } ens_file_t;
@@ -87,7 +87,7 @@ void *ensstat_func(void *ensarg)
   int gridsize = gridInqSize(gridID);
   double missval = vlistInqVarMissval(arg->vlistID1, arg->varID[t]);
 
-  int nmiss = 0;
+  size_t nmiss = 0;
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
 #endif
diff --git a/src/Ensstat3.cc b/src/Ensstat3.cc
index e732a73..7f1bdc3 100644
--- a/src/Ensstat3.cc
+++ b/src/Ensstat3.cc
@@ -52,7 +52,8 @@ double roc_curve_integrate(const double **roc, const int n);
 void *Ensstat3(void *argument)
 {
   int i,j;
-  int nrecs = 0, nrecs0, nmiss;
+  int nrecs = 0, nrecs0;
+  size_t nmiss;
   int cum;
   int chksum;                  // for check of histogram population 
   int levelID, varID, binID = 0;
diff --git a/src/Ensval.cc b/src/Ensval.cc
index 7615a38..3281d77 100644
--- a/src/Ensval.cc
+++ b/src/Ensval.cc
@@ -43,7 +43,8 @@ enum RESTYPE_CRPS { CRPS_RES,CRPS_RELI,CRPS_POT };
 void *Ensval(void *argument)
 {
   int i,k;
-  int nrecs = 0, nrecs0, nmiss, nostreams = 0, ngrids;
+  int nrecs = 0, nrecs0, nostreams = 0, ngrids;
+  size_t nmiss;
   int levelID, varID;
   int gridsize = 0;
   int vlistID;
diff --git a/src/Eof3d.cc b/src/Eof3d.cc
index dda6230..e0080cf 100644
--- a/src/Eof3d.cc
+++ b/src/Eof3d.cc
@@ -53,7 +53,8 @@ void *EOF3d(void * argument)
   size_t temp_size = 0, npack = 0;
   int varID, levelID;
   bool missval_warning = false;
-  int nmiss, ngrids;
+  size_t nmiss;
+  int ngrids;
   int n = 0;
   size_t nlevs = 0;
   int timer_cov = 0, timer_eig = 0;
diff --git a/src/Eofcoeff.cc b/src/Eofcoeff.cc
index cf33af6..d3f54ca 100644
--- a/src/Eofcoeff.cc
+++ b/src/Eofcoeff.cc
@@ -37,7 +37,8 @@ void *Eofcoeff(void * argument)
   field_type in;  
   field_type out;
   int i, varID, levelID;    
-  int nrecs, nmiss; 
+  int nrecs;
+  size_t nmiss; 
    
   cdoInitialize(argument);
 
@@ -59,7 +60,7 @@ void *Eofcoeff(void * argument)
   int gridID1 = vlistInqVarGrid(vlistID1, 0);
   int gridID2 = vlistInqVarGrid(vlistID2, 0);
   
-  int gridsize = vlistGridsizeMax(vlistID1);  
+  size_t gridsize = vlistGridsizeMax(vlistID1);  
   if ( gridsize != vlistGridsizeMax(vlistID2) )
     cdoAbort("Gridsize of input files does not match!");
       
@@ -108,7 +109,7 @@ void *Eofcoeff(void * argument)
            cdoAbort("Internal error - too high levelID");
          
          pstreamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, &nmiss);
-         eof[varID][levelID][eofID].nmiss = (size_t) nmiss;
+         eof[varID][levelID][eofID].nmiss = nmiss;
        }
      eofID++;
    }
@@ -181,7 +182,7 @@ void *Eofcoeff(void * argument)
           pstreamInqRecord(streamID2, &varID, &levelID);
           missval2 = vlistInqVarMissval(vlistID2, varID);
           pstreamReadRecord(streamID2, in.ptr, &nmiss);  
-          in.nmiss = (size_t) nmiss;
+          in.nmiss = nmiss;
           
           for ( eofID = 0; eofID < neof; eofID++ )
             {
@@ -190,7 +191,7 @@ void *Eofcoeff(void * argument)
               out.ptr[0]  = 0;
               out.grid    = gridID3;
               out.missval = missval2;            
-              for(i=0;i<gridsize;i++)
+              for(size_t i=0;i<gridsize;i++)
                 {                  
                   if (! DBL_IS_EQUAL(in.ptr[i],missval2) && 
                       ! DBL_IS_EQUAL(eof[varID][levelID][eofID].ptr[i],missval1 ))
diff --git a/src/Eofcoeff3d.cc b/src/Eofcoeff3d.cc
index b4e1d8e..c57644b 100644
--- a/src/Eofcoeff3d.cc
+++ b/src/Eofcoeff3d.cc
@@ -36,7 +36,8 @@ void *Eofcoeff3d(void * argument)
   double missval1 = -999, missval2 = -999;
   field_type in;  
   int i, varID, levelID;    
-  int nrecs, nmiss; 
+  int nrecs;
+  size_t nmiss; 
    
   cdoInitialize(argument);
 
@@ -57,7 +58,7 @@ void *Eofcoeff3d(void * argument)
   int gridID1 = vlistInqVarGrid(vlistID1, 0);
   int gridID2 = vlistInqVarGrid(vlistID2, 0);
   
-  int gridsize = vlistGridsizeMax(vlistID1);  
+  size_t gridsize = vlistGridsizeMax(vlistID1);  
   if ( gridsize != vlistGridsizeMax(vlistID2) )
     cdoAbort("Gridsize of input files does not match!");     
   
@@ -106,7 +107,7 @@ void *Eofcoeff3d(void * argument)
            cdoAbort("Internal error - too high levelID");
          
          pstreamReadRecord(streamID1, eof[varID][levelID][eofID].ptr, &nmiss);
-         eof[varID][levelID][eofID].nmiss = (size_t) nmiss;
+         eof[varID][levelID][eofID].nmiss = nmiss;
        }
      eofID++;
    }
@@ -199,14 +200,14 @@ void *Eofcoeff3d(void * argument)
           pstreamInqRecord(streamID2, &varID, &levelID);
           pstreamReadRecord(streamID2, in.ptr, &nmiss);  
           missval2 = vlistInqVarMissval(vlistID2, varID);
-          in.nmiss = (size_t) nmiss;
+          in.nmiss = nmiss;
           
           for ( eofID = 0; eofID < neof; eofID++ )
             {
               if ( recID == 0 ) pstreamDefTimestep(streamIDs[eofID],tsID);
 
 	      nmiss = 0;
-              for( i=0; i<gridsize; i++ )
+              for( size_t i=0; i<gridsize; i++ )
                 {                  
                   if (! DBL_IS_EQUAL(in.ptr[i],missval2) && 
                       ! DBL_IS_EQUAL(eof[varID][levelID][eofID].ptr[i],missval1 ) )
@@ -235,7 +236,7 @@ void *Eofcoeff3d(void * argument)
       for ( eofID = 0; eofID < neof; eofID++ ) {
 	for ( varID = 0; varID < nvars; varID++ ) {
 	  pstreamDefRecord(streamIDs[eofID], varID, 0);
-	  pstreamWriteRecord(streamIDs[eofID], out[varID][eofID].ptr, (int)out[varID][eofID].nmiss);
+	  pstreamWriteRecord(streamIDs[eofID], out[varID][eofID].ptr, out[varID][eofID].nmiss);
 	}
       }
 
diff --git a/src/EstFreq.cc b/src/EstFreq.cc
index 4a423e4..68b197b 100644
--- a/src/EstFreq.cc
+++ b/src/EstFreq.cc
@@ -25,7 +25,8 @@ void *EstFreq(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int gridsize, nmiss;
+  int gridsize;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Exprf.cc b/src/Exprf.cc
index 11ca484..e114278 100644
--- a/src/Exprf.cc
+++ b/src/Exprf.cc
@@ -104,6 +104,7 @@ paramType *params_new(int vlistID)
     {
       int gridID     = vlistInqVarGrid(vlistID, varID);
       int zaxisID    = vlistInqVarZaxis(vlistID, varID);
+      int datatype   = vlistInqVarDatatype(vlistID, varID);
       int steptype   = vlistInqVarTimetype(vlistID, varID);
       int ngp        = gridInqSize(gridID);
       int nlev       = zaxisInqSize(zaxisID);
@@ -119,6 +120,7 @@ paramType *params_new(int vlistID)
       params[varID].coord    = 0;
       params[varID].gridID   = gridID;
       params[varID].zaxisID  = zaxisID;
+      params[varID].datatype = datatype;
       params[varID].steptype = steptype;
       params[varID].ngp      = ngp;
       params[varID].nlev     = nlev;
@@ -217,7 +219,7 @@ int params_add_ts(parse_param_t *parse_arg)
       params[varID].steptype = TIME_VARYING;
       params[varID].ngp      = 1;
       params[varID].nlev     = 1;
-      
+
       parse_arg->nparams++;
     }
 
@@ -322,7 +324,7 @@ void *Expr(void *argument)
 
   if ( cdoVerbose )
     for ( int varID = 0; varID < parse_arg.nparams; varID++ )
-      cdoPrint("var: %d %s ngp=%lu nlev=%lu coord=%c",
+      cdoPrint("var: %d %s ngp=%zu nlev=%zu coord=%c",
                varID, params[varID].name, params[varID].ngp, params[varID].nlev, params[varID].coord==0?' ':params[varID].coord);
 
   int *varIDmap = (int*) Malloc(parse_arg.nparams*sizeof(int));
@@ -516,7 +518,7 @@ void *Expr(void *argument)
 	    {
 	      size_t offset = params[varID].ngp*levelID;
 	      double *vardata = params[varID].data + offset;
-              int nmiss;
+              size_t nmiss;
 	      pstreamReadRecord(streamID1, vardata, &nmiss);
 	      params[varID].nmiss += nmiss;
 	    }
@@ -551,7 +553,7 @@ void *Expr(void *argument)
               size_t offset = ngp*levelID;
 	      double *vardata = params[pidx].data + offset;
 
-	      int nmiss = 0;
+	      size_t nmiss = 0;
 	      for ( size_t i = 0; i < ngp; i++ )
 		if ( DBL_IS_EQUAL(vardata[i], missval) ) nmiss++;
 
diff --git a/src/FC.cc b/src/FC.cc
index 1afcc03..08b5c46 100644
--- a/src/FC.cc
+++ b/src/FC.cc
@@ -41,8 +41,9 @@ void *FC(void *argument)
   int gridIDsp = -1, gridIDgp = -1, gridIDfc = -1;
   int gridID1 = -1, gridID2 = -1;
   int gridID;
-  int nmiss;
-  int nlon = 0, nlat = 0, ntr = 0;
+  size_t nmiss;
+  size_t nlon = 0, nlat = 0;
+  int ntr = 0;
   int nsp = 0, nfc = 0;
   double *array2 = NULL;
   SPTRANS *sptrans = NULL;
@@ -218,17 +219,12 @@ void *FC(void *argument)
 	}
     }
 
-  // printf("nfc %d, ntr %d, nlat %d, nlon %d\n", nfc, ntr, nlat, nlon);
+  // printf("nfc %d, ntr %d, nlat %zu, nlon %zu\n", nfc, ntr, nlat, nlon);
 
   int nvars = vlistNvars(vlistID2);
-  int *vars  = (int*) Malloc(nvars*sizeof(int));
+  bool *vars  = (bool*) Malloc(nvars*sizeof(bool));
   for ( varID = 0; varID < nvars; varID++ )
-    {
-      if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
-	vars[varID] = TRUE;
-      else
-	vars[varID] = FALSE;
-    }
+    vars[varID] = gridID1 == vlistInqVarGrid(vlistID1, varID);
 
   if ( gridID1 != -1 ) vlistChangeGrid(vlistID2, gridID1, gridID2);
 
@@ -236,12 +232,12 @@ void *FC(void *argument)
 
   pstreamDefVlist(streamID2, vlistID2);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
-  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  size_t gridsizemax = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsizemax*sizeof(double));
 
   if ( gridID2 != -1 )
     {
-      gridsize = gridInqSize(gridID2);
+      size_t gridsize = gridInqSize(gridID2);
       array2 = (double*) Malloc(gridsize*sizeof(double));
     }
 
diff --git a/src/Fillmiss.cc b/src/Fillmiss.cc
index d8897fe..64f15dd 100644
--- a/src/Fillmiss.cc
+++ b/src/Fillmiss.cc
@@ -41,7 +41,7 @@ extern "C" {
 void fillmiss(field_type *field1, field_type *field2, int nfill)
 {
   int nx, ny, i, j;
-  int nmiss2 = 0;
+  size_t nmiss2 = 0;
   int kr, ku, kl, ko;
   int ir, iu, il, io;
   int kh, kv, k1, k2, kk;
@@ -51,7 +51,7 @@ void fillmiss(field_type *field1, field_type *field2, int nfill)
   double **matrix1, **matrix2;
 
   int gridID = field1->grid;
-  int nmiss1 = field1->nmiss;
+  size_t nmiss1 = field1->nmiss;
   double missval  = field1->missval;
   double *array1  = field1->ptr;
   double *array2  = field2->ptr;
@@ -156,7 +156,7 @@ void fillmiss(field_type *field1, field_type *field2, int nfill)
 void fillmiss_one_step(field_type *field1, field_type *field2, int maxfill)
 {
   int gridID, nx, ny, i, j;
-  int nmiss2 = 0;
+  size_t nmiss2 = 0;
   int kr, ku, kl, ko;
   int ir, iu, il, io;
   int kh, kv, k1, k2, kk;
@@ -419,7 +419,7 @@ void setmisstodis(field_type *field1, field_type *field2, int num_neighbors)
 
 void *Fillmiss(void *argument)
 {
-  int nmiss;
+  size_t nmiss;
   int nrecs, varID, levelID;
   void (*fill_method) (field_type *fin , field_type *fout , int) = NULL;
 
@@ -528,7 +528,7 @@ void *Fillmiss(void *argument)
               fill_method(&field1, &field2, nfill);
 
               int gridsize = gridInqSize(field2.grid);
-              int nmiss = 0;
+              size_t nmiss = 0;
               for ( int i = 0; i < gridsize; ++i )
                 if ( DBL_IS_EQUAL(field2.ptr[i], field2.missval) ) nmiss++;
               
diff --git a/src/Filter.cc b/src/Filter.cc
index 33a9a89..f9dbebb 100644
--- a/src/Filter.cc
+++ b/src/Filter.cc
@@ -124,7 +124,7 @@ void *Filter(void *argument)
   int nrecs;
   int varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int incperiod0, incunit0, incunit;
   int year0, month0, day0;
   bool use_fftw = false;
@@ -396,7 +396,7 @@ void *Filter(void *argument)
             {
               if ( vars[tsID][varID][levelID].ptr )
                 {
-                  int nmiss = vars[tsID][varID][levelID].nmiss;
+                  size_t nmiss = vars[tsID][varID][levelID].nmiss;
                   pstreamDefRecord(streamID2, varID, levelID);
                   pstreamWriteRecord(streamID2, vars[tsID][varID][levelID].ptr, nmiss);
 
diff --git a/src/Fldrms.cc b/src/Fldrms.cc
index 72f0130..bb8ac2a 100644
--- a/src/Fldrms.cc
+++ b/src/Fldrms.cc
@@ -34,7 +34,7 @@ void *Fldrms(void *argument)
   int index;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   double sglval;
 
   cdoInitialize(argument);
@@ -116,10 +116,10 @@ void *Fldrms(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
 	  pstreamInqRecord(streamID2, &varID, &levelID);
 	  pstreamReadRecord(streamID2, field2.ptr, &nmiss);
-          field2.nmiss = (size_t) nmiss;
+          field2.nmiss = nmiss;
 
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
@@ -147,7 +147,7 @@ void *Fldrms(void *argument)
 	  fldrms(field1, field2, &field3);
 
 	  pstreamDefRecord(streamID3, varID,  levelID);
-	  pstreamWriteRecord(streamID3, &sglval, (int)field3.nmiss);
+	  pstreamWriteRecord(streamID3, &sglval, field3.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Fldstat.cc b/src/Fldstat.cc
index 2eb6a9d..ed9017d 100644
--- a/src/Fldstat.cc
+++ b/src/Fldstat.cc
@@ -87,7 +87,7 @@ void *Fldstat(void *argument)
   int index;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   double sglval;
 
   cdoInitialize(argument);
diff --git a/src/Fldstat2.cc b/src/Fldstat2.cc
index 71c2a6b..95ad061 100644
--- a/src/Fldstat2.cc
+++ b/src/Fldstat2.cc
@@ -94,7 +94,7 @@ void *Fldstat2(void *argument)
   int gridID3;
   int nrecs, nrecs2;
   int varID, levelID;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   bool wstatus = false;
   bool needWeights = true;
   double sglval = 0;
@@ -193,7 +193,7 @@ void *Fldstat2(void *argument)
 	      sglval = covariance_s(array1, array2, weight, missval1, missval2, gridsize);
 	    }
 
-          int nmiss3 = DBL_IS_EQUAL(sglval, missval1) ? 1 : 0;
+          size_t nmiss3 = DBL_IS_EQUAL(sglval, missval1) ? 1 : 0;
 
 	  pstreamDefRecord(streamID3, varID,  levelID);
 	  pstreamWriteRecord(streamID3, &sglval, nmiss3);
diff --git a/src/Fourier.cc b/src/Fourier.cc
index 8cab19f..691caf7 100644
--- a/src/Fourier.cc
+++ b/src/Fourier.cc
@@ -33,7 +33,7 @@ void *Fourier(void *argument)
   int nrecs;
   int gridID, varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   int *vdate = NULL, *vtime = NULL;
   double missval;
diff --git a/src/Gengrid.cc b/src/Gengrid.cc
index 63ef912..8e1b34e 100644
--- a/src/Gengrid.cc
+++ b/src/Gengrid.cc
@@ -30,7 +30,7 @@
 void *Gengrid(void *argument)
 {
   int varID, levelID;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   double missval = 0;
 
   cdoInitialize(argument);
@@ -55,6 +55,9 @@ void *Gengrid(void *argument)
   double *array2 = (double*) Malloc(gridsize*sizeof(double));
   double *array3 = (double*) Malloc(gridsize*sizeof(double));
 
+  pstreamInqTimestep(streamID1, 0);
+  pstreamInqTimestep(streamID2, 0);
+
   pstreamInqRecord(streamID1, &varID, &levelID);
   pstreamReadRecord(streamID1, array1, &nmiss1);
   pstreamInqRecord(streamID2, &varID, &levelID);
diff --git a/src/Gradsdes.cc b/src/Gradsdes.cc
index 92aaa60..b7d4fa1 100644
--- a/src/Gradsdes.cc
+++ b/src/Gradsdes.cc
@@ -22,7 +22,7 @@
 */
 
 
-#if defined(HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #include "config.h" /* VERSION */
 #endif
 
@@ -963,7 +963,7 @@ void *Gradsdes(void *argument)
   int idmn, idhh, idmm, idyy, iddd;
   int dt=1, iik=0, mdt = 0;
   int gridsize = 0;
-  int nmiss;
+  size_t nmiss;
   int prec;
   int map_version = 2;
   int maxrecs = 0;
diff --git a/src/Gridboxstat.cc b/src/Gridboxstat.cc
index c135b86..8dbef1b 100644
--- a/src/Gridboxstat.cc
+++ b/src/Gridboxstat.cc
@@ -39,16 +39,16 @@
 
 
 static
-int genBoxGrid(int gridID1, int xinc, int yinc)
+int genBoxGrid(int gridID1, size_t xinc, size_t yinc)
 {
-  int i, j, i1;
+  size_t i, j, i1;
   int gridID2 = -1;
-  int nlon1 = 0, nlat1 = 0;
-  int gridsize2 = 0, nlon2 = 0, nlat2 = 0;
-  int x1, y1, x2, y2;
-  int use_x1, use_y1;
-  int corner, add, g2_add; 
-  int g1_add;
+  size_t nlon1 = 0, nlat1 = 0;
+  size_t gridsize2 = 0, nlon2 = 0, nlat2 = 0;
+  size_t x1, y1, x2, y2;
+  size_t use_x1, use_y1;
+  size_t g1_add, g2_add;
+  int corner, add; 
   int circular = gridIsCircular(gridID1) ;
   double *grid1_corner_lon = NULL, *grid1_corner_lat = NULL;
   double *grid2_corner_lon = NULL, *grid2_corner_lat = NULL;
@@ -57,7 +57,7 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
   double area_norm;  
 
   int gridtype  = gridInqType(gridID1);
-  int gridsize1 = gridInqSize(gridID1);
+  size_t gridsize1 = gridInqSize(gridID1);
 
   if ( xinc < 1 || yinc < 1 )
     cdoAbort("xinc and yinc must not be smaller than 1!");
@@ -330,7 +330,7 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
 				  lon = grid1_corner_lon[add];
 				  lat = grid1_corner_lat[add]; 
 				  g1_add2 = g1_add-1;
-				  if ( g1_add-nlon1 < 0 ) 
+				  if ( g1_add < nlon1 ) 
 				    {
 				      cdoWarning("Can't find cell above lower right left");
 				      continue; 
@@ -365,7 +365,7 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
 				  lon = grid1_corner_lon[add];
 				  lat = grid1_corner_lat[add]; 
 				  g1_add2 = g1_add+1;
-				  if ( g1_add-nlon1 < 0 ) 
+				  if ( g1_add < nlon1 ) 
 				    {
 				      cdoWarning("Can't find cell above lower right left");
 				      continue; 
@@ -446,7 +446,7 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
 }
 
 static
-void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int statfunc)
+void gridboxstat(field_type *field1, field_type *field2, size_t xinc, size_t yinc, int statfunc)
 {
   bool useWeight = (field1->weight != NULL);
   /*
@@ -455,7 +455,7 @@ void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int
   progressInit();
   */
 
-  int gridsize = xinc*yinc;
+  size_t gridsize = xinc*yinc;
   field_type *field = (field_type*) Malloc(ompNumThreads*sizeof(field_type));
   for ( int i = 0; i < ompNumThreads; i++ )
     {
@@ -472,16 +472,16 @@ void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int
   double *array2 = field2->ptr;
   double missval = field1->missval;
 
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
-  int nlon2 = gridInqXsize(gridID2);
-  int nlat2 = gridInqYsize(gridID2);
+  size_t nlon2 = gridInqXsize(gridID2);
+  size_t nlat2 = gridInqYsize(gridID2);
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
 #endif
-  for ( int ig = 0; ig < nlat2*nlon2; ++ig )
+  for ( size_t ig = 0; ig < nlat2*nlon2; ++ig )
     {
       int ompthID = cdo_omp_get_thread_num();
 
@@ -496,19 +496,19 @@ void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int
       findex++;
       if ( lprogress ) progressStatus(0, 1, findex/nlat2*nlon2);
       */
-      int ilat = ig/nlon2;
-      int ilon = ig - ilat*nlon2;
+      size_t ilat = ig/nlon2;
+      size_t ilon = ig - ilat*nlon2;
 
-      int isize = 0;
+      size_t isize = 0;
       field[ompthID].nmiss = 0;
-      for ( int j = 0; j < yinc; ++j )
+      for ( size_t j = 0; j < yinc; ++j )
 	{
-	  int jj = ilat*yinc+j;
+	  size_t jj = ilat*yinc+j;
 	  if ( jj >= nlat1 ) break;
-	  for ( int i = 0; i < xinc; ++i )
+	  for ( size_t i = 0; i < xinc; ++i )
 	    {
-	      int ii = ilon*xinc+i;
-	      int index = jj*nlon1 + ii;
+	      size_t ii = ilon*xinc+i;
+	      size_t index = jj*nlon1 + ii;
 	      if ( ii >= nlon1 ) break;
 	      field[ompthID].ptr[isize] = array1[index];
 	      if ( useWeight ) field[ompthID].weight[isize] = field1->weight[index];
@@ -521,8 +521,8 @@ void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int
       field2->ptr[ig] = fldfun(field[ompthID], statfunc);
     }
   
-  int nmiss = 0;
-  for ( int i = 0; i < nlat2*nlon2; i++ )
+  size_t nmiss = 0;
+  for ( size_t i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
   
   field2->nmiss = nmiss;
@@ -596,11 +596,11 @@ void *Gridboxstat(void *argument)
   field_init(&field1);
   field_init(&field2);
 
-  int gridsize1 = gridInqSize(gridID1);
+  size_t gridsize1 = gridInqSize(gridID1);
   field1.ptr    = (double*) Malloc(gridsize1*sizeof(double));
   field1.weight = needWeights ? (double*) Malloc(gridsize1*sizeof(double)) : NULL;
 
-  int gridsize2 = gridInqSize(gridID2);
+  size_t gridsize2 = gridInqSize(gridID2);
   field2.ptr    = (double*) Malloc(gridsize2*sizeof(double));
   field2.weight = NULL;
 
@@ -613,10 +613,10 @@ void *Gridboxstat(void *argument)
 
       for ( int recID = 0; recID < nrecs; recID++ )
         {
-          int nmiss;
+          size_t nmiss;
           pstreamInqRecord(streamID1, &varID, &levelID);
           pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
 
           field1.grid = vlistInqVarGrid(vlistID1, varID);
           field1.size = gridInqSize(field1.grid);
@@ -640,7 +640,7 @@ void *Gridboxstat(void *argument)
           gridboxstat(&field1, &field2, xinc, yinc, operfunc);
           
           pstreamDefRecord(streamID2, varID,  levelID);
-          pstreamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
+          pstreamWriteRecord(streamID2, field2.ptr, field2.nmiss);
         }
       tsID++;
     }
diff --git a/src/Harmonic.cc b/src/Harmonic.cc
index 4b1e829..a93c017 100644
--- a/src/Harmonic.cc
+++ b/src/Harmonic.cc
@@ -32,7 +32,7 @@ void *Harmonic(void *argument)
   int gridsize;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int offset;
   int nlevel;
   int vdate = 0, vtime = 0;
diff --git a/src/Hi.cc b/src/Hi.cc
index 9b7bb93..368c290 100644
--- a/src/Hi.cc
+++ b/src/Hi.cc
@@ -49,26 +49,26 @@ static double humidityIndex(double t, double e, double r, double missval)
 static void farexpr(field_type *field1, field_type field2, field_type field3, double (*expression)(double, double, double, double))
 {
   const int     grid1    = field1->grid;
-  const int     nmiss1   = field1->nmiss;
+  const size_t  nmiss1   = field1->nmiss;
   const double  missval1 = field1->missval;
   double       *array1   = field1->ptr;
   const int     grid2    = field2.grid;
-  const int     nmiss2   = field2.nmiss;
+  const size_t  nmiss2   = field2.nmiss;
   const double  missval2 = field2.missval;
   const double *array2   = field2.ptr;
   const int     grid3    = field3.grid;
-  const int     nmiss3   = field3.nmiss;
+  const size_t  nmiss3   = field3.nmiss;
   const double  missval3 = field3.missval;
   const double *array3   = field3.ptr;
 
-  int len = gridInqSize(grid1);
+  size_t len = gridInqSize(grid1);
 
   if ( len != gridInqSize(grid2) || len != gridInqSize(grid3) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 || nmiss3 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         if ( DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) || DBL_IS_EQUAL(array3[i], missval3))  
 	  array1[i] = missval1;
 	else
@@ -76,19 +76,19 @@ static void farexpr(field_type *field1, field_type field2, field_type field3, do
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         array1[i] = expression(array1[i], array2[i], array3[i], missval1);  
     }
 
   field1->nmiss = 0;
-  for ( int i = 0; i < len; i++ )
+  for ( size_t i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
    
 void *Hi(void *argument)
 {
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   int varID1, varID2, varID3;
   int levelID1, levelID2, levelID3;
@@ -111,7 +111,7 @@ void *Hi(void *argument)
   vlistCompare(vlistID1, vlistID2, CMP_DIM);
   vlistCompare(vlistID1, vlistID3, CMP_DIM);
   
-  int gridsize = vlistGridsizeMax(vlistID1);
+  size_t gridsize = vlistGridsizeMax(vlistID1);
 
   field_type field1, field2, field3;
   field_init(&field1);
@@ -160,15 +160,15 @@ void *Hi(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID1, &levelID1);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
           
 	  pstreamInqRecord(streamID2, &varID2, &levelID2);
 	  pstreamReadRecord(streamID2, field2.ptr, &nmiss);
-          field2.nmiss = (size_t) nmiss;
+          field2.nmiss = nmiss;
 	  
 	  pstreamInqRecord(streamID3, &varID3, &levelID3);
 	  pstreamReadRecord(streamID3, field3.ptr, &nmiss);
-          field3.nmiss = (size_t) nmiss;
+          field3.nmiss = nmiss;
 	  
 	  if ( varID1 != varID2 || varID1 != varID3 || levelID1 != levelID2 || levelID1 != levelID3 )
 	    cdoAbort("Input streams have different structure!");
@@ -187,7 +187,7 @@ void *Hi(void *argument)
 	  farexpr(&field1, field2, field3, humidityIndex);
 	  
 	  pstreamDefRecord(streamID4, varID4, levelID1);
-	  pstreamWriteRecord(streamID4, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID4, field1.ptr, field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Histogram.cc b/src/Histogram.cc
index 8440b2d..9b3d81f 100644
--- a/src/Histogram.cc
+++ b/src/Histogram.cc
@@ -30,7 +30,7 @@
 void *Histogram(void *argument)
 {
   int nrecs, varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int offset;
   int nlevel, zaxisID;
   double missval;
diff --git a/src/Importamsr.cc b/src/Importamsr.cc
index cdc22fb..a6c9e74 100644
--- a/src/Importamsr.cc
+++ b/src/Importamsr.cc
@@ -111,7 +111,7 @@ void init_amsr_averaged(int vlistID, int gridID, int zaxisID, int nvars)
 }
 
 static
-void read_amsr(FILE *fp, int vlistID, int nvars, double *data[], int *nmiss)
+void read_amsr(FILE *fp, int vlistID, int nvars, double *data[], size_t *nmiss)
 {
   int varID, i, gridsize;
   unsigned char *amsr_data = NULL;
@@ -148,7 +148,7 @@ void read_amsr(FILE *fp, int vlistID, int nvars, double *data[], int *nmiss)
 }
 
 static
-void write_data(int streamID, int nvars, double *data[], int *nmiss)
+void write_data(int streamID, int nvars, double *data[], size_t *nmiss)
 {
   for ( int varID = 0; varID < nvars; ++varID )
     {
@@ -176,7 +176,7 @@ void *Importamsr(void *argument)
   int vtime = 0;
   double xvals[NLON], yvals[NLAT];
   double *data[MAX_VARS];
-  int nmiss[MAX_VARS];
+  size_t nmiss[MAX_VARS];
 
   cdoInitialize(argument);
 
diff --git a/src/Importbinary.cc b/src/Importbinary.cc
index 97d3725..260285d 100644
--- a/src/Importbinary.cc
+++ b/src/Importbinary.cc
@@ -188,7 +188,7 @@ int define_level(dsets_t *pfi, int nlev)
 void *Importbinary(void *argument)
 {
   int i;
-  int nmiss = 0, n_nan;
+  size_t nmiss = 0, n_nan;
   int ivar;
   int varID = -1, levelID, tsID;
   int gridsize;
@@ -536,7 +536,7 @@ void *Importbinary(void *argument)
 		}
 	      /*
 	      if ( cdoVerbose )
-		printf("%3d %4d %3d %6d %6d %12.5g %12.5g\n", tsID, recID, recoffset, nmiss, n_nan, fmin, fmax);
+		printf("%3d %4d %3d %6zu %6zu %12.5g %12.5g\n", tsID, recID, recoffset, nmiss, n_nan, fmin, fmax);
 	      */
 	      varID   = recVarID[recID];
 	      levelID = recLevelID[recID];
diff --git a/src/Importcmsaf.cc b/src/Importcmsaf.cc
index 85919e2..9db4d0b 100644
--- a/src/Importcmsaf.cc
+++ b/src/Importcmsaf.cc
@@ -769,7 +769,7 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
   char varname[CDI_MAX_NAME];
   short *mask = NULL;
   double minval, maxval;
-  int nmiss;
+  size_t nmiss;
   int num_attrs;
 
   attstring[0] = 0;
@@ -1395,7 +1395,7 @@ void *Importcmsaf(void *argument)
   int streamID;
   int gridID = -1, zaxisID, taxisID, vlistID;
   int i, offset;
-  int nmiss;
+  size_t nmiss;
   int ivar;
   int varID, levelID, tsID;
   int nx, ny, nz, nt, gridsize;
@@ -1593,7 +1593,7 @@ void *Importcmsaf(void *argument)
 		if ( DBL_IS_EQUAL(array[i], missval) ) nmiss++;
 
 	      if ( cdoVerbose )
-		cdoPrint(" Write var %d,  level %d, nmiss %d, missval %g, minval %g, maxval %g",
+		cdoPrint(" Write var %d,  level %d, nmiss %zu, missval %g, minval %g, maxval %g",
 			 varID, levelID, nmiss, missval, minval, maxval);
 	      /*
 		if ( ! (missval < minval || missval > maxval) )
diff --git a/src/Importobs.cc b/src/Importobs.cc
index 96b0b48..a95e150 100644
--- a/src/Importobs.cc
+++ b/src/Importobs.cc
@@ -66,7 +66,7 @@ void write_data(int streamID, int vlistID, int nvars, double *data[])
       
       pstreamDefRecord(streamID, varID, 0);
 
-      int nmiss = 0;
+      size_t nmiss = 0;
       for ( int i = 0; i < gridsize; ++i )
 	if ( DBL_IS_EQUAL(data[varID][i], missval) ) nmiss++;
       
diff --git a/src/Info.cc b/src/Info.cc
index 99d83bf..117d854 100644
--- a/src/Info.cc
+++ b/src/Info.cc
@@ -241,7 +241,7 @@ void printMap(int nlon, int nlat, double *array, double missval, double min, dou
 
 typedef struct {
   double min, max, sum, sumi;
-  long nvals, nmiss, nlevs;
+  size_t nvals, nmiss, nlevs;
 } infostat_type;
 
 static
@@ -263,8 +263,8 @@ void *Info(void *argument)
   int fpeRaised = 0;
   int varID, levelID;
   int nrecs;
-  int nmiss;
-  long imiss = 0;
+  size_t nmiss;
+  size_t imiss = 0;
   char varname[CDI_MAX_NAME];
   char paramstr[32];
   char vdatestr[32], vtimestr[32];
@@ -304,7 +304,7 @@ void *Info(void *argument)
 
       infostat_type *infostat = (infostat_type*) Malloc(nvars*sizeof(infostat_type));
                   
-      int gridsizemax = vlistGridsizeMax(vlistID);
+      size_t gridsizemax = vlistGridsizeMax(vlistID);
       if ( vlistNumber(vlistID) != CDI_REAL ) gridsizemax *= 2;
 
       double *array = (double*) Malloc(gridsizemax*sizeof(double));
@@ -350,8 +350,8 @@ void *Info(void *argument)
 	      int gridID   = vlistInqVarGrid(vlistID, varID);
 	      int zaxisID  = vlistInqVarZaxis(vlistID, varID);
 	      int number   = vlistInqVarNumber(vlistID, varID);
-	      long gridsize = gridInqSize(gridID);
-              long nlevs    = zaxisInqSize(zaxisID);
+	      size_t gridsize = gridInqSize(gridID);
+              size_t nlevs  = zaxisInqSize(zaxisID);
 	      double level = cdoZaxisInqLevel(zaxisID, levelID);
 	      double missval = vlistInqVarMissval(vlistID, varID);
               
@@ -383,11 +383,11 @@ void *Info(void *argument)
 
                   set_text_color(stdout, RESET, GREEN);
                   if ( operatorID == XINFON )
-                    fprintf(stdout, "%7ld ", nlevs);
+                    fprintf(stdout, "%7zu ", nlevs);
                   else
                     fprintf(stdout, "%7g ", level);
                  
-                  fprintf(stdout, "%8ld %7ld ", gridsize, infostatp->nmiss);
+                  fprintf(stdout, "%8zu %7zu ", gridsize, infostatp->nmiss);
 		
                   set_text_color(stdout, RESET, BLACK);
                   fprintf(stdout, ":");
@@ -402,8 +402,8 @@ void *Info(void *argument)
 
                   if ( infostatp->nmiss > 0 )
                     {
-                      long nvals   = 0;
-                      for ( long i = 0; i < gridsize; ++i )
+                      size_t nvals   = 0;
+                      for ( size_t i = 0; i < gridsize; ++i )
                         {
                           if ( !DBL_IS_EQUAL(array[i], missval) )
                             {
@@ -452,8 +452,8 @@ void *Info(void *argument)
                 }
               else
                 {
-                  long nvals = 0;		      
-                  for ( long i = 0; i < gridsize; i++ )
+                  size_t nvals = 0;		      
+                  for ( size_t i = 0; i < gridsize; i++ )
                     {
                       if ( !DBL_IS_EQUAL(array[i*2],   missval) && 
                            !DBL_IS_EQUAL(array[i*2+1], missval) )
@@ -505,14 +505,14 @@ void *Info(void *argument)
                 }
 
 	      if ( imiss != nmiss && nmiss > 0 )
-		cdoPrint("Found %d of %d missing values!", imiss, nmiss);
+		cdoPrint("Found %zu of %zu missing values!", imiss, nmiss);
 
               if ( fpeRaised > 0 ) cdoWarning("floating-point exception reported: %s!", fpe_errstr(fpeRaised));
 
 	      if ( operatorID == MAP )
 		{		  
-		  int nlon = gridInqXsize(gridID);
-		  int nlat = gridInqYsize(gridID);
+		  size_t nlon = gridInqXsize(gridID);
+		  size_t nlat = gridInqYsize(gridID);
 
 		  if ( gridInqType(gridID) == GRID_GAUSSIAN    ||
 		       gridInqType(gridID) == GRID_LONLAT      ||
diff --git a/src/Input.cc b/src/Input.cc
index e8372a1..b9372aa 100644
--- a/src/Input.cc
+++ b/src/Input.cc
@@ -245,7 +245,7 @@ void *Input(void *argument)
 	  pstreamDefRecord(streamID, varID, levelID);
 
           int offset = gridsize*levelID;
-	  int nmiss = 0;
+	  size_t nmiss = 0;
 	  for ( i = 0; i < gridsize; ++i )
 	    if ( DBL_IS_EQUAL(array[offset+i], missval) ) nmiss++;
 
diff --git a/src/Intgrid.cc b/src/Intgrid.cc
index 7c03a86..d6b0bdb 100644
--- a/src/Intgrid.cc
+++ b/src/Intgrid.cc
@@ -30,17 +30,17 @@
 #include "grid.h"
 
 
-int genThinoutGrid(int gridID1, int xinc, int yinc)
+int genThinoutGrid(int gridID1, size_t xinc, size_t yinc)
 {
   int gridtype = gridInqType(gridID1);
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
-  int nlon2 = nlon1/xinc;
-  int nlat2 = nlat1/yinc;
+  size_t nlon2 = nlon1/xinc;
+  size_t nlat2 = nlat1/yinc;
   if ( nlon1%xinc ) nlon2++;
   if ( nlat1%yinc ) nlat2++;
-  int gridsize2 = nlon2*nlat2;
+  size_t gridsize2 = nlon2*nlat2;
 
   int gridID2 = gridCreate(GRID_LONLAT, gridsize2);
   gridDefXsize(gridID2, nlon2);
@@ -55,15 +55,15 @@ int genThinoutGrid(int gridID1, int xinc, int yinc)
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
-      int olat = 0;
-      for ( int ilat = 0; ilat < nlat1; ilat+=yinc )
+      size_t olat = 0;
+      for ( size_t ilat = 0; ilat < nlat1; ilat+=yinc )
 	{
 	  yvals2[olat] = yvals1[ilat];
 	  olat++;
 	}
 
-      int olon = 0;
-      for ( int ilon = 0; ilon < nlon1; ilon+=xinc )
+      size_t olon = 0;
+      for ( size_t ilon = 0; ilon < nlon1; ilon+=xinc )
 	{
 	  xvals2[olon] = xvals1[ilon];
 	  olon++;
@@ -88,17 +88,17 @@ int genThinoutGrid(int gridID1, int xinc, int yinc)
 
 int genBoxavgGrid(int gridID1, int xinc, int yinc)
 {
-  int i, j, i1;
+  size_t i, j, i1;
 
   int gridtype = gridInqType(gridID1);
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
-  int nlon2 = nlon1/xinc;
-  int nlat2 = nlat1/yinc;
+  size_t nlon2 = nlon1/xinc;
+  size_t nlat2 = nlat1/yinc;
   if ( nlon1%xinc ) nlon2++;
   if ( nlat1%yinc ) nlat2++;
-  int gridsize2 = nlon2*nlat2;
+  size_t gridsize2 = nlon2*nlat2;
 
   int gridID2 = gridCreate(GRID_LONLAT, gridsize2);
   gridDefXsize(gridID2, nlon2);
@@ -179,7 +179,7 @@ int genBoxavgGrid(int gridID1, int xinc, int yinc)
 }
 
 static
-void boxavg(field_type *field1, field_type *field2, int xinc, int yinc)
+void boxavg(field_type *field1, field_type *field2, size_t xinc, size_t yinc)
 {
   int gridID1 = field1->grid;
   int gridID2 = field2->grid;
@@ -187,35 +187,35 @@ void boxavg(field_type *field1, field_type *field2, int xinc, int yinc)
   double *array2  = field2->ptr;
   double missval = field1->missval;
 
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
-  int nlon2 = gridInqXsize(gridID2);
-  int nlat2 = gridInqYsize(gridID2);
+  size_t nlon2 = gridInqXsize(gridID2);
+  size_t nlat2 = gridInqYsize(gridID2);
 
   double **xfield1 = (double **) Malloc(nlat1*sizeof(double *));
 
-  for ( int ilat = 0; ilat < nlat1; ilat++ )
+  for ( size_t ilat = 0; ilat < nlat1; ilat++ )
     xfield1[ilat] = array1 + ilat*nlon1;
 
   double **xfield2 = (double **) Malloc(nlat2 * sizeof(double *));
 
-  for ( int ilat = 0; ilat < nlat2; ilat++ )
+  for ( size_t ilat = 0; ilat < nlat2; ilat++ )
     xfield2[ilat] = array2 + ilat*nlon2;
 
-  for ( int ilat = 0; ilat < nlat2; ilat++ )
-    for ( int ilon = 0; ilon < nlon2; ilon++ )
+  for ( size_t ilat = 0; ilat < nlat2; ilat++ )
+    for ( size_t ilon = 0; ilon < nlon2; ilon++ )
       {
 	xfield2[ilat][ilon] = 0;
 
-	int in = 0;
-	for ( int j = 0; j < yinc; ++j )
+	size_t in = 0;
+	for ( size_t j = 0; j < yinc; ++j )
 	  {
-	    int jj = ilat*yinc+j;
+	    size_t jj = ilat*yinc+j;
 	    if ( jj >= nlat1 ) break;
-	    for ( int i = 0; i < xinc; ++i )
+	    for ( size_t i = 0; i < xinc; ++i )
 	      {
-		int ii = ilon*xinc+i;
+		size_t ii = ilon*xinc+i;
 		if ( ii >= nlon1 ) break;
 		in++;
 		xfield2[ilat][ilon] += xfield1[jj][ii];
@@ -224,8 +224,8 @@ void boxavg(field_type *field1, field_type *field2, int xinc, int yinc)
 	xfield2[ilat][ilon] /= in;
       }
 
-  int nmiss = 0;
-  for ( int i = 0; i < nlat2*nlon2; i++ )
+  size_t nmiss = 0;
+  for ( size_t i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
   field2->nmiss = nmiss;
@@ -243,27 +243,27 @@ void thinout(field_type *field1, field_type *field2, int xinc, int yinc)
   double *array2  = field2->ptr;
   double missval = field1->missval;
 
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
-  int nlon2 = gridInqXsize(gridID2);
-  int nlat2 = gridInqYsize(gridID2);
+  size_t nlon2 = gridInqXsize(gridID2);
+  size_t nlat2 = gridInqYsize(gridID2);
 
   double **xfield1 = (double **) Malloc(nlat1*sizeof(double *));
 
-  for ( int ilat = 0; ilat < nlat1; ilat++ )
+  for ( size_t ilat = 0; ilat < nlat1; ilat++ )
     xfield1[ilat] = array1 + ilat*nlon1;
 
   double **xfield2 = (double **) Malloc(nlat2*sizeof(double *));
 
-  for ( int ilat = 0; ilat < nlat2; ilat++ )
+  for ( size_t ilat = 0; ilat < nlat2; ilat++ )
     xfield2[ilat] = array2 + ilat*nlon2;
 
-  int olat = 0;
-  for ( int ilat = 0; ilat < nlat1; ilat+=yinc )
+  size_t olat = 0;
+  for ( size_t ilat = 0; ilat < nlat1; ilat+=yinc )
     {
-      int olon = 0;
-      for ( int ilon = 0; ilon < nlon1; ilon+=xinc )
+      size_t olon = 0;
+      for ( size_t ilon = 0; ilon < nlon1; ilon+=xinc )
 	{
 	  xfield2[olat][olon] = xfield1[ilat][ilon];
 	  olon++;
@@ -271,8 +271,8 @@ void thinout(field_type *field1, field_type *field2, int xinc, int yinc)
       olat++;
     }
 
-  int nmiss = 0;
-  for ( int i = 0; i < nlat2*nlon2; i++ )
+  size_t nmiss = 0;
+  for ( size_t i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
   
   field2->nmiss = nmiss;
@@ -288,7 +288,7 @@ void *Intgrid(void *argument)
   int nrecs;
   int varID, levelID;
   int gridID1 = -1, gridID2 = -1;
-  int nmiss;
+  size_t nmiss;
   int xinc = 0, yinc = 0;
   double missval;
 
@@ -375,7 +375,7 @@ void *Intgrid(void *argument)
   int streamID2 = pstreamOpenWrite(cdoStreamName(1), cdoFiletype());
   pstreamDefVlist(streamID2, vlistID2);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
+  size_t gridsize = vlistGridsizeMax(vlistID1);
   double *array1 = (double*) Malloc(gridsize*sizeof(double));
 
   gridsize = gridInqSize(gridID2);
diff --git a/src/Intgridtraj.cc b/src/Intgridtraj.cc
index 065a28f..6b4b958 100644
--- a/src/Intgridtraj.cc
+++ b/src/Intgridtraj.cc
@@ -55,7 +55,7 @@ void *Intgridtraj(void *argument)
   int gridID1;
   int varID, levelID;
   int vdate, vtime;
-  int nmiss;
+  size_t nmiss;
   double point;
   double xpos, ypos;
   int calendar = CALENDAR_STANDARD;
diff --git a/src/Intlevel.cc b/src/Intlevel.cc
index 902f741..0980013 100644
--- a/src/Intlevel.cc
+++ b/src/Intlevel.cc
@@ -159,7 +159,7 @@ void *Intlevel(void *argument)
   int nrecs;
   int i, offset;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int zaxisID1 = -1;
   int gridID, zaxisID;
   int nlevel = 0;
@@ -290,7 +290,7 @@ void *Intlevel(void *argument)
 
   bool *vars = (bool*) Malloc(nvars*sizeof(bool));
   bool *varinterp = (bool*) Malloc(nvars*sizeof(bool));
-  int **varnmiss = (int**) Malloc(nvars*sizeof(int*));
+  size_t **varnmiss = (size_t**) Malloc(nvars*sizeof(size_t*));
   double **vardata1 = (double**) Malloc(nvars*sizeof(double*));
   double **vardata2 = (double**) Malloc(nvars*sizeof(double*));
 
@@ -309,14 +309,14 @@ void *Intlevel(void *argument)
 	{
 	  varinterp[varID] = true;
 	  vardata2[varID]  = (double*) Malloc(gridsize*nlev2*sizeof(double));
-	  varnmiss[varID]  = (int*) Malloc(maxlev*sizeof(int));
-	  memset(varnmiss[varID], 0, maxlev*sizeof(int));
+	  varnmiss[varID]  = (size_t*) Malloc(maxlev*sizeof(size_t));
+	  memset(varnmiss[varID], 0, maxlev*sizeof(size_t));
 	}
       else
 	{
 	  varinterp[varID] = false;
 	  vardata2[varID]  = vardata1[varID];
-	  varnmiss[varID]  = (int*) Malloc(nlevel*sizeof(int));
+	  varnmiss[varID]  = (size_t*) Malloc(nlevel*sizeof(size_t));
 	}
     }
 
diff --git a/src/Intlevel3d.cc b/src/Intlevel3d.cc
index 5d23e93..19139cb 100644
--- a/src/Intlevel3d.cc
+++ b/src/Intlevel3d.cc
@@ -40,7 +40,7 @@ void *Intlevel3d(void *argument)
   int tsID, varID, levelID;
   int nvars,nvct;
   int nzaxis;
-  int nmiss;
+  size_t nmiss;
 
   int nlonIn, nlatIn, nlonOut, nlatOut;
   //double *lonIn, *latIn, *lonOut, *latOut;
@@ -53,7 +53,7 @@ void *Intlevel3d(void *argument)
   double *single1, *single2;
   int taxisID1, taxisID3;
   double *zlevels_in, *zlevels_out;
-  int zlevels_in_miss, zlevels_out_miss;
+  size_t zlevels_in_miss, zlevels_out_miss;
   char varname[10]; 
 
   cdoInitialize(argument);
@@ -319,7 +319,7 @@ void *Intlevel3d(void *argument)
   nvars     = vlistNvars(vlistID1);
   bool *vars = (bool*) Malloc(nvars*sizeof(bool));
   bool *varinterp = (bool*) Malloc(nvars*sizeof(bool));   /* marker for variables to be interpolated       */
-  int **varnmiss = (int**) Malloc(nvars*sizeof(int*));    /* can for missing values of arbitrary variables */
+  size_t **varnmiss = (size_t**) Malloc(nvars*sizeof(size_t*)); /* can for missing values of arbitrary variables */
   double **vardata1 = (double**) Malloc(nvars*sizeof(double*)); /* input                                         */
   double **vardata2 = (double**) Malloc(nvars*sizeof(double*)); /* output                                        */
 
@@ -359,22 +359,22 @@ void *Intlevel3d(void *argument)
             {
               varinterp[varID] = false;
               vardata2[varID]  = vardata1[varID];
-              varnmiss[varID]  = (int*) Malloc(nlevel*sizeof(int));
+              varnmiss[varID]  = (size_t*) Malloc(nlevel*sizeof(size_t));
               if ( cdoVerbose ) cdoPrint("Ignore variable %s with %d levels",varname,nlevel);
             }
           else
             {
               varinterp[varID] = true;
               vardata2[varID]  = (double*) Malloc(gridsize*nlevo*sizeof(double));
-              varnmiss[varID]  = (int*) Malloc(maxlev*sizeof(int));
-              memset(varnmiss[varID], 0, maxlev*sizeof(int));
+              varnmiss[varID]  = (size_t*) Malloc(maxlev*sizeof(size_t));
+              memset(varnmiss[varID], 0, maxlev*sizeof(size_t));
             }
         }
       else
         {
           varinterp[varID] = false;
           vardata2[varID]  = vardata1[varID];
-          varnmiss[varID]  = (int*) Malloc(nlevel*sizeof(int));
+          varnmiss[varID]  = (size_t*) Malloc(nlevel*sizeof(size_t));
           if ( cdoVerbose ) cdoPrint("Ignore variable %s with %d levels",varname,nlevel);
         }
     }
diff --git a/src/Intntime.cc b/src/Intntime.cc
index 9e7ac5f..4b65174 100644
--- a/src/Intntime.cc
+++ b/src/Intntime.cc
@@ -60,8 +60,8 @@ void *Intntime(void *argument)
   int gridsize = vlistGridsizeMax(vlistID1);
   double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  int **nmiss1   = (int **) Malloc(nvars*sizeof(int *));
-  int **nmiss2   = (int **) Malloc(nvars*sizeof(int *));
+  size_t **nmiss1   = (size_t **) Malloc(nvars*sizeof(size_t *));
+  size_t **nmiss2   = (size_t **) Malloc(nvars*sizeof(size_t *));
   double **vardata1 = (double **) Malloc(nvars*sizeof(double *));
   double **vardata2 = (double **) Malloc(nvars*sizeof(double *));
 
@@ -69,8 +69,8 @@ void *Intntime(void *argument)
     {
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
       nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      nmiss1[varID]   = (int*) Malloc(nlevel*sizeof(int));
-      nmiss2[varID]   = (int*) Malloc(nlevel*sizeof(int));
+      nmiss1[varID]   = (size_t*) Malloc(nlevel*sizeof(size_t));
+      nmiss2[varID]   = (size_t*) Malloc(nlevel*sizeof(size_t));
       vardata1[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
@@ -164,7 +164,7 @@ void *Intntime(void *argument)
 	      single1  = vardata1[varID] + offset;
 	      single2  = vardata2[varID] + offset;
 
-	      int nmiss3 = 0;
+	      size_t nmiss3 = 0;
 
 	      if ( nmiss1[varID][levelID] > 0 || nmiss2[varID][levelID] > 0 )
 		{
diff --git a/src/Inttime.cc b/src/Inttime.cc
index bdb0d75..4617b3f 100644
--- a/src/Inttime.cc
+++ b/src/Inttime.cc
@@ -105,8 +105,8 @@ void *Inttime(void *argument)
   int gridsize = vlistGridsizeMax(vlistID1);
   double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  int **nmiss1   = (int **) Malloc(nvars*sizeof(int *));
-  int **nmiss2   = (int **) Malloc(nvars*sizeof(int *));
+  size_t **nmiss1   = (size_t **) Malloc(nvars*sizeof(size_t *));
+  size_t **nmiss2   = (size_t **) Malloc(nvars*sizeof(size_t *));
   double **vardata1 = (double **) Malloc(nvars*sizeof(double *));
   double **vardata2 = (double **) Malloc(nvars*sizeof(double *));
 
@@ -114,8 +114,8 @@ void *Inttime(void *argument)
     {
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
       nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      nmiss1[varID]   = (int*) Malloc(nlevel*sizeof(int));
-      nmiss2[varID]   = (int*) Malloc(nlevel*sizeof(int));
+      nmiss1[varID]   = (size_t*) Malloc(nlevel*sizeof(size_t));
+      nmiss2[varID]   = (size_t*) Malloc(nlevel*sizeof(size_t));
       vardata1[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
@@ -227,7 +227,7 @@ void *Inttime(void *argument)
 		  single1  = vardata1[varID] + offset;
 		  single2  = vardata2[varID] + offset;
 
-		  int nmiss3 = 0;
+		  size_t nmiss3 = 0;
 
 		  if ( nmiss1[varID][levelID] > 0 || nmiss2[varID][levelID] > 0 )
 		    {
diff --git a/src/Intyear.cc b/src/Intyear.cc
index 5a028fa..639680a 100644
--- a/src/Intyear.cc
+++ b/src/Intyear.cc
@@ -34,7 +34,7 @@ void *Intyear(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss1, nmiss2, nmiss3;
+  size_t nmiss1, nmiss2, nmiss3;
   char filesuffix[32];
   char filename[8192];
 
diff --git a/src/Invert.cc b/src/Invert.cc
index a47d2ac..b216545 100644
--- a/src/Invert.cc
+++ b/src/Invert.cc
@@ -283,7 +283,7 @@ void *Invert(void *argument)
   int nrecs;
   int varID, levelID;
   int gridID1;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Invertlev.cc b/src/Invertlev.cc
index aebfc71..34b03a5 100644
--- a/src/Invertlev.cc
+++ b/src/Invertlev.cc
@@ -93,7 +93,7 @@ void *Invertlev(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nlev, nlevel;
   int gridID, zaxisID, offset;
   bool linvert = false;
@@ -129,7 +129,7 @@ void *Invertlev(void *argument)
   int nvars = vlistNvars(vlistID1);
 
   double **vardata  = (double**) Malloc(nvars*sizeof(double*));
-  int **varnmiss = (int**) Malloc(nvars*sizeof(int*));
+  size_t **varnmiss = (size_t**) Malloc(nvars*sizeof(size_t*));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -147,7 +147,7 @@ void *Invertlev(void *argument)
 	{
 	  linvert = true;
 	  vardata[varID]  = (double*) Malloc(gridsize*nlev*sizeof(double));
-	  varnmiss[varID] = (int*) Malloc(nlev*sizeof(int));
+	  varnmiss[varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	}
     }
 
diff --git a/src/Isosurface.cc b/src/Isosurface.cc
index 88d345e..511bdd4 100644
--- a/src/Isosurface.cc
+++ b/src/Isosurface.cc
@@ -81,7 +81,7 @@ void *Isosurface(void *argument)
   int gridID;
   int i, offset;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int zaxisID, zaxisID1 = -1;
   double missval;
   double *single;
diff --git a/src/Maggraph.cc b/src/Maggraph.cc
index c63ae3e..7553d69 100644
--- a/src/Maggraph.cc
+++ b/src/Maggraph.cc
@@ -882,7 +882,7 @@ void *Maggraph(void *argument)
   int gridID;
   int nrecs;
   int vlistID0 = -1;
-  int nmiss;
+  size_t nmiss;
   long nts_alloc;
   
   int nparam = operatorArgc();
diff --git a/src/Magplot.cc b/src/Magplot.cc
index c191e5f..2ce4ace 100644
--- a/src/Magplot.cc
+++ b/src/Magplot.cc
@@ -1102,7 +1102,7 @@ void *Magplot(void *argument)
 #if defined(HAVE_LIBMAGICS)
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   char varname[CDI_MAX_NAME];
   char units[CDI_MAX_NAME];
   char vdatestr[32], vtimestr[32], datetimestr[64];
diff --git a/src/Magvector.cc b/src/Magvector.cc
index 8999637..66443ed 100644
--- a/src/Magvector.cc
+++ b/src/Magvector.cc
@@ -316,7 +316,7 @@ void *Magvector(void *argument)
 #if defined(HAVE_LIBMAGICS)
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   char varname[CDI_MAX_NAME];
   char units[CDI_MAX_NAME];
   char vdatestr[32],vtimestr[32],datetimestr[64];
diff --git a/src/Makefile.am b/src/Makefile.am
index 4b002b2..839b091 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,12 +1,16 @@
 ## Process this file with automake to produce Makefile.in
 noinst_LTLIBRARIES = libcdo.la
 libcdo_la_SOURCES =            \
-			   argument.h		\
-			   argument.cc		\
-			   array.h         \
+               argument.h		\
+               argument.cc		\
+               array.h         \
                array.cc         \
                cdo_int.h       \
                compare.h       \
+               cfortran.h       \
+               libncl.h         \
+               cfortran.h       \
+               cf_interface.h   \
                cdo_pthread.cc   \
                cdo_vlist.cc     \
                cdo_getopt.cc    \
@@ -22,8 +26,8 @@ libcdo_la_SOURCES =            \
                after_dvtrans.cc \
                after_vertint.cc \
                after_vertint.h \
-               after_namelist.cc\
-               afterburnerlib.cc\
+               after_namelist.cc \
+               afterburnerlib.cc \
                afterburner.h   \
                vct_l191.h      \
                calendar.h      \
@@ -38,6 +42,8 @@ libcdo_la_SOURCES =            \
                counter.h       \
                datetime.cc      \
                datetime.h      \
+               cdoDebugOutput.cc \
+               cdoDebugOutput.h\
                dmemory.h       \
                ecacore.cc       \
                ecacore.h       \
@@ -64,6 +70,8 @@ libcdo_la_SOURCES =            \
                fieldmer.cc      \
                fieldzon.cc      \
                functs.h        \
+               getMemorySize.c \
+               getRSS.c        \
                gradsdeslib.cc   \
                gradsdeslib.h   \
                grid.cc          \
@@ -289,6 +297,7 @@ cdo_SOURCES += Adisit.cc        \
                Monarith.cc      \
                Mrotuv.cc        \
                Mrotuvb.cc       \
+               NCL_wind.cc      \
                Ninfo.cc         \
                Nmldump.cc       \
                Output.cc        \
@@ -398,13 +407,13 @@ cdo_SOURCES += Adisit.cc        \
                cdo.h
 
 cdo_SOURCES += nearpt3c.h
-#if ENABLE_NEARPT3
-#cdo_SOURCES +=           \
-#               nearpt3x.h      \
-#               nearpt3c.h      \
-#               nearpt3c.cc     \
-#               cellsearchorder.h
-#endif
+if ENABLE_NEARPT3
+cdo_SOURCES +=           \
+               nearpt3x.h      \
+               nearpt3c.h      \
+               nearpt3c.cc     \
+               cellsearchorder.h
+endif
 
 #if ENABLE_MAGICS
 cdo_SOURCES += Magplot.cc       \
@@ -424,6 +433,9 @@ cdo_SOURCES += Magplot.cc       \
 
 cdo_CPPFLAGS = -I$(top_srcdir)/libcdi/src
 cdo_LDADD    = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
+if USE_F77
+cdo_LDADD   += $(top_builddir)/src/lib/ncl/libncl.la
+endif
 cdo_LDFLAGS  =
 
 if ENABLE_ALL_STATIC
diff --git a/src/Makefile.in b/src/Makefile.in
index 476d28e..80231d5 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -16,7 +16,17 @@
 
 
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -80,15 +90,21 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 bin_PROGRAMS = cdo$(EXEEXT)
- at ENABLE_ALL_STATIC_TRUE@am__append_1 = -all-static
+ at ENABLE_NEARPT3_TRUE@am__append_1 = \
+ at ENABLE_NEARPT3_TRUE@               nearpt3x.h      \
+ at ENABLE_NEARPT3_TRUE@               nearpt3c.h      \
+ at ENABLE_NEARPT3_TRUE@               nearpt3c.cc     \
+ at ENABLE_NEARPT3_TRUE@               cellsearchorder.h
+
+ at USE_F77_TRUE@am__append_2 = $(top_builddir)/src/lib/ncl/libncl.la
+ at ENABLE_ALL_STATIC_TRUE@am__append_3 = -all-static
 noinst_PROGRAMS = cdotest$(EXEEXT)
- at ENABLE_ALL_STATIC_TRUE@am__append_2 = -all-static
+ at ENABLE_ALL_STATIC_TRUE@am__append_4 = -all-static
 subdir = src
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(srcdir)/config.h.in $(top_srcdir)/config/mkinstalldirs \
-	$(top_srcdir)/config/depcomp
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -97,6 +113,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = config.h
 CONFIG_CLEAN_FILES =
@@ -114,13 +131,14 @@ am_libcdo_la_OBJECTS = libcdo_la-argument.lo libcdo_la-array.lo \
 	libcdo_la-afterburnerlib.lo libcdo_la-constants.lo \
 	libcdo_la-color.lo libcdo_la-commandline.lo \
 	libcdo_la-convert_units.lo libcdo_la-datetime.lo \
-	libcdo_la-ecacore.lo libcdo_la-ecautil.lo \
-	libcdo_la-exception.lo libcdo_la-expr.lo libcdo_la-expr_fun.lo \
-	libcdo_la-expr_lex.lo libcdo_la-expr_yacc.lo \
-	libcdo_la-features.lo libcdo_la-field.lo libcdo_la-field2.lo \
-	libcdo_la-fieldc.lo libcdo_la-fieldmem.lo \
-	libcdo_la-fieldmer.lo libcdo_la-fieldzon.lo \
-	libcdo_la-gradsdeslib.lo libcdo_la-grid.lo \
+	libcdo_la-cdoDebugOutput.lo libcdo_la-ecacore.lo \
+	libcdo_la-ecautil.lo libcdo_la-exception.lo libcdo_la-expr.lo \
+	libcdo_la-expr_fun.lo libcdo_la-expr_lex.lo \
+	libcdo_la-expr_yacc.lo libcdo_la-features.lo \
+	libcdo_la-field.lo libcdo_la-field2.lo libcdo_la-fieldc.lo \
+	libcdo_la-fieldmem.lo libcdo_la-fieldmer.lo \
+	libcdo_la-fieldzon.lo libcdo_la-getMemorySize.lo \
+	libcdo_la-getRSS.lo libcdo_la-gradsdeslib.lo libcdo_la-grid.lo \
 	libcdo_la-grid_proj.lo libcdo_la-grid_area.lo \
 	libcdo_la-grid_define.lo libcdo_la-grid_gme.lo \
 	libcdo_la-grid_rot.lo libcdo_la-grid_from_name.lo \
@@ -168,6 +186,53 @@ am__v_lt_0 = --silent
 am__v_lt_1 = 
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am__cdo_SOURCES_DIST = cdo.cc Adisit.cc Afterburner.cc Arith.cc \
+	Arithc.cc Arithdays.cc Arithlat.cc CDItest.cc CDIread.cc \
+	CDIwrite.cc Cat.cc Change.cc Change_e5slm.cc Cloudlayer.cc \
+	CMOR.cc CMOR_lite.cc CMOR_table.cc Collgrid.cc Command.cc \
+	Comp.cc Compc.cc Complextorect.cc Cond.cc Cond2.cc Condc.cc \
+	Consecstat.cc Copy.cc Deltat.cc Deltime.cc Derivepar.cc \
+	Detrend.cc Diff.cc Distgrid.cc Duplicate.cc EOFs.cc Eof3d.cc \
+	EcaIndices.cc Echam5ini.cc Enlarge.cc Enlargegrid.cc \
+	Ensstat.cc Ensstat3.cc Ensval.cc Eofcoeff.cc Eofcoeff3d.cc \
+	EstFreq.cc Exprf.cc FC.cc Filedes.cc Fillmiss.cc Filter.cc \
+	Fldrms.cc Fldstat.cc Fldstat2.cc Fourier.cc Gengrid.cc \
+	Gradsdes.cc Gridboxstat.cc Gridcell.cc Gridsearch.cc \
+	Harmonic.cc Hi.cc Histogram.cc Importamsr.cc Importbinary.cc \
+	Importcmsaf.cc Importobs.cc Info.cc Input.cc Intgrid.cc \
+	Intgridtraj.cc Intlevel.cc Intlevel3d.cc Intntime.cc \
+	Inttime.cc Intyear.cc Invert.cc Invertlev.cc Isosurface.cc \
+	Log.cc MapReduce.cc Maskbox.cc Mastrfu.cc Math.cc Merge.cc \
+	Mergegrid.cc Mergetime.cc Merstat.cc Monarith.cc Mrotuv.cc \
+	Mrotuvb.cc NCL_wind.cc Ninfo.cc Nmldump.cc Output.cc \
+	Outputgmt.cc Pack.cc Pardup.cc Pinfo.cc Pressure.cc Regres.cc \
+	Remap.cc Remapeta.cc Replace.cc Replacevalues.cc Rhopot.cc \
+	Rotuv.cc Runpctl.cc Runstat.cc Samplegrid.cc Samplegridicon.cc \
+	Seascount.cc Seaspctl.cc Seasstat.cc Selbox.cc Selgridcell.cc \
+	Select.cc Selmulti.cc Seloperator.cc Selrec.cc Seltime.cc \
+	Selvar.cc Set.cc Setattribute.cc Setbox.cc Setgatt.cc \
+	Setgrid.cc Sethalo.cc Setmiss.cc Setpartab.cc Setrcaname.cc \
+	Settime.cc Setzaxis.cc Shiftxy.cc Showinfo.cc Showattribute.h \
+	Showattribute.cc Sinfo.cc Smooth.cc Sort.cc Sorttimestamp.cc \
+	Specinfo.cc Spectral.cc Spectrum.cc Split.cc Splitrec.cc \
+	Splitsel.cc Splittime.cc Splityear.cc Subtrend.cc Tee.cc \
+	Templates.cc Test.cc Tests.cc Timcount.cc Timcumsum.cc \
+	Timpctl.cc Timselpctl.cc Timselstat.cc Timsort.cc Timstat.cc \
+	Timstat2.cc Timstat3.cc Tinfo.cc Tocomplex.cc Transpose.cc \
+	Trend.cc Trms.cc Tstepcount.cc Vargen.cc Varrms.cc \
+	Vertintml.cc Vertintap.cc Vertstat.cc Vertcum.cc Vertwind.cc \
+	Verifygrid.cc Wct.cc Wind.cc WindTrans.cc Writegrid.cc \
+	Writerandom.cc XTimstat.cc YAR.cc Yearmonstat.cc Ydayarith.cc \
+	Ydaypctl.cc Ydaystat.cc Ydrunpctl.cc Ydrunstat.cc \
+	Yhourarith.cc Yhourstat.cc Ymonarith.cc Ymonpctl.cc \
+	Ymonstat.cc Yseaspctl.cc Yseasstat.cc Zonstat.cc cdo.h \
+	nearpt3c.h nearpt3x.h nearpt3c.cc cellsearchorder.h Magplot.cc \
+	Magvector.cc Maggraph.cc template_parser.h template_parser.cc \
+	results_template_parser.h results_template_parser.cc \
+	magics_template_parser.h magics_template_parser.cc \
+	StringUtilities.h StringUtilities.cc CdoMagicsMapper.h \
+	CdoMagicsMapper.cc
+ at ENABLE_NEARPT3_TRUE@am__objects_1 = cdo-nearpt3c.$(OBJEXT)
 am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Afterburner.$(OBJEXT) cdo-Arith.$(OBJEXT) \
 	cdo-Arithc.$(OBJEXT) cdo-Arithdays.$(OBJEXT) \
@@ -210,7 +275,8 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Mastrfu.$(OBJEXT) cdo-Math.$(OBJEXT) cdo-Merge.$(OBJEXT) \
 	cdo-Mergegrid.$(OBJEXT) cdo-Mergetime.$(OBJEXT) \
 	cdo-Merstat.$(OBJEXT) cdo-Monarith.$(OBJEXT) \
-	cdo-Mrotuv.$(OBJEXT) cdo-Mrotuvb.$(OBJEXT) cdo-Ninfo.$(OBJEXT) \
+	cdo-Mrotuv.$(OBJEXT) cdo-Mrotuvb.$(OBJEXT) \
+	cdo-NCL_wind.$(OBJEXT) cdo-Ninfo.$(OBJEXT) \
 	cdo-Nmldump.$(OBJEXT) cdo-Output.$(OBJEXT) \
 	cdo-Outputgmt.$(OBJEXT) cdo-Pack.$(OBJEXT) \
 	cdo-Pardup.$(OBJEXT) cdo-Pinfo.$(OBJEXT) \
@@ -260,14 +326,15 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Yhourstat.$(OBJEXT) cdo-Ymonarith.$(OBJEXT) \
 	cdo-Ymonpctl.$(OBJEXT) cdo-Ymonstat.$(OBJEXT) \
 	cdo-Yseaspctl.$(OBJEXT) cdo-Yseasstat.$(OBJEXT) \
-	cdo-Zonstat.$(OBJEXT) cdo-Magplot.$(OBJEXT) \
+	cdo-Zonstat.$(OBJEXT) $(am__objects_1) cdo-Magplot.$(OBJEXT) \
 	cdo-Magvector.$(OBJEXT) cdo-Maggraph.$(OBJEXT) \
 	cdo-template_parser.$(OBJEXT) \
 	cdo-results_template_parser.$(OBJEXT) \
 	cdo-magics_template_parser.$(OBJEXT) \
 	cdo-StringUtilities.$(OBJEXT) cdo-CdoMagicsMapper.$(OBJEXT)
 cdo_OBJECTS = $(am_cdo_OBJECTS)
-cdo_DEPENDENCIES = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
+cdo_DEPENDENCIES = libcdo.la $(top_builddir)/libcdi/src/libcdi.la \
+	$(am__append_2)
 cdo_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
 	$(CXXFLAGS) $(cdo_LDFLAGS) $(LDFLAGS) -o $@
@@ -330,7 +397,8 @@ am__v_CXXLD_ = $(am__v_CXXLD_ at AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
 SOURCES = $(libcdo_la_SOURCES) $(cdo_SOURCES) $(cdotest_SOURCES)
-DIST_SOURCES = $(libcdo_la_SOURCES) $(cdo_SOURCES) $(cdotest_SOURCES)
+DIST_SOURCES = $(libcdo_la_SOURCES) $(am__cdo_SOURCES_DIST) \
+	$(cdotest_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -356,6 +424,9 @@ am__define_uniq_tagged_files = \
   done | $(am__uniquify_input)`
 ETAGS = etags
 CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(top_srcdir)/config/depcomp \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -398,18 +469,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -485,6 +560,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -534,20 +610,22 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 noinst_LTLIBRARIES = libcdo.la
 libcdo_la_SOURCES = argument.h argument.cc array.h array.cc cdo_int.h \
-	compare.h cdo_pthread.cc cdo_vlist.cc cdo_getopt.cc \
-	cdo_getopt.h cdo_task.cc cdo_task.h cdo_history.cc cdo_read.cc \
-	cdi_uuid.h cmortable_parser.cc after_sptrans.cc \
-	after_fctrans.cc after_dvtrans.cc after_vertint.cc \
-	after_vertint.h after_namelist.cc afterburnerlib.cc \
-	afterburner.h vct_l191.h calendar.h constants.h constants.cc \
-	color.cc color.h commandline.cc const.h convert_units.cc \
-	convert_units.h counter.h datetime.cc datetime.h dmemory.h \
-	ecacore.cc ecacore.h ecautil.cc ecautil.h error.h etopo.h \
-	temp.h mask.h exception.cc expr.cc expr.h expr_fun.cc \
-	expr_fun.h expr_lex.cc expr_yacc.cc expr_yacc.h features.cc \
-	field.cc field.h field2.cc fieldc.cc fieldmem.cc fieldmer.cc \
-	fieldzon.cc functs.h gradsdeslib.cc gradsdeslib.h grid.cc \
-	grid.h grid_proj.cc grid_proj.h grid_area.cc grid_define.cc \
+	compare.h cfortran.h libncl.h cfortran.h cf_interface.h \
+	cdo_pthread.cc cdo_vlist.cc cdo_getopt.cc cdo_getopt.h \
+	cdo_task.cc cdo_task.h cdo_history.cc cdo_read.cc cdi_uuid.h \
+	cmortable_parser.cc after_sptrans.cc after_fctrans.cc \
+	after_dvtrans.cc after_vertint.cc after_vertint.h \
+	after_namelist.cc afterburnerlib.cc afterburner.h vct_l191.h \
+	calendar.h constants.h constants.cc color.cc color.h \
+	commandline.cc const.h convert_units.cc convert_units.h \
+	counter.h datetime.cc datetime.h cdoDebugOutput.cc \
+	cdoDebugOutput.h dmemory.h ecacore.cc ecacore.h ecautil.cc \
+	ecautil.h error.h etopo.h temp.h mask.h exception.cc expr.cc \
+	expr.h expr_fun.cc expr_fun.h expr_lex.cc expr_yacc.cc \
+	expr_yacc.h features.cc field.cc field.h field2.cc fieldc.cc \
+	fieldmem.cc fieldmer.cc fieldzon.cc functs.h getMemorySize.c \
+	getRSS.c gradsdeslib.cc gradsdeslib.h grid.cc grid.h \
+	grid_proj.cc grid_proj.h grid_area.cc grid_define.cc \
 	grid_gme.cc grid_rot.cc grid_from_name.cc grid_read.cc \
 	grid_read_pingo.cc grid_print.cc gridreference.cc griddes.cc \
 	griddes.h griddes_h5.cc griddes_nc.cc hetaeta.cc hetaeta.h \
@@ -582,13 +660,6 @@ libcdo_la_SOURCES = argument.h argument.cc array.h array.cc cdo_int.h \
 	clipping/grid_cell.c clipping/grid_cell.h \
 	clipping/intersection.c clipping/utils.c clipping/utils.h
 #
-#if ENABLE_NEARPT3
-#cdo_SOURCES +=           \
-#               nearpt3x.h      \
-#               nearpt3c.h      \
-#               nearpt3c.cc     \
-#               cellsearchorder.h
-#endif
 
 #if ENABLE_MAGICS
 cdo_SOURCES = cdo.cc Adisit.cc Afterburner.cc Arith.cc Arithc.cc \
@@ -609,15 +680,15 @@ cdo_SOURCES = cdo.cc Adisit.cc Afterburner.cc Arith.cc Arithc.cc \
 	Inttime.cc Intyear.cc Invert.cc Invertlev.cc Isosurface.cc \
 	Log.cc MapReduce.cc Maskbox.cc Mastrfu.cc Math.cc Merge.cc \
 	Mergegrid.cc Mergetime.cc Merstat.cc Monarith.cc Mrotuv.cc \
-	Mrotuvb.cc Ninfo.cc Nmldump.cc Output.cc Outputgmt.cc Pack.cc \
-	Pardup.cc Pinfo.cc Pressure.cc Regres.cc Remap.cc Remapeta.cc \
-	Replace.cc Replacevalues.cc Rhopot.cc Rotuv.cc Runpctl.cc \
-	Runstat.cc Samplegrid.cc Samplegridicon.cc Seascount.cc \
-	Seaspctl.cc Seasstat.cc Selbox.cc Selgridcell.cc Select.cc \
-	Selmulti.cc Seloperator.cc Selrec.cc Seltime.cc Selvar.cc \
-	Set.cc Setattribute.cc Setbox.cc Setgatt.cc Setgrid.cc \
-	Sethalo.cc Setmiss.cc Setpartab.cc Setrcaname.cc Settime.cc \
-	Setzaxis.cc Shiftxy.cc Showinfo.cc Showattribute.h \
+	Mrotuvb.cc NCL_wind.cc Ninfo.cc Nmldump.cc Output.cc \
+	Outputgmt.cc Pack.cc Pardup.cc Pinfo.cc Pressure.cc Regres.cc \
+	Remap.cc Remapeta.cc Replace.cc Replacevalues.cc Rhopot.cc \
+	Rotuv.cc Runpctl.cc Runstat.cc Samplegrid.cc Samplegridicon.cc \
+	Seascount.cc Seaspctl.cc Seasstat.cc Selbox.cc Selgridcell.cc \
+	Select.cc Selmulti.cc Seloperator.cc Selrec.cc Seltime.cc \
+	Selvar.cc Set.cc Setattribute.cc Setbox.cc Setgatt.cc \
+	Setgrid.cc Sethalo.cc Setmiss.cc Setpartab.cc Setrcaname.cc \
+	Settime.cc Setzaxis.cc Shiftxy.cc Showinfo.cc Showattribute.h \
 	Showattribute.cc Sinfo.cc Smooth.cc Sort.cc Sorttimestamp.cc \
 	Specinfo.cc Spectral.cc Spectrum.cc Split.cc Splitrec.cc \
 	Splitsel.cc Splittime.cc Splityear.cc Subtrend.cc Tee.cc \
@@ -631,22 +702,23 @@ cdo_SOURCES = cdo.cc Adisit.cc Afterburner.cc Arith.cc Arithc.cc \
 	Ydaypctl.cc Ydaystat.cc Ydrunpctl.cc Ydrunstat.cc \
 	Yhourarith.cc Yhourstat.cc Ymonarith.cc Ymonpctl.cc \
 	Ymonstat.cc Yseaspctl.cc Yseasstat.cc Zonstat.cc cdo.h \
-	nearpt3c.h Magplot.cc Magvector.cc Maggraph.cc \
+	nearpt3c.h $(am__append_1) Magplot.cc Magvector.cc Maggraph.cc \
 	template_parser.h template_parser.cc results_template_parser.h \
 	results_template_parser.cc magics_template_parser.h \
 	magics_template_parser.cc StringUtilities.h StringUtilities.cc \
 	CdoMagicsMapper.h CdoMagicsMapper.cc
 #endif
 cdo_CPPFLAGS = -I$(top_srcdir)/libcdi/src
-cdo_LDADD = libcdo.la $(top_builddir)/libcdi/src/libcdi.la
-cdo_LDFLAGS = $(am__append_1)
+cdo_LDADD = libcdo.la $(top_builddir)/libcdi/src/libcdi.la \
+	$(am__append_2)
+cdo_LDFLAGS = $(am__append_3)
 libcdo_la_CPPFLAGS = $(cdo_CPPFLAGS)
 cdotest_SOURCES = cdo_int.h	\
 	           cdotest.cc
 
 cdotest_LDADD = $(cdo_LDADD)
 cdotest_CPPFLAGS = $(cdo_CPPFLAGS)
-cdotest_LDFLAGS = $(cdo_LDFLAGS) $(am__append_2)
+cdotest_LDFLAGS = $(cdo_LDFLAGS) $(am__append_4)
 
 #cdo-userlog.o: userlog.cc config.h
 #	$(COMPILE) -DLOGPATH=${exec_prefix}/log -c -o cdo-userlog.o `test -f 'userlog.cc' || echo '$(srcdir)/'`userlog.cc
@@ -671,7 +743,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign src/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -935,6 +1006,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Monarith.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Mrotuv.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Mrotuvb.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-NCL_wind.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Ninfo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Nmldump.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Output.Po at am__quote@
@@ -1043,6 +1115,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Zonstat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-cdo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-magics_template_parser.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-nearpt3c.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-results_template_parser.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-template_parser.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdotest-cdotest.Po at am__quote@
@@ -1054,6 +1127,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-afterburnerlib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-argument.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdoDebugOutput.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdo_getopt.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdo_history.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdo_pthread.Plo at am__quote@
@@ -1080,6 +1154,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-fieldmem.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-fieldmer.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-fieldzon.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-getMemorySize.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-getRSS.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-gradsdeslib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_area.Plo at am__quote@
@@ -1182,6 +1258,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+libcdo_la-getMemorySize.lo: getMemorySize.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-getMemorySize.lo -MD -MP -MF $(DEPDIR)/libcdo_la-getMemorySize.Tpo -c -o libcdo_la-getMemorySize.lo `test -f 'getMemorySize.c' || echo '$(srcdir)/'`getMemorySize.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-getMemorySize.Tpo $(DEPDIR)/libcdo_la-getMemorySize.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getMemorySize.c' object='libcdo_la-getMemorySize.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-getMemorySize.lo `test -f 'getMemorySize.c' || echo '$(srcdir)/'`getMemorySize.c
+
+libcdo_la-getRSS.lo: getRSS.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-getRSS.lo -MD -MP -MF $(DEPDIR)/libcdo_la-getRSS.Tpo -c -o libcdo_la-getRSS.lo `test -f 'getRSS.c' || echo '$(srcdir)/'`getRSS.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-getRSS.Tpo $(DEPDIR)/libcdo_la-getRSS.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='getRSS.c' object='libcdo_la-getRSS.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-getRSS.lo `test -f 'getRSS.c' || echo '$(srcdir)/'`getRSS.c
+
 json/libcdo_la-jsmn.lo: json/jsmn.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT json/libcdo_la-jsmn.lo -MD -MP -MF json/$(DEPDIR)/libcdo_la-jsmn.Tpo -c -o json/libcdo_la-jsmn.lo `test -f 'json/jsmn.c' || echo '$(srcdir)/'`json/jsmn.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) json/$(DEPDIR)/libcdo_la-jsmn.Tpo json/$(DEPDIR)/libcdo_la-jsmn.Plo
@@ -1395,6 +1485,13 @@ libcdo_la-datetime.lo: datetime.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcdo_la-datetime.lo `test -f 'datetime.cc' || echo '$(srcdir)/'`datetime.cc
 
+libcdo_la-cdoDebugOutput.lo: cdoDebugOutput.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcdo_la-cdoDebugOutput.lo -MD -MP -MF $(DEPDIR)/libcdo_la-cdoDebugOutput.Tpo -c -o libcdo_la-cdoDebugOutput.lo `test -f 'cdoDebugOutput.cc' || echo '$(srcdir)/'`cdoDebugOutput.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-cdoDebugOutput.Tpo $(DEPDIR)/libcdo_la-cdoDebugOutput.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='cdoDebugOutput.cc' object='libcdo_la-cdoDebugOutput.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libcdo_la-cdoDebugOutput.lo `test -f 'cdoDebugOutput.cc' || echo '$(srcdir)/'`cdoDebugOutput.cc
+
 libcdo_la-ecacore.lo: ecacore.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libcdo_la-ecacore.lo -MD -MP -MF $(DEPDIR)/libcdo_la-ecacore.Tpo -c -o libcdo_la-ecacore.lo `test -f 'ecacore.cc' || echo '$(srcdir)/'`ecacore.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-ecacore.Tpo $(DEPDIR)/libcdo_la-ecacore.Plo
@@ -3257,6 +3354,20 @@ cdo-Mrotuvb.obj: Mrotuvb.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-Mrotuvb.obj `if test -f 'Mrotuvb.cc'; then $(CYGPATH_W) 'Mrotuvb.cc'; else $(CYGPATH_W) '$(srcdir)/Mrotuvb.cc'; fi`
 
+cdo-NCL_wind.o: NCL_wind.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-NCL_wind.o -MD -MP -MF $(DEPDIR)/cdo-NCL_wind.Tpo -c -o cdo-NCL_wind.o `test -f 'NCL_wind.cc' || echo '$(srcdir)/'`NCL_wind.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-NCL_wind.Tpo $(DEPDIR)/cdo-NCL_wind.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='NCL_wind.cc' object='cdo-NCL_wind.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-NCL_wind.o `test -f 'NCL_wind.cc' || echo '$(srcdir)/'`NCL_wind.cc
+
+cdo-NCL_wind.obj: NCL_wind.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-NCL_wind.obj -MD -MP -MF $(DEPDIR)/cdo-NCL_wind.Tpo -c -o cdo-NCL_wind.obj `if test -f 'NCL_wind.cc'; then $(CYGPATH_W) 'NCL_wind.cc'; else $(CYGPATH_W) '$(srcdir)/NCL_wind.cc'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-NCL_wind.Tpo $(DEPDIR)/cdo-NCL_wind.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='NCL_wind.cc' object='cdo-NCL_wind.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-NCL_wind.obj `if test -f 'NCL_wind.cc'; then $(CYGPATH_W) 'NCL_wind.cc'; else $(CYGPATH_W) '$(srcdir)/NCL_wind.cc'; fi`
+
 cdo-Ninfo.o: Ninfo.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-Ninfo.o -MD -MP -MF $(DEPDIR)/cdo-Ninfo.Tpo -c -o cdo-Ninfo.o `test -f 'Ninfo.cc' || echo '$(srcdir)/'`Ninfo.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Ninfo.Tpo $(DEPDIR)/cdo-Ninfo.Po
@@ -4727,6 +4838,20 @@ cdo-Zonstat.obj: Zonstat.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-Zonstat.obj `if test -f 'Zonstat.cc'; then $(CYGPATH_W) 'Zonstat.cc'; else $(CYGPATH_W) '$(srcdir)/Zonstat.cc'; fi`
 
+cdo-nearpt3c.o: nearpt3c.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-nearpt3c.o -MD -MP -MF $(DEPDIR)/cdo-nearpt3c.Tpo -c -o cdo-nearpt3c.o `test -f 'nearpt3c.cc' || echo '$(srcdir)/'`nearpt3c.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-nearpt3c.Tpo $(DEPDIR)/cdo-nearpt3c.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='nearpt3c.cc' object='cdo-nearpt3c.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-nearpt3c.o `test -f 'nearpt3c.cc' || echo '$(srcdir)/'`nearpt3c.cc
+
+cdo-nearpt3c.obj: nearpt3c.cc
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-nearpt3c.obj -MD -MP -MF $(DEPDIR)/cdo-nearpt3c.Tpo -c -o cdo-nearpt3c.obj `if test -f 'nearpt3c.cc'; then $(CYGPATH_W) 'nearpt3c.cc'; else $(CYGPATH_W) '$(srcdir)/nearpt3c.cc'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-nearpt3c.Tpo $(DEPDIR)/cdo-nearpt3c.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='nearpt3c.cc' object='cdo-nearpt3c.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o cdo-nearpt3c.obj `if test -f 'nearpt3c.cc'; then $(CYGPATH_W) 'nearpt3c.cc'; else $(CYGPATH_W) '$(srcdir)/nearpt3c.cc'; fi`
+
 cdo-Magplot.o: Magplot.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT cdo-Magplot.o -MD -MP -MF $(DEPDIR)/cdo-Magplot.Tpo -c -o cdo-Magplot.o `test -f 'Magplot.cc' || echo '$(srcdir)/'`Magplot.cc
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Magplot.Tpo $(DEPDIR)/cdo-Magplot.Po
@@ -5077,6 +5202,8 @@ uninstall-am: uninstall-binPROGRAMS
 	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
 	uninstall-binPROGRAMS
 
+.PRECIOUS: Makefile
+
 #
 clean-local: clean-local-dirs
 .PHONY: clean-local-dirs
diff --git a/src/MapReduce.cc b/src/MapReduce.cc
index f40132d..cb5d339 100644
--- a/src/MapReduce.cc
+++ b/src/MapReduce.cc
@@ -38,7 +38,8 @@
  * function definition */
 void read_first_record(char *filename, double *field)
 {
-  int nmiss,varID,levelID;
+  size_t nmiss;
+  int varID,levelID;
   int streamID = streamOpenRead(filename);
   streamInqTimestep(streamID,0);
   streamInqRecord(streamID,&varID,&levelID);
@@ -72,7 +73,7 @@ void *MapReduce(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nobounds = FALSE;
   int nocoords = FALSE;
   /*double missval1, missval2; */
@@ -85,7 +86,7 @@ void *MapReduce(void *argument)
   /* check input grid type and size - this will be used for selecting relevant
    * variables from the input file*/
   int inputGridID   = cdoDefineGrid(operatorArgv()[0]);
-  int inputGridSize = gridInqSize(inputGridID);
+  size_t inputGridSize = gridInqSize(inputGridID);
   int inputGridType = gridInqType(inputGridID);
   if ( cdoDebug ) cdoPrint("MapReduce: input gridSize:%d", inputGridSize);
 
@@ -100,8 +101,8 @@ void *MapReduce(void *argument)
   int *maskIndexList = (int *) Malloc(maskSize*sizeof(int));
   for (int m = 0; m < maskSize; m++) maskIndexList[m] = -1;
 
-  int k = 0;
-  for (int i = 0; i < inputGridSize; i++)
+  size_t k = 0;
+  for (size_t i = 0; i < inputGridSize; i++)
     {
       if (!DBL_IS_EQUAL(inputMaskField[i],0.0))
         {
diff --git a/src/Maskbox.cc b/src/Maskbox.cc
index 4fc2bb5..b860d0e 100644
--- a/src/Maskbox.cc
+++ b/src/Maskbox.cc
@@ -399,7 +399,7 @@ void *Maskbox(void *argument)
 
 	  if ( vars[varID] )
 	    {
-              int nmiss;
+              size_t nmiss;
 	      pstreamReadRecord(streamID1, array, &nmiss);
 
               double missval = vlistInqVarMissval(vlistID1, varID);             
diff --git a/src/Mastrfu.cc b/src/Mastrfu.cc
index 857e0c7..063fd78 100644
--- a/src/Mastrfu.cc
+++ b/src/Mastrfu.cc
@@ -30,7 +30,7 @@
 
 
 static
-void mastrfu(int gridID, int zaxisID, double *array1, double *array2, int nmiss, double missval)
+void mastrfu(int gridID, int zaxisID, double *array1, double *array2, size_t nmiss, double missval)
 {
   int ilev, ilat, n;
   double fact =  4*atan(1.0) * 6371000 / 9.81;
@@ -109,7 +109,7 @@ void *Mastrfu(void *argument)
   int nrecs;
   int varID, levelID;
   int offset;
-  int nmiss, nmiss1;
+  size_t nmiss, nmiss1;
 
   cdoInitialize(argument);
 
diff --git a/src/Math.cc b/src/Math.cc
index 7cf9de0..c0b61c4 100644
--- a/src/Math.cc
+++ b/src/Math.cc
@@ -46,7 +46,7 @@ void *Math(void *argument)
   enum {ABS, FINT, FNINT, SQR, SQRT, EXP, LN, LOG10, SIN, COS, TAN, ASIN, ACOS, ATAN, POW, RECI};
   int nrecs;
   int varID, levelID;
-  int nmiss, nmiss2;
+  size_t nmiss, nmiss2;
   int i;
 
   cdoInitialize(argument);
diff --git a/src/Merge.cc b/src/Merge.cc
index e0fb869..51340a0 100644
--- a/src/Merge.cc
+++ b/src/Merge.cc
@@ -127,7 +127,7 @@ void *Merge(void *argument)
   int levelID, levelID2;
   int index;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Mergegrid.cc b/src/Mergegrid.cc
index 4eaf7b8..c167ca4 100644
--- a/src/Mergegrid.cc
+++ b/src/Mergegrid.cc
@@ -160,7 +160,7 @@ void *Mergegrid(void *argument)
 {
   int varID, levelID;
   int nrecs = 0;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   int index;
 
   cdoInitialize(argument);
diff --git a/src/Mergetime.cc b/src/Mergetime.cc
index f987eed..53007ce 100644
--- a/src/Mergetime.cc
+++ b/src/Mergetime.cc
@@ -185,7 +185,7 @@ void *Mergetime(void *argument)
 		}
 	      else
 		{
-                  int nmiss;
+                  size_t nmiss;
 		  pstreamReadRecord(sf[fileID].streamID, array, &nmiss);
 		  pstreamWriteRecord(streamID2, array, nmiss);
 		}
diff --git a/src/Merstat.cc b/src/Merstat.cc
index d480c91..a7fe558 100644
--- a/src/Merstat.cc
+++ b/src/Merstat.cc
@@ -44,7 +44,7 @@ void *Merstat(void *argument)
   int gridID1, gridID2 = -1, lastgrid = -1;
   int wstatus = FALSE;
   int index;
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   int varID, levelID;
   char varname[CDI_MAX_NAME];
@@ -139,7 +139,7 @@ void *Merstat(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
 	  field1.grid = vlistInqVarGrid(vlistID1, varID);
 	  if ( needWeights && field1.grid != lastgrid )
 	    {
@@ -160,7 +160,7 @@ void *Merstat(void *argument)
 	    merfun(field1, &field2, operfunc);
 
 	  pstreamDefRecord(streamID2, varID,  levelID);
-	  pstreamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
+	  pstreamWriteRecord(streamID2, field2.ptr, field2.nmiss);
 	}
 
       tsID++;
diff --git a/src/Monarith.cc b/src/Monarith.cc
index 9e3426f..a32c39f 100644
--- a/src/Monarith.cc
+++ b/src/Monarith.cc
@@ -35,7 +35,7 @@ void *Monarith(void *argument)
   int nrecs, nrecs2, nlev;
   int varID, levelID;
   int offset;
-  int nmiss;
+  size_t nmiss;
   int yearmon2 = -1;
 
   cdoInitialize(argument);
@@ -76,14 +76,14 @@ void *Monarith(void *argument)
   int nvars  = vlistNvars(vlistID2);
 
   double **vardata2  = (double **) Malloc(nvars*sizeof(double *));
-  int **varnmiss2 = (int **) Malloc(nvars*sizeof(int *));
+  size_t **varnmiss2 = (size_t **) Malloc(nvars*sizeof(size_t *));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
       gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
       nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
       vardata2[varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-      varnmiss2[varID] = (int*) Malloc(nlev*sizeof(int));
+      varnmiss2[varID] = (size_t*) Malloc(nlev*sizeof(size_t));
     }
 
   int tsID  = 0;
@@ -138,7 +138,7 @@ void *Monarith(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss   = (size_t) nmiss;
+          field1.nmiss   = nmiss;
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 
@@ -152,7 +152,7 @@ void *Monarith(void *argument)
 	  farfun(&field1, field2, operfunc);
 
 	  pstreamDefRecord(streamID3, varID, levelID);
-	  pstreamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID3, field1.ptr, field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Mrotuv.cc b/src/Mrotuv.cc
index bbb9f6a..d345b8a 100644
--- a/src/Mrotuv.cc
+++ b/src/Mrotuv.cc
@@ -194,7 +194,7 @@ void *Mrotuv(void *argument)
   int nrecs;
   int levelID;
   int varID, varid;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   int uid = -1, vid = -1;
 
   cdoInitialize(argument);
@@ -228,7 +228,7 @@ void *Mrotuv(void *argument)
 
   int gridID1 = vlistInqVarGrid(vlistID1, uid);
   int gridID2 = vlistInqVarGrid(vlistID1, vid);
-  int gridsize = gridInqSize(gridID1);
+  size_t gridsize = gridInqSize(gridID1);
   if ( gridID1 != gridID2 ) cdoAbort("Input grids differ!");
 
   if ( gridInqType(gridID1) != GRID_LONLAT      &&
@@ -241,8 +241,8 @@ void *Mrotuv(void *argument)
 
   if ( gridsize != gridInqSize(gridID1) ) cdoAbort("Internal problem: gridsize changed!");
 
-  int nlon    = gridInqXsize(gridID1);
-  int nlat    = gridInqYsize(gridID1);
+  size_t nlon    = gridInqXsize(gridID1);
+  size_t nlat    = gridInqYsize(gridID1);
 
   double *grid1x  = (double*) Malloc(gridsize*sizeof(double));
   double *grid1y  = (double*) Malloc(gridsize*sizeof(double));
@@ -251,7 +251,7 @@ void *Mrotuv(void *argument)
   double *gridvx  = (double*) Malloc(gridsize*sizeof(double));
   double *gridvy  = (double*) Malloc(gridsize*sizeof(double));
 
-  int gridsizex = (nlon+2)*nlat;
+  size_t gridsizex = (nlon+2)*nlat;
 
   gridInqXvals(gridID1, grid1x);
   gridInqYvals(gridID1, grid1y);
@@ -281,7 +281,7 @@ void *Mrotuv(void *argument)
   gridDefXvals(gridIDv, gridvx);
   gridDefYvals(gridIDv, gridvy);
 
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     {
       grid1x[i] *= DEG2RAD;
       grid1y[i] *= DEG2RAD;
@@ -349,7 +349,7 @@ void *Mrotuv(void *argument)
 	  /* remove missing values */
 	  if ( nmiss1 || nmiss2 )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		{
 		  if ( DBL_IS_EQUAL(urfield[levelID][i], missval1) ) urfield[levelID][i] = 0;
 		  if ( DBL_IS_EQUAL(vrfield[levelID][i], missval2) ) vrfield[levelID][i] = 0;
@@ -361,15 +361,15 @@ void *Mrotuv(void *argument)
 	  rotate_uv(urfield[levelID], vrfield[levelID], nlon, nlat, grid1x, grid1y, ufield, vfield);
 
 	  /* load to a help field */
-	  for ( int j = 0; j < nlat; j++ )
-	    for ( int i = 0; i < nlon; i++ )
+	  for ( size_t j = 0; j < nlat; j++ )
+	    for ( size_t i = 0; i < nlon; i++ )
 	      {
 		uhelp[IX2D(j,i+1,nlon+2)] = ufield[IX2D(j,i,nlon)];
 		vhelp[IX2D(j,i+1,nlon+2)] = vfield[IX2D(j,i,nlon)];
 	      }
 
 	  /* make help field cyclic */
-	  for ( int j = 0; j < nlat; j++ )
+	  for ( size_t j = 0; j < nlat; j++ )
 	    {
 	      uhelp[IX2D(j,0,nlon+2)]      = uhelp[IX2D(j,nlon,nlon+2)];
 	      uhelp[IX2D(j,nlon+1,nlon+2)] = uhelp[IX2D(j,1,nlon+2)];
@@ -378,19 +378,19 @@ void *Mrotuv(void *argument)
 	    }
 
 	  /* interpolate on u/v points */
-	  for ( int j = 0; j < nlat; j++ )
-	    for ( int i = 0; i < nlon; i++ )
+	  for ( size_t j = 0; j < nlat; j++ )
+	    for ( size_t i = 0; i < nlon; i++ )
 	      {
 		ufield[IX2D(j,i,nlon)] = (uhelp[IX2D(j,i+1,nlon+2)]+uhelp[IX2D(j,i+2,nlon+2)])*0.5;
 	      }
 
-	  for ( int j = 0; j < nlat-1; j++ )
-	    for ( int i = 0; i < nlon; i++ )
+	  for ( size_t j = 0; j < nlat-1; j++ )
+	    for ( size_t i = 0; i < nlon; i++ )
 	      {
 		vfield[IX2D(j,i,nlon)] = (vhelp[IX2D(j,i+1,nlon+2)]+vhelp[IX2D(j+1,i+1,nlon+2)])*0.5;
 	      }
 
-	  for ( int i = 0; i < nlon; i++ )
+	  for ( size_t i = 0; i < nlon; i++ )
 	    {
 	      vfield[IX2D(nlat-1,i,nlon)] = vhelp[IX2D(nlat-1,i+1,nlon+2)];
 	    }
diff --git a/src/Mrotuvb.cc b/src/Mrotuvb.cc
index 8fdd986..6c5b8ad 100644
--- a/src/Mrotuvb.cc
+++ b/src/Mrotuvb.cc
@@ -151,26 +151,26 @@ void rotate_uv2(double *u_i, double *v_j, int ix, int iy,
 
 
 static
-void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y, 
+void uv_to_p_grid(size_t nlon, size_t nlat, double *grid1x, double *grid1y, 
 		  double *grid2x, double *grid2y, double *grid3x, double *grid3y)
 {
   double gx, gy;
   double gx2, gy2;
 
-  int gridsizex = (nlon+2)*nlat;
+  size_t gridsizex = (nlon+2)*nlat;
   double *gxhelp = (double*) Malloc(gridsizex*sizeof(double));
   double *gyhelp = (double*) Malloc(gridsizex*sizeof(double));
 
   /* load to a help field */
-  for ( int j = 0; j < nlat; j++ )
-    for ( int i = 0; i < nlon; i++ )
+  for ( size_t j = 0; j < nlat; j++ )
+    for ( size_t i = 0; i < nlon; i++ )
       {
 	gxhelp[IX2D(j,i+1,nlon+2)] = grid1x[IX2D(j,i,nlon)];
 	gyhelp[IX2D(j,i+1,nlon+2)] = grid1y[IX2D(j,i,nlon)];
       }
 
   /* make help field cyclic */
-  for ( int j = 0; j < nlat; j++ )
+  for ( size_t j = 0; j < nlat; j++ )
     {
       gxhelp[IX2D(j,0,nlon+2)]      = gxhelp[IX2D(j,nlon,nlon+2)];
       gxhelp[IX2D(j,nlon+1,nlon+2)] = gxhelp[IX2D(j,1,nlon+2)];
@@ -179,8 +179,8 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
     }
 
   /* interpolate u to scalar points */
-  for ( int j = 0; j < nlat; j++ )
-    for ( int i = 0; i < nlon; i++ )
+  for ( size_t j = 0; j < nlat; j++ )
+    for ( size_t i = 0; i < nlon; i++ )
       {
 	grid3x[IX2D(j,i,nlon)] = (gxhelp[IX2D(j,i,nlon+2)]+gxhelp[IX2D(j,i+1,nlon+2)])*0.5;
 	if ( (gxhelp[IX2D(j,i,nlon+2)] > 340 && gxhelp[IX2D(j,i+1,nlon+2)] <  20) ||
@@ -196,15 +196,15 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
       }
 
   /* load to a help field */
-  for ( int j = 0; j < nlat; j++ )
-    for ( int i = 0; i < nlon; i++ )
+  for ( size_t j = 0; j < nlat; j++ )
+    for ( size_t i = 0; i < nlon; i++ )
       {
 	gxhelp[IX2D(j,i+1,nlon+2)] = grid2x[IX2D(j,i,nlon)];
 	gyhelp[IX2D(j,i+1,nlon+2)] = grid2y[IX2D(j,i,nlon)];
       }
 
   /* make help field cyclic */
-  for ( int j = 0; j < nlat; j++ )
+  for ( size_t j = 0; j < nlat; j++ )
     {
       gxhelp[IX2D(j,0,nlon+2)]      = gxhelp[IX2D(j,nlon,nlon+2)];
       gxhelp[IX2D(j,nlon+1,nlon+2)] = gxhelp[IX2D(j,1,nlon+2)];
@@ -213,8 +213,8 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
     }
 
   /* interpolate v to scalar points */
-  for ( int j = 1; j < nlat-1; j++ )
-    for ( int i = 0; i < nlon; i++ )
+  for ( size_t j = 1; j < nlat-1; j++ )
+    for ( size_t i = 0; i < nlon; i++ )
       {
 	gx = (gxhelp[IX2D(j,i+1,nlon+2)]+gxhelp[IX2D(j-1,i+1,nlon+2)])*0.5;
 	if ( (gxhelp[IX2D(j,i+1,nlon+2)] > 340 && gxhelp[IX2D(j-1,i+1,nlon+2)] <  20) ||
@@ -258,7 +258,7 @@ void *Mrotuvb(void *argument)
   int nrecs, nrecs2;
   int levelID;
   int varID1, varID2;
-  int nmiss1, nmiss2;
+  size_t nmiss1, nmiss2;
   bool gpint = true;
 
   cdoInitialize(argument);
@@ -279,9 +279,9 @@ void *Mrotuvb(void *argument)
 
   int gridID1 = vlistGrid(vlistID1, 0);
   int gridID2 = vlistGrid(vlistID2, 0);
-  int gridsize = gridInqSize(gridID1);
-  if ( gpint == TRUE  && gridID1 == gridID2 ) cdoAbort("Input grids are the same, use parameter >noint< to disable interpolation!");
-  if ( gpint == FALSE && gridID1 != gridID2 ) cdoAbort("Input grids are not the same!");
+  size_t gridsize = gridInqSize(gridID1);
+  if ( gpint == true  && gridID1 == gridID2 ) cdoAbort("Input grids are the same, use parameter >noint< to disable interpolation!");
+  if ( gpint == false && gridID1 != gridID2 ) cdoAbort("Input grids are not the same!");
   if ( gridsize != gridInqSize(gridID2) ) cdoAbort("Grids have different size!");
 
   if ( gridInqType(gridID1) != GRID_LONLAT      &&
@@ -299,8 +299,8 @@ void *Mrotuvb(void *argument)
 
   if ( gridsize != gridInqSize(gridID2) ) cdoAbort("Internal problem: gridsize changed!");
 
-  int nlon    = gridInqXsize(gridID1);
-  int nlat    = gridInqYsize(gridID1);
+  size_t nlon = gridInqXsize(gridID1);
+  size_t nlat = gridInqYsize(gridID1);
 
   double *grid1x = (double*) Malloc(gridsize*sizeof(double));
   double *grid1y = (double*) Malloc(gridsize*sizeof(double));
@@ -355,7 +355,7 @@ void *Mrotuvb(void *argument)
   gridDefXvals(gridID3, grid3x);
   gridDefYvals(gridID3, grid3y);
 
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     {
       grid3x[i] *= DEG2RAD;
       grid3y[i] *= DEG2RAD;
@@ -393,7 +393,7 @@ void *Mrotuvb(void *argument)
   double *uhelp = NULL, *vhelp = NULL;
   if ( gpint )
     {
-      int gridsizex = (nlon+2)*nlat;
+      size_t gridsizex = (nlon+2)*nlat;
       uhelp   = (double*) Malloc(gridsizex*sizeof(double));
       vhelp   = (double*) Malloc(gridsizex*sizeof(double));
     }
@@ -420,7 +420,7 @@ void *Mrotuvb(void *argument)
 	  /* remove missing values */
 	  if ( nmiss1 || nmiss2 )
 	    {
-	      for ( int i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		{
 		  if ( DBL_IS_EQUAL(ufield[i], missval1) ) ufield[i] = 0;
 		  if ( DBL_IS_EQUAL(vfield[i], missval2) ) vfield[i] = 0;
@@ -430,15 +430,15 @@ void *Mrotuvb(void *argument)
 	  if ( gpint )
 	    {
 	      /* load to a help field */
-	      for ( int j = 0; j < nlat; j++ )
-		for ( int i = 0; i < nlon; i++ )
+	      for ( size_t j = 0; j < nlat; j++ )
+		for ( size_t i = 0; i < nlon; i++ )
 		  {
 		    uhelp[IX2D(j,i+1,nlon+2)] = ufield[IX2D(j,i,nlon)];
 		    vhelp[IX2D(j,i+1,nlon+2)] = vfield[IX2D(j,i,nlon)];
 		  }
 
 	      /* make help field cyclic */
-	      for ( int j = 0; j < nlat; j++ )
+	      for ( size_t j = 0; j < nlat; j++ )
 		{
 		  uhelp[IX2D(j,0,nlon+2)]      = uhelp[IX2D(j,nlon,nlon+2)];
 		  uhelp[IX2D(j,nlon+1,nlon+2)] = uhelp[IX2D(j,1,nlon+2)];
@@ -447,15 +447,15 @@ void *Mrotuvb(void *argument)
 		}
 
 	      /* interpolate on pressure points */
-	      for ( int j = 1; j < nlat; j++ )
-		for ( int i = 0; i < nlon; i++ )
+	      for ( size_t j = 1; j < nlat; j++ )
+		for ( size_t i = 0; i < nlon; i++ )
 		  {
 		    ufield[IX2D(j,i,nlon)] = (uhelp[IX2D(j,i,nlon+2)]+uhelp[IX2D(j,i+1,nlon+2)])*0.5;
 		    vfield[IX2D(j,i,nlon)] = (vhelp[IX2D(j-1,i+1,nlon+2)]+vhelp[IX2D(j,i+1,nlon+2)])*0.5;
 		  }
 	    }
 
-	  for ( int i = 0; i < nlon; i++ )
+	  for ( size_t i = 0; i < nlon; i++ )
 	    {
 	      ufield[IX2D(0,i,nlon)] = 0;
 	      vfield[IX2D(0,i,nlon)] = 0;
diff --git a/src/NCL_wind.cc b/src/NCL_wind.cc
new file mode 100644
index 0000000..6839f00
--- /dev/null
+++ b/src/NCL_wind.cc
@@ -0,0 +1,328 @@
+/*
+  This file is part of CDO. CDO is a collection of Operators to
+  manipulate and analyse Climate model Data.
+
+  Copyright (C) 2003-2017 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  See COPYING file for copying and redistribution conditions.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; version 2 of the License.
+
+  This program 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 General Public License for more details.
+*/
+
+#include <limits.h>
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pstream.h"
+#include "libncl.h"
+
+static
+void uv2dv_cfd_W(double missval, double *u, double *v, double *lon, double *lat, size_t nlon, size_t nlat, size_t nlev, int boundOpt, double *div)
+{
+  int ierror;
+
+  // Test dimension sizes.
+  if ( (nlon > INT_MAX) || (nlat > INT_MAX) )
+    cdoAbort("nlat and/or nlon is greater than INT_MAX!");
+
+  int inlon = (int) nlon;
+  int inlat = (int) nlat;
+
+  size_t gridsize_uv = nlat * nlon;
+
+  for ( size_t k = 0; k < nlev; ++k )
+    {
+      double *tmp_u = u + k*gridsize_uv;
+      double *tmp_v = v + k*gridsize_uv;
+      double *tmp_div = div + k*gridsize_uv;
+      // Init output array.
+      memset(tmp_div, 0, gridsize_uv*sizeof(double));
+      // Call the Fortran routine.
+#ifdef HAVE_CF_INTERFACE
+      DDVFIDF(tmp_u, tmp_v, lat, lon, inlon, inlat, missval, boundOpt, tmp_div, ierror);
+#else
+      cdoAbort("Fortran support not compiled in!");
+#endif
+    }
+}
+
+static
+void uv2vr_cfd_W(double missval, double *u, double *v, double *lon, double *lat, size_t nlon, size_t nlat, size_t nlev, int boundOpt, double *vort)
+{
+  int ierror;
+
+  // Test dimension sizes.
+  if ( (nlon > INT_MAX) || (nlat > INT_MAX) )
+    cdoAbort("nlat and/or nlon is greater than INT_MAX!");
+
+  int inlon = (int) nlon;
+  int inlat = (int) nlat;
+
+  size_t gridsize_uv = nlat * nlon;
+
+  for ( size_t k = 0; k < nlev; ++k )
+    {
+      double *tmp_u = u + k*gridsize_uv;
+      double *tmp_v = v + k*gridsize_uv;
+      double *tmp_vort = vort + k*gridsize_uv;
+      // Init output array.
+      memset(tmp_vort, 0, gridsize_uv*sizeof(double));
+      // Call the Fortran routine.
+#ifdef HAVE_CF_INTERFACE
+      DVRFIDF(tmp_u, tmp_v, lat, lon, inlon, inlat, missval, boundOpt, tmp_vort, ierror);
+#else
+      cdoAbort("Fortran support not compiled in!");
+#endif
+    }
+}
+
+static
+int find_name(int vlistID, char *name)
+{
+  char varname[CDI_MAX_NAME];
+
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; ++varID )
+    {
+      vlistInqVarName(vlistID, varID, varname);
+      if ( STR_IS_EQ(name, varname) ) return varID;
+    }
+
+  return CDI_UNDEFID;
+}
+
+enum OUTMODE {OUTMODE_NEW, OUTMODE_APPEND, OUTMODE_REPLACE};
+
+// Parameter
+int outMode = OUTMODE_NEW;
+int boundOpt = -1;
+char name_u[CDI_MAX_NAME], name_v[CDI_MAX_NAME];
+
+static
+void print_parameter(void)
+{
+  cdoPrint("u=%s, v=%s, boundOpt=%d, outMode=%s", name_u, name_v, boundOpt,
+           outMode==OUTMODE_NEW?"new":outMode==OUTMODE_APPEND?"append":"replace");
+}
+
+static
+void set_parameter(void)
+{
+  strcpy(name_u, "u");
+  strcpy(name_v, "v");
+
+  int pargc = operatorArgc();
+  if ( pargc )
+    { 
+      char **pargv = operatorArgv();
+
+      list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "PARAMETER");
+      if ( kvlist_parse_cmdline(kvlist, pargc, pargv) != 0 ) cdoAbort("Parse error!");
+      if ( cdoVerbose ) kvlist_print(kvlist);
+
+      for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+        {
+          keyValues_t *kv = *(keyValues_t **)kvnode->data;
+          const char *key = kv->key;
+          if ( kv->nvalues > 1 ) cdoAbort("Too many values for parameter key >%s<!", key);
+          if ( kv->nvalues < 1 ) cdoAbort("Missing value for parameter key >%s<!", key);
+          const char *value = kv->values[0];
+          
+          if      ( STR_IS_EQ(key, "u") ) strcpy(name_u, value);
+          else if ( STR_IS_EQ(key, "v") ) strcpy(name_v, value);
+          else if ( STR_IS_EQ(key, "boundOpt") ) boundOpt = parameter2int(value);
+          else if ( STR_IS_EQ(key, "outMode") )
+            {
+              if      ( STR_IS_EQ(value, "new") ) outMode = OUTMODE_NEW;
+              else if ( STR_IS_EQ(value, "append") ) outMode = OUTMODE_APPEND;
+              else if ( STR_IS_EQ(value, "replace") ) outMode = OUTMODE_REPLACE;
+              else cdoAbort("Invalid parameter key value: outMode=%s (valid are: new/append/replace)", value);
+            }
+          else cdoAbort("Invalid parameter key >%s<!", key);
+        }          
+          
+      list_destroy(kvlist);
+    }
+
+  if ( cdoVerbose ) print_parameter();
+}
+
+
+void *NCL_wind(void *argument)
+{
+  int nrecs;
+  int varID, levelID;
+  size_t nmiss;
+
+  cdoInitialize(argument);
+
+  int UV2DV_CFD = cdoOperatorAdd("uv2dv_cfd", 0,     0, "[u, v, boundsOpt, outMode]");
+  int UV2VR_CFD = cdoOperatorAdd("uv2vr_cfd", 0,     0, "[u, v, boundsOpt, outMode]");
+
+  int operatorID = cdoOperatorID();
+
+  set_parameter();
+
+  int streamID1 = pstreamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = pstreamInqVlist(streamID1);
+  int vlistID2 = CDI_UNDEFID;
+  if ( outMode == OUTMODE_NEW )
+    vlistID2 = vlistCreate();
+  else if ( outMode == OUTMODE_APPEND )
+    vlistID2 = vlistDuplicate(vlistID1);
+  else
+    cdoAbort("outMode=%d unsupported!", outMode);
+
+  int varIDu = find_name(vlistID1, name_u);
+  int varIDv = find_name(vlistID1, name_v);
+
+  if ( varIDu == CDI_UNDEFID ) cdoAbort("%s not found!", name_u);
+  if ( varIDv == CDI_UNDEFID ) cdoAbort("%s not found!", name_v);
+
+  int gridIDu = vlistInqVarGrid(vlistID1, varIDu);
+  int gridIDv = vlistInqVarGrid(vlistID1, varIDv);
+  int gridtype = gridInqType(gridIDu);
+  size_t gridsizeuv = gridInqSize(gridIDu);
+
+  if ( !((gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN) && gridtype == gridInqType(gridIDv)) )
+    cdoAbort("u and v must be on a regular lonlat or Gaussian grid!");
+  
+  if ( !(gridsizeuv == gridInqSize(gridIDv)) )
+    cdoAbort("u and v must have the same grid size!");
+
+  if ( boundOpt == -1 ) boundOpt = gridIsCircular(gridIDu) ? 1 : 0;
+  if ( cdoVerbose ) print_parameter();
+  if ( boundOpt < 0 || boundOpt > 3 ) cdoAbort("Parameter boundOpt=%d out of bounds (0-3)!", boundOpt);
+
+  size_t nlon = gridInqXsize(gridIDu);
+  size_t nlat = gridInqYsize(gridIDu);
+
+  int zaxisIDu = vlistInqVarZaxis(vlistID1, varIDu);
+  int nlev = zaxisInqSize(zaxisIDu);
+
+  if ( nlev != zaxisInqSize(vlistInqVarZaxis(vlistID1, varIDv)) )
+    cdoAbort("u and v must have the same number of level!");
+
+
+  double missvalu = vlistInqVarMissval(vlistID1, varIDu);
+  double missvalv = vlistInqVarMissval(vlistID1, varIDv);
+
+  int timetype = vlistInqVarTimetype(vlistID1, varIDu);
+  int varIDo = vlistDefVar(vlistID2, gridIDu, zaxisIDu, timetype);
+  if ( operatorID == UV2DV_CFD )
+    {
+      vlistDefVarName(vlistID2, varIDo, "d");
+      vlistDefVarLongname(vlistID2, varIDo, "divergence");
+      vlistDefVarUnits(vlistID2, varIDo, "1/s");
+    }
+  else if ( operatorID == UV2VR_CFD )
+    {
+      vlistDefVarName(vlistID2, varIDo, "vo");
+      vlistDefVarLongname(vlistID2, varIDo, "vorticity");
+      vlistDefVarUnits(vlistID2, varIDo, "1/s");
+    }
+
+  vlistDefVarMissval(vlistID2, varIDo, missvalu);
+  
+  double *lon = (double*) Malloc(nlon*sizeof(double));
+  double *lat = (double*) Malloc(nlat*sizeof(double));
+
+  gridInqXvals(gridIDu, lon);
+  gridInqYvals(gridIDu, lat);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int streamID2 = pstreamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  pstreamDefVlist(streamID2, vlistID2);
+
+  size_t gridsizemax = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsizemax*sizeof(double));
+  double *arrayu = (double*) Malloc(nlev*gridsizeuv*sizeof(double));
+  double *arrayv = (double*) Malloc(nlev*gridsizeuv*sizeof(double));
+  double *arrayo = (double*) Malloc(nlev*gridsizeuv*sizeof(double));
+
+  int tsID = 0;
+  while ( (nrecs = pstreamInqTimestep(streamID1, tsID)) )
+    {
+      size_t nmissu = 0, nmissv = 0;
+
+      taxisCopyTimestep(taxisID2, taxisID1);
+      pstreamDefTimestep(streamID2, tsID);
+	       
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  pstreamInqRecord(streamID1, &varID, &levelID);         
+          pstreamReadRecord(streamID1, array, &nmiss);
+
+          if ( varID == varIDu || varID == varIDv )
+            {
+              if ( varID == varIDu ) { memcpy(arrayu+levelID*gridsizeuv, array, gridsizeuv*sizeof(double)); nmissu += nmiss; }
+              if ( varID == varIDv ) { memcpy(arrayv+levelID*gridsizeuv, array, gridsizeuv*sizeof(double)); nmissv += nmiss; }
+            }
+
+          if ( outMode == OUTMODE_APPEND )
+            {
+              pstreamDefRecord(streamID2, varID, levelID);
+              pstreamWriteRecord(streamID2, array, nmiss);
+            }
+        }
+
+      if ( nmissu != nmissv )
+        {
+          cdoAbort("u and v have different number of missing values!");
+          if ( nmissu > 0 && !DBL_IS_EQUAL(missvalu, missvalv) )
+            {
+              for ( levelID = 0; levelID < nlev; ++levelID )
+                {
+                  double *parray = arrayv+levelID*gridsizeuv;
+                  for ( size_t i = 0; i < gridsizeuv; ++i )
+                    if ( DBL_IS_EQUAL(parray[i], missvalv) ) parray[i] = missvalu;
+                  
+                }
+            }
+        }
+
+      if ( operatorID == UV2DV_CFD )
+        uv2dv_cfd_W(missvalu, arrayu, arrayv, lon, lat, nlon, nlat, nlev, boundOpt, arrayo);
+      else if ( operatorID == UV2VR_CFD )
+        uv2vr_cfd_W(missvalu, arrayu, arrayv, lon, lat, nlon, nlat, nlev, boundOpt, arrayo);
+
+      for ( levelID = 0; levelID < nlev; ++levelID )
+        {
+          double *parray = arrayo+levelID*gridsizeuv;
+          nmiss = 0;
+          for ( size_t i = 0; i < gridsizeuv; ++i )
+            if ( DBL_IS_EQUAL(parray[i], missvalu) ) nmiss++;
+
+          pstreamDefRecord(streamID2, varIDo, levelID);
+          pstreamWriteRecord(streamID2, parray, nmiss);
+        }
+
+      tsID++;
+    }
+
+  pstreamClose(streamID1);
+  pstreamClose(streamID2);
+
+  vlistDestroy(vlistID2);
+
+  if ( array ) Free(array);
+  if ( arrayu ) Free(arrayu);
+  if ( arrayv ) Free(arrayv);
+  if ( arrayo ) Free(arrayo);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Output.cc b/src/Output.cc
index a9844c9..439ab32 100644
--- a/src/Output.cc
+++ b/src/Output.cc
@@ -40,7 +40,7 @@ void *Output(void *argument)
   int gridID;
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int nelem = 1;
   int len;
   int index;
diff --git a/src/Outputgmt.cc b/src/Outputgmt.cc
index ffb4d60..6613076 100644
--- a/src/Outputgmt.cc
+++ b/src/Outputgmt.cc
@@ -204,7 +204,7 @@ void *Outputgmt(void *argument)
   int gridsize2 = 0;
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int ninc = 1;
   bool lzon = false, lmer = false, lhov = false;
   bool lgrid_gen_bounds = false, luse_grid_corner = false;
diff --git a/src/Pack.cc b/src/Pack.cc
index 1c69646..b0c0b6a 100644
--- a/src/Pack.cc
+++ b/src/Pack.cc
@@ -85,7 +85,7 @@ void *Pack(void *argument)
   int nrecs;
   int gridID, varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   int datatype = CDI_DATATYPE_INT16;
   dtlist_type *dtlist = dtlist_new();
diff --git a/src/Pardup.cc b/src/Pardup.cc
index ce8bce3..8fc0885 100644
--- a/src/Pardup.cc
+++ b/src/Pardup.cc
@@ -34,7 +34,7 @@ void *Pardup(void *argument)
   int varID, varID2, levelID;
   long offset;
   int nmul = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   double *single;
 
@@ -75,14 +75,14 @@ void *Pardup(void *argument)
   int gridsize = vlistGridsizeMax(vlistID1);
   double *array    = (double*) Malloc(gridsize*sizeof(double));
   double **vardata = (double **) Malloc(nvars*sizeof(double *));
-  int **varnmiss   = (int **) Malloc(nvars*sizeof(int *));
+  size_t **varnmiss = (size_t **) Malloc(nvars*sizeof(size_t *));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
       nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
       vardata[varID]  = (double*) Malloc(gridsize*nlevel*sizeof(double));
-      varnmiss[varID] = (int*) Malloc(nlevel*sizeof(int));
+      varnmiss[varID] = (size_t*) Malloc(nlevel*sizeof(size_t));
     }
 
   for ( int i = 1; i < nmul; i++ )
diff --git a/src/Pinfo.cc b/src/Pinfo.cc
index 4b402ed..fe69976 100644
--- a/src/Pinfo.cc
+++ b/src/Pinfo.cc
@@ -33,8 +33,8 @@ void *Pinfo(void *argument)
   int varID;
   int nrecs;
   int levelID;
-  int nmiss;
-  int ivals = 0, imiss = 0;
+  size_t nmiss, imiss = 0;
+  int ivals = 0;
   char varname[CDI_MAX_NAME];
   char vdatestr[32], vtimestr[32];	  
   double level;
@@ -113,7 +113,7 @@ void *Pinfo(void *argument)
 	  level = cdoZaxisInqLevel(zaxisID, levelID);
 	  fprintf(stdout, " %7g ", level);
 
-	  fprintf(stdout, "%7d %7d :", gridsize, nmiss);
+	  fprintf(stdout, "%7d %7zu :", gridsize, nmiss);
 
 	  if ( gridInqType(gridID) == GRID_SPECTRAL ||
 	       (gridsize == 1 && nmiss == 0) )
@@ -170,7 +170,7 @@ void *Pinfo(void *argument)
 		}
 
 	      if ( imiss != nmiss && nmiss > 0 )
-		fprintf(stdout, "Found %d of %d missing values!\n", imiss, nmiss);
+		fprintf(stdout, "Found %zu of %zu missing values!\n", imiss, nmiss);
 	    }
 
 	  for ( i = 0; i < gridsize; i++ ) array2[i] = array1[i];
diff --git a/src/Pressure.cc b/src/Pressure.cc
index 221e5a5..1aa0278 100644
--- a/src/Pressure.cc
+++ b/src/Pressure.cc
@@ -43,7 +43,7 @@ void *Pressure(void *argument)
   int zaxisIDp, zaxisIDh = -1;
   int nhlevf = 0, nhlevh = 0, nlevel = 0;
   int nvct = 0;
-  int nmiss;
+  size_t nmiss;
   int psID = -1, lnpsID = -1;
   char paramstr[32];
   char varname[CDI_MAX_NAME];
diff --git a/src/Regres.cc b/src/Regres.cc
index 520d2b9..5702bc5 100644
--- a/src/Regres.cc
+++ b/src/Regres.cc
@@ -33,7 +33,7 @@ void *Regres(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   double temp1, temp2;
   enum {nwork = 5};
   field_type **work[nwork];
diff --git a/src/Remap.cc b/src/Remap.cc
index c0f622e..d1dcc3f 100644
--- a/src/Remap.cc
+++ b/src/Remap.cc
@@ -117,7 +117,7 @@ int maptype2operfunc(int map_type, int submap_type, int num_neighbors, int remap
 } 
 
 static
-void print_remap_info(int operfunc, int remap_genweights, remapgrid_t *src_grid, remapgrid_t *tgt_grid, int nmiss)
+void print_remap_info(int operfunc, bool remap_genweights, remapgrid_t *src_grid, remapgrid_t *tgt_grid, size_t nmiss)
 {
   char line[256], tmpstr[256];
 
@@ -155,7 +155,7 @@ void print_remap_info(int operfunc, int remap_genweights, remapgrid_t *src_grid,
 
   if ( nmiss > 0 )
     {
-      snprintf(tmpstr, sizeof(tmpstr), ", with source mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
+      snprintf(tmpstr, sizeof(tmpstr), ", with source mask (%zu)", gridInqSize(src_grid->gridID)-nmiss);
       strcat(line, tmpstr);
     }
 
@@ -163,7 +163,7 @@ void print_remap_info(int operfunc, int remap_genweights, remapgrid_t *src_grid,
 }
 
 static
-void print_remap_warning(const char *remap_file, int operfunc, remapgrid_t *src_grid, int nmiss)
+void print_remap_warning(const char *remap_file, int operfunc, remapgrid_t *src_grid, size_t nmiss)
 {
   char line[256];
   char tmpstr[256];
@@ -196,7 +196,7 @@ void print_remap_warning(const char *remap_file, int operfunc, remapgrid_t *src_
 
   if ( nmiss > 0 )
     {
-      snprintf(tmpstr, sizeof(tmpstr), " with mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
+      snprintf(tmpstr, sizeof(tmpstr), " with mask (%zu)", gridInqSize(src_grid->gridID)-nmiss);
       strcat(line, tmpstr);
     }
 
@@ -218,7 +218,7 @@ static bool lextrapolate = false;
 int max_remaps = -1;
 int sort_mode = HEAP_SORT;
 double remap_frac_min = 0;
-int remap_genweights = TRUE;
+bool REMAP_genweights = true;
 
 static
 void get_remap_env(void)
@@ -417,19 +417,15 @@ void get_remap_env(void)
       if ( *envstr )
 	{
 	  if ( memcmp(envstr, "ON", 2) == 0 || memcmp(envstr, "on", 2) == 0 )
-	    {
-	      remap_genweights = TRUE;
-	    }
+            REMAP_genweights = true;
 	  else if ( memcmp(envstr, "OFF", 3) == 0 || memcmp(envstr, "off", 3) == 0 )
-	    {
-	      remap_genweights = FALSE;
-	    }
+            REMAP_genweights = false;
 	  else
 	    cdoWarning("Environment variable CDO_REMAP_GENWEIGHTS has wrong value!");
 
 	  if ( cdoVerbose )
 	    {
-	      if ( remap_genweights == TRUE )
+	      if ( REMAP_genweights )
 		cdoPrint("Generation of weights enabled!");
 	      else
 		cdoPrint("Generation of weights disabled!");
@@ -775,20 +771,21 @@ void sort_remap_add(remapvars_t *remapvars)
 
 void *Remap(void *argument)
 {
+  bool remap_genweights = REMAP_genweights;
+  bool need_gradiants = false;
   int streamID2 = -1;
   int nrecs;
   int varID, levelID;
   size_t gridsize, gridsize2;
   int gridID1 = -1, gridID2;
-  int nmiss1, nmiss2;
-  size_t i, j;
+  size_t nmiss1, nmiss2;
+  size_t j;
   int r = -1;
   int nremaps = 0;
   int norm_opt = NORM_OPT_NONE;
   int map_type = -1;
   int submap_type = SUBMAP_TYPE_NONE;
   int num_neighbors = 0;
-  int need_gradiants = FALSE;
   char varname[CDI_MAX_NAME];
   double missval;
   remap_t *remaps = NULL;
@@ -901,20 +898,17 @@ void *Remap(void *argument)
 	}
     }
 
-  if ( lwrite_remap || lremapxxx )
-    remap_genweights = TRUE;
+  if ( lwrite_remap || lremapxxx ) remap_genweights = true;
 
   if ( lremapxxx )
     {
-      size_t gridsize2;
-
       read_remap_scrip(remap_file, gridID1, gridID2, &map_type, &submap_type, &num_neighbors,
 		       &remap_order, &remaps[0].src_grid, &remaps[0].tgt_grid, &remaps[0].vars);
 
       if ( remaps[0].vars.links_per_value == 0 ) links_per_value(&remaps[0].vars);
             
       nremaps = 1;
-      gridsize = remaps[0].src_grid.size;
+      size_t gridsize = remaps[0].src_grid.size;
       remaps[0].gridID   = gridID1;
       remaps[0].gridsize = gridInqSize(gridID1);
 
@@ -934,7 +928,7 @@ void *Remap(void *argument)
 
       if ( gridInqType(gridID1) == GRID_GME ) gridsize = remaps[0].src_grid.size;
 
-      for ( i = 0; i < gridsize; i++ )
+      for ( size_t i = 0; i < gridsize; i++ )
         if ( remaps[0].src_grid.mask[i] == FALSE )
           remaps[0].nmiss++;
 
@@ -965,22 +959,22 @@ void *Remap(void *argument)
       get_map_type(operfunc, &map_type, &submap_type, &num_neighbors, &remap_order);
     }
 
-  if ( remap_genweights == FALSE &&
+  if ( !remap_genweights &&
        map_type != MAP_TYPE_BILINEAR && map_type != MAP_TYPE_BICUBIC &&
        map_type != MAP_TYPE_DISTWGT  && map_type != MAP_TYPE_CONSERV_YAC )
-    remap_genweights = TRUE;
+    remap_genweights = true;
 
-  remap_set_int(REMAP_GENWEIGHTS, remap_genweights);
+  remap_set_int(REMAP_GENWEIGHTS, (int)remap_genweights);
 
   if ( map_type == MAP_TYPE_CONSERV || map_type == MAP_TYPE_CONSERV_YAC ) norm_opt = get_norm_opt();
 
   size_t grid1sizemax = vlistGridsizeMax(vlistID1);
 
-  if ( map_type == MAP_TYPE_BICUBIC ) need_gradiants = TRUE;
+  if ( map_type == MAP_TYPE_BICUBIC ) need_gradiants = true;
   if ( map_type == MAP_TYPE_CONSERV && remap_order == 2 )
     {
       if ( cdoVerbose ) cdoPrint("Second order remapping");
-      need_gradiants = TRUE;
+      need_gradiants = true;
     }
   else
     remap_order = 1;
@@ -1037,6 +1031,7 @@ void *Remap(void *argument)
 	  if ( gridIsCircular(gridID1) && !lextrapolate ) remap_extrapolate = true;
 	  if ( map_type == MAP_TYPE_DISTWGT && !remap_extrapolate && gridInqSize(gridID1) > 1 && !is_global_grid(gridID1) )
 	    {
+              if ( cdoVerbose ) cdoPrint("---> Expand array!");
 	      long nx = gridInqXsize(gridID1);
 	      long ny = gridInqYsize(gridID1);
 	      size_t gridsize_new = gridsize + 4*(nx+2) + 4*(ny+2);
@@ -1045,13 +1040,6 @@ void *Remap(void *argument)
 		  grid1sizemax = gridsize_new;
 		  array1 = (double*) Realloc(array1, grid1sizemax*sizeof(double));
 		  imask  = (int*) Realloc(imask, grid1sizemax*sizeof(int));
-
-		  if ( need_gradiants )
-		    {
-		      grad1_lat    = (double*) Realloc(grad1_lat, grid1sizemax*sizeof(double));
-		      grad1_lon    = (double*) Realloc(grad1_lon, grid1sizemax*sizeof(double));
-		      grad1_latlon = (double*) Realloc(grad1_latlon, grid1sizemax*sizeof(double));
-		    }
 		}
 	      
 	      for ( long j = ny-1; j >= 0; j-- )
@@ -1064,7 +1052,7 @@ void *Remap(void *argument)
 	      nmiss1 += 4*(nx+2) + 4*(ny+2);
 	    }
 
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( size_t i = 0; i < gridsize; i++ )
             imask[i] = DBL_IS_EQUAL(array1[i], missval) ? FALSE : TRUE;
 
 	  for ( r = nremaps-1; r >= 0; r-- )
@@ -1108,9 +1096,7 @@ void *Remap(void *argument)
 		  if ( gridIsCircular(gridID1) && !lextrapolate ) remap_extrapolate = true;
 		  remaps[r].src_grid.non_global = false;
 		  if ( map_type == MAP_TYPE_DISTWGT && !remap_extrapolate && gridInqSize(gridID1) > 1 && !is_global_grid(gridID1) )
-		    {
-		      remaps[r].src_grid.non_global = true;
-		    }
+                    remaps[r].src_grid.non_global = true;
 		  /*
 		    remaps[r].src_grid.luse_cell_area = FALSE;
 		    remaps[r].tgt_grid.luse_cell_area = FALSE;
@@ -1152,7 +1138,7 @@ void *Remap(void *argument)
 	      if ( gridInqType(gridID1) == GRID_GME )
 		{
 		  j = 0;
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( size_t i = 0; i < gridsize; i++ )
 		    if ( remaps[r].src_grid.vgpm[i] ) imask[j++] = imask[i];
 		}
 
@@ -1196,7 +1182,7 @@ void *Remap(void *argument)
 	  if ( gridInqType(gridID1) == GRID_GME )
 	    {
 	      j = 0;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		if ( remaps[r].src_grid.vgpm[i] ) array1[j++] = array1[i];
 	    }
 	  
@@ -1207,7 +1193,7 @@ void *Remap(void *argument)
 	      if ( need_gradiants )
 		{
 		  if ( remaps[r].src_grid.rank != 2 && remap_order == 2 )
-		    cdoAbort("Second order remapping is not only available for unstructured grids!");
+		    cdoAbort("Second order remapping is not available for unstructured grids!");
 
 		  remap_gradients(remaps[r].src_grid, array1, grad1_lat, grad1_lon, grad1_latlon);
 		}
@@ -1243,16 +1229,16 @@ void *Remap(void *argument)
 
 	  if ( operfunc == REMAPSUM )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		printf("1 %zd %g %g %g %g\n", i, array1[i], remaps[r].src_grid.cell_frac[i], remaps[r].src_grid.cell_area[i],remaps[r].src_grid.cell_frac[i]);
 	      double array1sum = 0;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( size_t i = 0; i < gridsize; i++ )
 		array1sum += remaps[r].src_grid.cell_area[i];
 
-	      for ( i = 0; i < gridsize2; i++ )
+	      for ( size_t i = 0; i < gridsize2; i++ )
 		printf("2 %zd %g %g %g %g\n", i, array2[i], remaps[r].tgt_grid.cell_frac[i],remaps[r].tgt_grid.cell_area[i],remaps[r].tgt_grid.cell_frac[i]);
 	      double array2sum = 0;
-	      for ( i = 0; i < gridsize2; i++ )
+	      for ( size_t i = 0; i < gridsize2; i++ )
 		array2sum += remaps[r].tgt_grid.cell_area[i];
 
 	      printf("array1sum %g, array2sum %g\n", array1sum, array2sum);
@@ -1275,14 +1261,14 @@ void *Remap(void *argument)
  	      gridInqParamGME(gridID2, &nd, &ni, &ni2, &ni3);
 	      j = remaps[r].tgt_grid.size;
 
-	      for ( i = gridsize2; i > 0 ; i-- )
+	      for ( size_t i = gridsize2; i > 0 ; i-- )
 		if ( remaps[r].tgt_grid.vgpm[i-1] ) array2[i-1] = array2[--j];
 
 	      gme_grid_restore(array2, ni, nd);
 	    }
 
 	  nmiss2 = 0;
-	  for ( i = 0; i < gridsize2; i++ )
+	  for ( size_t i = 0; i < gridsize2; i++ )
 	    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss2++;
 
 	SKIPVAR:
diff --git a/src/Remapeta.cc b/src/Remapeta.cc
index 83ce4d5..1ca6bb8 100644
--- a/src/Remapeta.cc
+++ b/src/Remapeta.cc
@@ -243,7 +243,7 @@ Remapeta(void *argument)
   double *t1 = NULL, *q1 = NULL;
   double *t2 = NULL, *q2 = NULL;
   double *tscor = NULL, *pscor = NULL, *secor = NULL;
-  int nmiss, nmissout = 0;
+  size_t nmiss, nmissout = 0;
   bool ltq = false;
   bool lfis2 = false;
   int varids[MAX_VARS3D];
diff --git a/src/Replace.cc b/src/Replace.cc
index 39994c9..1785ab0 100644
--- a/src/Replace.cc
+++ b/src/Replace.cc
@@ -38,10 +38,10 @@ void *Replace(void *argument)
   int nchvars = 0;
   int idx;
   char varname1[CDI_MAX_NAME], varname2[CDI_MAX_NAME];
-  int nmiss;
+  size_t nmiss;
   int varlist1[MAX_VARS], varlist2[MAX_VARS];
   int **varlevel = NULL;
-  int **varnmiss2 = NULL;
+  size_t **varnmiss2 = NULL;
   double **vardata2 = NULL;
   double *parray;
 
@@ -102,7 +102,7 @@ void *Replace(void *argument)
   if ( nchvars )
     {
       vardata2  = (double **) Malloc(nchvars*sizeof(double *));
-      varnmiss2 = (int **) Malloc(nchvars*sizeof(int *));
+      varnmiss2 = (size_t **) Malloc(nchvars*sizeof(size_t *));
       varlevel  = (int **) Malloc(nchvars*sizeof(int *));
       for ( idx = 0; idx < nchvars; idx++ )
 	{
@@ -112,7 +112,7 @@ void *Replace(void *argument)
 	  int nlevel2  = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
 	  int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
 	  vardata2[idx]  = (double*) Malloc(nlevel2*gridsize*sizeof(double));
-	  varnmiss2[idx] = (int*) Malloc(nlevel2*sizeof(int));
+	  varnmiss2[idx] = (size_t*) Malloc(nlevel2*sizeof(size_t));
 	  varlevel[idx] = (int*) Malloc(nlevel1*sizeof(int));
 	  /*
 	  for ( levelID = 0; levelID < nlevel1; levelID++ )
diff --git a/src/Replacevalues.cc b/src/Replacevalues.cc
index 06598b5..9dfb78c 100644
--- a/src/Replacevalues.cc
+++ b/src/Replacevalues.cc
@@ -34,7 +34,7 @@ void *Replacevalues(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nvals = 0;
   lista_t *flista = lista_new(FLT_LISTA);
   double *fltarr = NULL;
diff --git a/src/Rhopot.cc b/src/Rhopot.cc
index 694e118..c771873 100644
--- a/src/Rhopot.cc
+++ b/src/Rhopot.cc
@@ -155,7 +155,7 @@ void *Rhopot(void *argument)
   int varID, levelID;
   int zaxisID;
   int offset;
-  int nmiss;
+  size_t nmiss;
   int toID = -1, saoID = -1, thoID = -1;
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
   double pin = -1;
diff --git a/src/Rotuv.cc b/src/Rotuv.cc
index c321972..5e24cfd 100644
--- a/src/Rotuv.cc
+++ b/src/Rotuv.cc
@@ -127,7 +127,7 @@ void *Rotuv(void *argument)
   int *recVarID   = (int*) Malloc(nrecs*sizeof(int));
   int *recLevelID = (int*) Malloc(nrecs*sizeof(int));
 
-  int **varnmiss    = (int **) Malloc(nvars*sizeof(int *));
+  size_t **varnmiss = (size_t **) Malloc(nvars*sizeof(size_t *));
   double **vardata  = (double **) Malloc(nvars*sizeof(double *));
 
   bool lfound[MAXARG];
@@ -164,7 +164,7 @@ void *Rotuv(void *argument)
 
       gridsize = gridInqSize(gridID);
       nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      varnmiss[varID] = (int*) Malloc(nlevel*sizeof(int));
+      varnmiss[varID] = (size_t*) Malloc(nlevel*sizeof(size_t));
       vardata[varID]  = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
diff --git a/src/Runpctl.cc b/src/Runpctl.cc
index d1418ef..6e5c888 100644
--- a/src/Runpctl.cc
+++ b/src/Runpctl.cc
@@ -33,7 +33,7 @@ void *Runpctl(void *argument)
   int timestat_date = TIMESTAT_MEAN;
   int varID;
   int levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Runstat.cc b/src/Runstat.cc
index 2f82511..6177567 100644
--- a/src/Runstat.cc
+++ b/src/Runstat.cc
@@ -40,7 +40,7 @@ void *Runstat(void *argument)
   int timestat_date = TIMESTAT_MEAN;
   int varID;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int runstat_nomiss = 0;
 
   cdoInitialize(argument);
diff --git a/src/Samplegrid.cc b/src/Samplegrid.cc
index 2a758e9..7282807 100644
--- a/src/Samplegrid.cc
+++ b/src/Samplegrid.cc
@@ -58,7 +58,7 @@ void *Samplegrid(void *argument)
   int resampleFactor;
   int subI0 = 0, subI1 = 0, subJ0 = 0, subJ1 = 0;
   int index;
-  int nmiss;
+  size_t nmiss;
   typedef struct {
     int gridSrcID, gridIDsampled;
     int *cellidx, nvals;
diff --git a/src/Samplegridicon.cc b/src/Samplegridicon.cc
index d635608..8915b9d 100644
--- a/src/Samplegridicon.cc
+++ b/src/Samplegridicon.cc
@@ -14,19 +14,19 @@ extern "C" {
 constexpr int MAX_CHILDS = 9;
 
 typedef struct {
-  int ncells;
-  int *neighbor; // neighbor cell index
-  int *parent;   // parent cell index
-  int *child;    // child cell index
+  long ncells;
+  long *neighbor; // neighbor cell index
+  long *parent;   // parent cell index
+  long *child;    // child cell index
   const char *filename;
 } cellindex_type;
 
 
 static
-void copy_data_to_index(int ncells, const double *restrict data, int *restrict cellindex)
+void copy_data_to_index(long ncells, const double *restrict data, long *restrict cellindex)
 {
-  for ( int i = 0; i < ncells; ++i )
-    cellindex[i] = (int) lround(data[i]);
+  for ( long i = 0; i < ncells; ++i )
+    cellindex[i] = lround(data[i]);
 }
 
 static
@@ -75,14 +75,14 @@ cellindex_type *read_cellindex(const char *filename)
   if ( pid == CDI_UNDEFID ) cdoAbort("parent_cell_index not found in %s!", filename);
   // if ( cid == CDI_UNDEFID ) cdoAbort("child_cell_index not found in %s!", filename);
 
-  int ncells = gridInqSize(gridID);
+  long ncells = gridInqSize(gridID);
 
   cellindex_type *cellindex = (cellindex_type*) Malloc(sizeof(cellindex_type));
   cellindex->ncells = ncells;
 
   cellindex->neighbor = NULL;
-  // cellindex->neighbor = (int*) Malloc(3*ncells*sizeof(int));
-  cellindex->parent   = (int*) Malloc(  ncells*sizeof(int));
+  // cellindex->neighbor = (long*) Malloc(3*ncells*sizeof(long));
+  cellindex->parent   = (long*) Malloc(  ncells*sizeof(long));
   cellindex->child    = NULL;
   // cellindex->child    = (cid != CDI_UNDEFID) ? (int*) Malloc(MAX_CHILDS*ncells*sizeof(int)) : NULL;
   double *data = (double *) Malloc(ncells*sizeof(double));
@@ -90,7 +90,8 @@ cellindex_type *read_cellindex(const char *filename)
   int nrecs = streamInqTimestep(streamID, 0);
   for ( int recID = 0; recID < nrecs; recID++ )
     {
-      int varID, levelID, nmiss;
+      int varID, levelID;
+      size_t nmiss;
       streamInqRecord(streamID, &varID, &levelID);
       if ( varID == pid /* || varID == nid || varID == cid */ )
         {
@@ -102,8 +103,8 @@ cellindex_type *read_cellindex(const char *filename)
     }
 
   // Fortran to C index
-  for ( int i = 0; i < ncells; ++i ) cellindex->parent[i] -= 1;
-  // for ( int i = 0; i < 3*ncells; ++i ) cellindex->neighbor[i] -= 1;
+  for ( long i = 0; i < ncells; ++i ) cellindex->parent[i] -= 1;
+  // for ( long i = 0; i < 3*ncells; ++i ) cellindex->neighbor[i] -= 1;
 
   streamClose(streamID);
 
@@ -149,11 +150,11 @@ int read_grid(const char *filename)
 * @param search the element to find a position for 
 */
 static
-int find_index(int search, int n, const int *restrict array)
+long find_index(int search, long n, const long *restrict array)
 {
-  int first = 0;
-  int last = n - 1;
-  int middle = (first+last)/2;
+  long first = 0;
+  long last = n - 1;
+  long middle = (first+last)/2;
  
   while ( first <= last )
     {
@@ -161,7 +162,7 @@ int find_index(int search, int n, const int *restrict array)
         first = middle + 1;    
       else if ( array[middle] == search )
         {
-          for ( int i = middle; i >= 0; i-- )
+          for ( long i = middle; i >= 0; i-- )
             {
               if ( array[i] == search ) middle = i;
               else break;
@@ -199,23 +200,23 @@ int cmpsinfo(const void *s1, const void *s2)
 static
 void compute_child_from_parent(cellindex_type *cellindex1, cellindex_type *cellindex2)
 {
-  int ncells1 = cellindex1->ncells;
-  int *parent1 = cellindex1->parent;
+  long ncells1 = cellindex1->ncells;
+  long *parent1 = cellindex1->parent;
 
-  int *idx1 = (int*) Malloc(ncells1*sizeof(int));
-  for ( int i = 0; i < ncells1; ++i ) idx1[i] = i;
-  for ( int i = 1; i < ncells1; ++i )
+  long *idx1 = (long*) Malloc(ncells1*sizeof(long));
+  for ( long i = 0; i < ncells1; ++i ) idx1[i] = i;
+  for ( long i = 1; i < ncells1; ++i )
     if ( parent1[i] < parent1[i-1] )
       {
         if ( cdoVerbose ) cdoPrint("Sort parent index of %s!", cellindex1->filename);
         sinfo_t *sinfo = (sinfo_t*)Malloc(ncells1*sizeof(sinfo_t));
-        for ( int j = 0; j < ncells1; ++j )
+        for ( long j = 0; j < ncells1; ++j )
           {
             sinfo[j].p = parent1[j];
             sinfo[j].i = idx1[j];
           }
         qsort(sinfo, ncells1, sizeof(sinfo_t), cmpsinfo);
-        for ( int j = 0; j < ncells1; ++j )
+        for ( long j = 0; j < ncells1; ++j )
           {
             parent1[j] = sinfo[j].p;
             idx1[j] = sinfo[j].i;
@@ -224,15 +225,15 @@ void compute_child_from_parent(cellindex_type *cellindex1, cellindex_type *celli
         break;
       }
 
-  int ncells2 = cellindex2->ncells;
-  int *child2 = (int*) Malloc(MAX_CHILDS*ncells2*sizeof(int));
+  long ncells2 = cellindex2->ncells;
+  long *child2 = (long*) Malloc(MAX_CHILDS*ncells2*sizeof(long));
   cellindex2->child = child2;
-  for ( int i = 0; i< ncells2; ++i )
+  for ( long i = 0; i< ncells2; ++i )
     {
-      for ( int k = 0; k < MAX_CHILDS; ++k ) child2[i*MAX_CHILDS+k] = -1;
-      int j = find_index(i, ncells1, parent1);
+      for ( long k = 0; k < MAX_CHILDS; ++k ) child2[i*MAX_CHILDS+k] = -1;
+      long j = find_index(i, ncells1, parent1);
       if ( j < 0 ) continue;
-      for ( int k = 0; k < MAX_CHILDS; ++k )
+      for ( long k = 0; k < MAX_CHILDS; ++k )
         {
           if ( i != parent1[j+k] ) break;
           //  child2[i*MAX_CHILDS+k] = j+k;
@@ -244,7 +245,7 @@ void compute_child_from_parent(cellindex_type *cellindex1, cellindex_type *celli
 }
 
 static
-void read_coordinates(const char *filename, int n, double *lon, double *lat, int nv, double *lon_bnds, double *lat_bnds)
+void read_coordinates(const char *filename, long n, double *lon, double *lat, int nv, double *lon_bnds, double *lat_bnds)
 {
   openLock();
   int streamID = streamOpenRead(filename);
@@ -259,7 +260,7 @@ void read_coordinates(const char *filename, int n, double *lon, double *lat, int
     {
       gridID = vlistGrid(vlistID, index);
       if ( gridInqType(gridID) == GRID_UNSTRUCTURED &&
-           gridInqSize(gridID) == n &&
+           (long)gridInqSize(gridID) == n &&
            gridInqNvertex(gridID) == 3 ) break;
     }
 
@@ -299,8 +300,8 @@ int winding_numbers_algorithm(double cell_corners[], int number_corners, double
 #define MAX_SEARCH 128 // the triangles are distorted!
 
 static
-void compute_child_from_bounds(cellindex_type *cellindex2, int ncells2, double *grid_center_lon2, double *grid_center_lat2, double *grid_corner_lon2,
-                               double *grid_corner_lat2, int ncells1, double *grid_center_lon1, double *grid_center_lat1)
+void compute_child_from_bounds(cellindex_type *cellindex2, long ncells2, double *grid_center_lon2, double *grid_center_lat2, double *grid_corner_lon2,
+                               double *grid_corner_lat2, long ncells1, double *grid_center_lon1, double *grid_center_lat1)
 {
   struct gridsearch *gs = gridsearch_create(ncells1, grid_center_lon1, grid_center_lat1);
   size_t nbr_add[MAX_SEARCH];  // source address at nearest neighbors
@@ -313,9 +314,9 @@ void compute_child_from_bounds(cellindex_type *cellindex2, int ncells2, double *
   double cell_corners_plane_projection[8];
   double center_point_plane_projection[2];
 
-  int *child2 = (int*) Malloc(MAX_CHILDS*ncells2*sizeof(int));
+  long *child2 = (long*) Malloc(MAX_CHILDS*ncells2*sizeof(long));
   cellindex2->child = child2;
-  for ( int cell_no2 = 0; cell_no2 < ncells2; ++cell_no2 )
+  for ( long cell_no2 = 0; cell_no2 < ncells2; ++cell_no2 )
     {
       for ( int k = 0; k < MAX_CHILDS; ++k ) child2[cell_no2*MAX_CHILDS+k] = -1;
 
@@ -377,7 +378,7 @@ void compute_child_from_bounds(cellindex_type *cellindex2, int ncells2, double *
       for ( int i = 0; i < MAX_SEARCH; ++i )
         {
           size_t cell_no1 = nbr_add[i];
-          if ( cell_no1 < ULONG_MAX )
+          if ( cell_no1 < SIZE_MAX )
             {
               LLtoXYZ(grid_center_lon1[cell_no1], grid_center_lat1[cell_no1], center_point_xyz);
 
@@ -401,7 +402,7 @@ void compute_child_from_bounds(cellindex_type *cellindex2, int ncells2, double *
               if ( winding_number != 0 )
                 {
                   if ( k >= MAX_CHILDS ) cdoAbort("Internal problem, limit of MAX_CHILDS reached (limit=9).");
-                  child2[cell_no2*MAX_CHILDS+k++] = (int)cell_no1;
+                  child2[cell_no2*MAX_CHILDS+k++] = (long)cell_no1;
                 }
             }
         }
@@ -412,8 +413,8 @@ void compute_child_from_bounds(cellindex_type *cellindex2, int ncells2, double *
 static
 void compute_child_from_coordinates(cellindex_type *cellindex1, cellindex_type *cellindex2)
 {
-  int ncells1 = cellindex1->ncells;
-  int ncells2 = cellindex2->ncells;
+  long ncells1 = cellindex1->ncells;
+  long ncells2 = cellindex2->ncells;
 
   double *lon1 = (double*) Malloc(ncells1*sizeof(double));
   double *lat1 = (double*) Malloc(ncells1*sizeof(double));
@@ -439,10 +440,10 @@ static
 void compute_child(cellindex_type *cellindex1, cellindex_type *cellindex2)
 {
   bool lparent = true;
-  int ncells1 = cellindex1->ncells;
-  int *parent1 = cellindex1->parent;
+  long ncells1 = cellindex1->ncells;
+  long *parent1 = cellindex1->parent;
   {
-    int i;
+    long i;
     for ( i = 0; i < ncells1; ++i ) if ( parent1[i] >= 0 ) break;
     if ( i == ncells1 ) lparent = false;
   }
@@ -457,15 +458,15 @@ void compute_child(cellindex_type *cellindex1, cellindex_type *cellindex2)
 }
 
 static
-void compute_sum(int i, int *n, double *sum, double *sumq, int kci, cellindex_type **cellindex, double *array)
+void compute_sum(long i, long *n, double *sum, double *sumq, long kci, cellindex_type **cellindex, double *array)
 {
   // printf("compute: i, kci %d %d\n", i, kci);
-  int ncells2 = cellindex[kci]->ncells;
-  if ( i < 0 || i > ncells2 ) cdoAbort("Child grid cell index %d out of bounds %d!", i, ncells2);
+  long ncells2 = cellindex[kci]->ncells;
+  if ( i < 0 || i > ncells2 ) cdoAbort("Child grid cell index %ld out of bounds %ld!", i, ncells2);
 
   for ( int k = 0; k < MAX_CHILDS; ++k )
     {
-      int index = cellindex[kci]->child[i*MAX_CHILDS+k];
+      long index = cellindex[kci]->child[i*MAX_CHILDS+k];
       if ( index == -1 ) break;
       if ( kci == 1 )
         {
@@ -478,19 +479,19 @@ void compute_sum(int i, int *n, double *sum, double *sumq, int kci, cellindex_ty
 }
 
 static
-void samplegrid(double missval, int nci, cellindex_type **cellindex, double *array1, double *array2, double *array3)
+void samplegrid(double missval, long nci, cellindex_type **cellindex, double *array1, double *array2, double *array3)
 {
   static bool lstat = true;
-  int kci = nci-1;
-  int ncells2 = cellindex[kci]->ncells;
-  int nx = 0;
+  long kci = nci-1;
+  long ncells2 = cellindex[kci]->ncells;
+  long nx = 0;
   double x = 0;
 #if defined(_OPENMP)
   //#pragma omp parallel for default(none) shared(missval, ncells2, kci, cellindex, array1, array2, array3)
 #endif
-  for ( int i = 0; i < ncells2; ++i )
+  for ( long i = 0; i < ncells2; ++i )
     {
-      int n = 0;
+      long n = 0;
       double sum = 0, sumq = 0;
       compute_sum(i, &n, &sum, &sumq, kci, cellindex, array1);
       array2[i] = n ? sum/n : missval;  // mean
@@ -524,7 +525,7 @@ void *Samplegridicon(void *argument)
     {
       cellindex[i] = read_cellindex(operatorArgv()[i]);
       cellindex[i]->filename = operatorArgv()[i];
-      if ( cdoVerbose ) cdoPrint("Found %d grid cells in %s", cellindex[i]->ncells, cellindex[i]->filename);
+      if ( cdoVerbose ) cdoPrint("Found %ld grid cells in %s", cellindex[i]->ncells, cellindex[i]->filename);
     }
 
   for ( int i = 0; i < nsamplegrids-1; ++i )
@@ -536,10 +537,10 @@ void *Samplegridicon(void *argument)
 
   int vlistID1 = pstreamInqVlist(streamID1);
 
-  int gridsize = vlistGridsizeMax(vlistID1);
-  if ( cdoVerbose ) cdoPrint("Source gridsize = %d", gridsize);
+  long gridsize = vlistGridsizeMax(vlistID1);
+  if ( cdoVerbose ) cdoPrint("Source gridsize = %zu", gridsize);
   if ( gridsize != cellindex[0]->ncells )
-    cdoAbort("Gridsize (%d) of input stream and first grid (%d) differ!", gridsize, cellindex[0]->ncells);
+    cdoAbort("Gridsize (%ls) of input stream and first grid (%ld) differ!", gridsize, cellindex[0]->ncells);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
   double *array1 = (double *) Malloc(gridsize*sizeof(double));
 
@@ -570,8 +571,8 @@ void *Samplegridicon(void *argument)
   int streamID3 = pstreamOpenWrite(cdoStreamName(2), cdoFiletype());
   pstreamDefVlist(streamID3, vlistID3);
 
-  int gridsize2 = gridInqSize(gridID2);
-  if ( cdoVerbose ) cdoPrint("Target gridsize = %d", gridsize2);
+  long gridsize2 = gridInqSize(gridID2);
+  if ( cdoVerbose ) cdoPrint("Target gridsize = %ld", gridsize2);
   if ( vlistNumber(vlistID2) != CDI_REAL ) gridsize2 *= 2;
   double *array2 = (double *) Malloc(gridsize2*sizeof(double));
   double *array3 = (double *) Malloc(gridsize2*sizeof(double));
@@ -586,7 +587,7 @@ void *Samplegridicon(void *argument)
 
       for ( int recID = 0; recID < nrecs; recID++ )
         {
-          int nmiss;
+          size_t nmiss;
           pstreamInqRecord(streamID1, &varID, &levelID);
           pstreamReadRecord(streamID1, array1, &nmiss);
 
@@ -595,14 +596,14 @@ void *Samplegridicon(void *argument)
           samplegrid(missval, nsamplegrids, cellindex.data(), array1, array2, array3);
 
           nmiss = 0;
-          for ( int i = 0; i < gridsize2; ++i )
+          for ( long i = 0; i < gridsize2; ++i )
             if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
           pstreamDefRecord(streamID2, varID, levelID);
           pstreamWriteRecord(streamID2, array2, nmiss);
 
           nmiss = 0;
-          for ( int i = 0; i < gridsize2; ++i )
+          for ( long i = 0; i < gridsize2; ++i )
             if ( DBL_IS_EQUAL(array3[i], missval) ) nmiss++;
 
           pstreamDefRecord(streamID3, varID, levelID);
diff --git a/src/Seascount.cc b/src/Seascount.cc
index c504ec0..66b0469 100644
--- a/src/Seascount.cc
+++ b/src/Seascount.cc
@@ -34,7 +34,7 @@ void *Seascount(void *argument)
   int vdate0 = 0, vtime0 = 0;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int year, month, day, seas0 = 0;
   int oldmon = 0;
 
@@ -120,7 +120,7 @@ void *Seascount(void *argument)
                 }
 
               pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t)nmiss;
+              field.nmiss   = nmiss;
               field.grid    = vars1[varID][levelID].grid;
               field.missval = vars1[varID][levelID].missval;
 
@@ -147,7 +147,7 @@ void *Seascount(void *argument)
 	  if ( otsID && vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT ) continue;
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr, (int)vars1[varID][levelID].nmiss);
+	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr, vars1[varID][levelID].nmiss);
         }
 
       if ( nrecs == 0 ) break;
diff --git a/src/Seaspctl.cc b/src/Seaspctl.cc
index 8cd136b..f9062a1 100644
--- a/src/Seaspctl.cc
+++ b/src/Seaspctl.cc
@@ -36,7 +36,7 @@ void *Seaspctl(void *argument)
   int nrecs;
   int gridID, varID, levelID;
   int year, month, day, seas0 = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
   int oldmon = 0;
   int season_start;
diff --git a/src/Seasstat.cc b/src/Seasstat.cc
index 4a7aeb0..9920807 100644
--- a/src/Seasstat.cc
+++ b/src/Seasstat.cc
@@ -45,7 +45,7 @@ void *Seasstat(void *argument)
   int nrecs;
   int varID, levelID;
   int year, month, day, seas0 = 0;
-  int nmiss;
+  size_t nmiss;
   int oldmon = 0;
   int nseason = 0;
   const char *seas_name[4];
@@ -164,7 +164,7 @@ void *Seasstat(void *argument)
 	      if ( nsets == 0 )
 		{
 		  pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-		  pvars1->nmiss = (size_t)nmiss;
+		  pvars1->nmiss = nmiss;
                   if ( lrange )
                     {
                       pvars2->nmiss = pvars1->nmiss;
@@ -184,7 +184,7 @@ void *Seasstat(void *argument)
 	      else
 		{
 		  pstreamReadRecord(streamID1, field.ptr, &nmiss);
-                  field.nmiss   = (size_t)nmiss;
+                  field.nmiss   = nmiss;
 		  field.grid    = pvars1->grid;
 		  field.missval = pvars1->missval;
 
@@ -306,7 +306,7 @@ void *Seasstat(void *argument)
           field_type *pvars1 = &vars1[varID][levelID];
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	  pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Selbox.cc b/src/Selbox.cc
index 6b001d6..e3dab01 100644
--- a/src/Selbox.cc
+++ b/src/Selbox.cc
@@ -847,7 +847,7 @@ void *Selbox(void *argument)
   int varID, levelID;
   int gridID1 = -1, gridID2;
   int index, gridtype = -1;
-  int nmiss;
+  size_t nmiss;
   double missval;
   typedef struct {
     int gridID1, gridID2;
diff --git a/src/Select.cc b/src/Select.cc
index 03cd35c..cdc555f 100644
--- a/src/Select.cc
+++ b/src/Select.cc
@@ -44,7 +44,7 @@ void write_const_vars(int streamID2, int vlistID2, int nvars, double **vardata2)
           for ( int levelID2c = 0; levelID2c < nlevel; ++levelID2c )
             {
               double *pdata = vardata2[varID2c]+gridsize*levelID2c;
-              int nmiss = 0;
+              size_t nmiss = 0;
               for ( int i = 0; i < gridsize; ++i )
                 if ( DBL_IS_EQUAL(pdata[i], missval) ) nmiss++;
 
@@ -632,7 +632,7 @@ void *Select(void *argument)
 			}
 		      else
 			{
-                          int nmiss;
+                          size_t nmiss;
 			  pstreamReadRecord(streamID1, array, &nmiss);
 			  pstreamWriteRecord(streamID2, array, nmiss);
 			}
@@ -661,7 +661,7 @@ void *Select(void *argument)
                               int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
                               vardata2[varID2] = (double*) Malloc(gridsize*nlevel*sizeof(double));
                             }
-                          int nmiss;
+                          size_t nmiss;
                           pstreamReadRecord(streamID1, vardata2[varID2]+gridsize*levelID2, &nmiss);
                         }
 		    }
diff --git a/src/Selgridcell.cc b/src/Selgridcell.cc
index 6873794..7f20c78 100644
--- a/src/Selgridcell.cc
+++ b/src/Selgridcell.cc
@@ -210,7 +210,8 @@ void *Selgridcell(void *argument)
 	       
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
-          int nmiss, varID, levelID;
+          size_t nmiss;
+          int varID, levelID;
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, array1, &nmiss);
 
diff --git a/src/Selmulti.cc b/src/Selmulti.cc
index bbaf01a..0d28f91 100644
--- a/src/Selmulti.cc
+++ b/src/Selmulti.cc
@@ -165,7 +165,7 @@ void *Selmulti(void *argument)
   int varID2, levelID2;
   int sellevel, selcode, selltype;
   bool lcopy = false;
-  int nmiss;
+  size_t nmiss;
   int simpleMath=0;  // 1:  simple array arithmetics ( *,+), 0: do nothing
   float scale = 1.0;
   float offset = 0.0; // If SCALE and/or OFFSET are defined, then the data values are scaled as SCALE*(VALUE-OFFSET).
diff --git a/src/Seloperator.cc b/src/Seloperator.cc
index 24216b5..6abd35a 100644
--- a/src/Seloperator.cc
+++ b/src/Seloperator.cc
@@ -29,7 +29,7 @@ void *Seloperator(void *argument)
   int levID, ltype = 0;
   int varID2, levelID2;
   int sellevel, selcode, selltype;
-  int gridsize, nmiss;
+  size_t gridsize, nmiss;
   double slevel = 0, level;
   double *array = NULL;
 
diff --git a/src/Seltime.cc b/src/Seltime.cc
index 7a2a08c..f75be89 100644
--- a/src/Seltime.cc
+++ b/src/Seltime.cc
@@ -173,7 +173,7 @@ void *Seltime(void *argument)
   int varID, levelID;
   int nsel = 0;
   int i;
-  int nmiss;
+  size_t nmiss;
   int ncts = 0, nts, it;
   int hour = 0, minute = 0, second = 0;
   int nts1 = 0, nts2 = 0;
diff --git a/src/Selvar.cc b/src/Selvar.cc
index 43c7d1d..9924560 100644
--- a/src/Selvar.cc
+++ b/src/Selvar.cc
@@ -53,7 +53,7 @@ void *Selvar(void *argument)
   char zaxistypename[CDI_MAX_NAME];
   char zaxisname[CDI_MAX_NAME];
   char **argnames = NULL;
-  int nmiss;
+  size_t nmiss;
   int gridnum = 0;
   lista_t *ilista = lista_new(INT_LISTA);
   lista_t *flista = lista_new(FLT_LISTA);
diff --git a/src/Set.cc b/src/Set.cc
index 80f2a31..d3f3bc7 100644
--- a/src/Set.cc
+++ b/src/Set.cc
@@ -48,7 +48,7 @@ void *Set(void *argument)
 {
   int nrecs, nvars, newval = -1, tabnum = 0;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int index, zaxisID1, zaxisID2, nzaxis, nlevs;
   int zaxistype;
   int newparam    = 0;
diff --git a/src/Setattribute.cc b/src/Setattribute.cc
index 1374d01..3373cf8 100644
--- a/src/Setattribute.cc
+++ b/src/Setattribute.cc
@@ -255,7 +255,7 @@ void *Setattribute(void *argument)
             }
           else
             {
-              int nmiss;
+              size_t nmiss;
               pstreamReadRecord(streamID1, array, &nmiss);
               pstreamWriteRecord(streamID2, array, nmiss);
             }
diff --git a/src/Setbox.cc b/src/Setbox.cc
index 6e52692..4b9ae34 100644
--- a/src/Setbox.cc
+++ b/src/Setbox.cc
@@ -64,7 +64,7 @@ void *Setbox(void *argument)
   int vlistID1, vlistID2;
   int gridID = -1;
   int index, ngrids, gridtype;
-  int nmiss;
+  size_t nmiss;
   int *vars;
   int i;
   int ndiffgrids;
diff --git a/src/Setgatt.cc b/src/Setgatt.cc
index c04fbbe..8b13d44 100644
--- a/src/Setgatt.cc
+++ b/src/Setgatt.cc
@@ -33,7 +33,7 @@ void *Setgatt(void *argument)
   int nrecs;
   int varID, levelID;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   char *attname = NULL, *attstring = NULL, *attfile = NULL;
 
   cdoInitialize(argument);
diff --git a/src/Setgrid.cc b/src/Setgrid.cc
index fbc5dc4..a7de880 100644
--- a/src/Setgrid.cc
+++ b/src/Setgrid.cc
@@ -37,7 +37,7 @@ void *Setgrid(void *argument)
   int varID, levelID;
   int gridID2 = -1;
   int gridtype = -1;
-  int nmiss;
+  size_t nmiss;
   int areasize = 0;
   int  masksize = 0;
   bool lregular = false;
diff --git a/src/Sethalo.cc b/src/Sethalo.cc
index 3f539e5..45fc14e 100644
--- a/src/Sethalo.cc
+++ b/src/Sethalo.cc
@@ -444,7 +444,7 @@ void *Sethalo(void *argument)
   int gridsize, gridsize2;
   int gridID1 = -1, gridID2;
   int index, gridtype;
-  int nmiss;
+  size_t nmiss;
   int i;
   int lhalo = 0, rhalo = 0;
   double missval;
diff --git a/src/Setmiss.cc b/src/Setmiss.cc
index fec30bb..f81d2dd 100644
--- a/src/Setmiss.cc
+++ b/src/Setmiss.cc
@@ -44,7 +44,7 @@ void *Setmiss(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int i;
   double missval, missval2 = 0;
   double rconst = 0, rmin = 0, rmax = 0;
diff --git a/src/Setpartab.cc b/src/Setpartab.cc
index d7b4d92..3eb2e2b 100644
--- a/src/Setpartab.cc
+++ b/src/Setpartab.cc
@@ -302,7 +302,7 @@ void *Setpartab(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int tableID = -1;
   int tableformat = 0;
   bool delvars = false;
diff --git a/src/Setrcaname.cc b/src/Setrcaname.cc
index 9be5e82..70a41a0 100644
--- a/src/Setrcaname.cc
+++ b/src/Setrcaname.cc
@@ -32,7 +32,7 @@ void *Setrcaname(void *argument)
   int scode, sltype, slevel;
   int zaxisID, ltype, code, nlev;
   int level;
-  int gridsize, nmiss;
+  size_t gridsize, nmiss;
   double *array = NULL;
 
   cdoInitialize(argument);
diff --git a/src/Settime.cc b/src/Settime.cc
index 2b84354..634d202 100644
--- a/src/Settime.cc
+++ b/src/Settime.cc
@@ -164,7 +164,7 @@ void *Settime(void *argument)
   int vdateb[2], vtimeb[2];
   int sdate = 0, stime = 0;
   int taxisID2 = CDI_UNDEFID;
-  int nmiss;
+  size_t nmiss;
   int gridsize;
   int tunit = TUNIT_DAY;
   int ijulinc = 0, incperiod = 1, incunit = 86400;
diff --git a/src/Setzaxis.cc b/src/Setzaxis.cc
index bc64f80..98f1d90 100644
--- a/src/Setzaxis.cc
+++ b/src/Setzaxis.cc
@@ -57,7 +57,7 @@ void *Setzaxis(void *argument)
   int varID, levelID;
   int zaxisID1, zaxisID2 = -1;
   int nzaxis, index;
-  int nmiss;
+  size_t nmiss;
   int found;
   bool lztop = false, lzbot = false;
   double ztop = 0, zbot = 0;
diff --git a/src/Shiftxy.cc b/src/Shiftxy.cc
index 91175a7..3e03b31 100644
--- a/src/Shiftxy.cc
+++ b/src/Shiftxy.cc
@@ -161,7 +161,7 @@ void *Shiftxy(void *argument)
   bool lcoord = false;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Sinfo.cc b/src/Sinfo.cc
index 0d60ce8..a0d07a9 100644
--- a/src/Sinfo.cc
+++ b/src/Sinfo.cc
@@ -213,9 +213,9 @@ void *Sinfo(void *argument)
 	  fprintf(stdout, "%3d ", vlistZaxisIndex(vlistID, zaxisID) + 1);
 
 	  /* grid info */
-	  int gridsize = gridInqSize(gridID);
+	  size_t gridsize = gridInqSize(gridID);
 	  set_text_color(stdout, RESET, GREEN);
-	  fprintf(stdout, "%9d ", gridsize);
+	  fprintf(stdout, "%9zu ", gridsize);
 	  reset_text_color(stdout);
 	  fprintf(stdout, "%3d ", vlistGridIndex(vlistID, gridID) + 1);
 
diff --git a/src/Smooth.cc b/src/Smooth.cc
index da71c1e..cd9fcd1 100644
--- a/src/Smooth.cc
+++ b/src/Smooth.cc
@@ -36,7 +36,7 @@ enum {FORM_LINEAR};
 static const char *Form[] = {"linear"};
 
 typedef struct {
-  int maxpoints;
+  size_t maxpoints;
   int form;
   double radius;
   double weight0;
@@ -58,7 +58,7 @@ double smooth_knn_compute_weights(size_t num_neighbors, const bool *restrict src
   for ( size_t n = 0; n < num_neighbors; ++n )
     {
       nbr_mask[n] = false;
-      if ( nbr_add[n] < ULONG_MAX && src_grid_mask[nbr_add[n]] )
+      if ( nbr_add[n] < SIZE_MAX && src_grid_mask[nbr_add[n]] )
         {
           nbr_dist[n] = intlin(nbr_dist[n], weight0, 0, weightR, search_radius);
           dist_tot += nbr_dist[n];
@@ -93,7 +93,7 @@ size_t smooth_knn_normalize_weights(unsigned num_neighbors, double dist_tot, str
 }
 
 static
-void smooth(int gridID, double missval, const double *restrict array1, double *restrict array2, int *nmiss, smoothpoint_t spoint)
+void smooth(int gridID, double missval, const double *restrict array1, double *restrict array2, size_t *nmiss, smoothpoint_t spoint)
 {
   *nmiss = 0;
   int gridID0 = gridID;
@@ -216,7 +216,7 @@ void smooth9_sum(size_t ij, bool *mask, double sfac, const double *restrict arra
 }
 
 static
-void smooth9(int gridID, double missval, const double *restrict array1, double *restrict array2, int *nmiss)
+void smooth9(int gridID, double missval, const double *restrict array1, double *restrict array2, size_t *nmiss)
 {
   size_t gridsize = gridInqSize(gridID);
   size_t nlon = gridInqXsize(gridID);	 
@@ -350,7 +350,7 @@ int convert_form(const char *formstr)
 }
 
 static
-void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
+void set_parameter(int *xnsmooth, smoothpoint_t *spoint)
 {
   int pargc = operatorArgc();
 
@@ -371,7 +371,7 @@ void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
           const char *value = kv->values[0];
           
           if      ( STR_IS_EQ(key, "nsmooth")   ) *xnsmooth = parameter2int(value);
-          else if ( STR_IS_EQ(key, "maxpoints") ) spoint->maxpoints = parameter2int(value);
+          else if ( STR_IS_EQ(key, "maxpoints") ) spoint->maxpoints = parameter2sizet(value);
           else if ( STR_IS_EQ(key, "weight0")   ) spoint->weight0 = parameter2double(value);
           else if ( STR_IS_EQ(key, "weightR")   ) spoint->weightR = parameter2double(value);
           else if ( STR_IS_EQ(key, "radius")    ) spoint->radius = radius_str_to_deg(value);
@@ -383,7 +383,7 @@ void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
     }
       
   if ( cdoVerbose )
-    cdoPrint("nsmooth = %d, maxpoints = %d, radius = %gdeg, form = %s, weight0 = %g, weightR = %g",
+    cdoPrint("nsmooth = %d, maxpoints = %zu, radius = %gdeg, form = %s, weight0 = %g, weightR = %g",
              *xnsmooth, spoint->maxpoints, spoint->radius, Form[spoint->form], spoint->weight0, spoint->weightR);
 }
 
@@ -392,10 +392,10 @@ void *Smooth(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int xnsmooth = 1;
   smoothpoint_t spoint;
-  spoint.maxpoints = INT_MAX;
+  spoint.maxpoints = SIZE_MAX;
   spoint.radius    = 1;
   spoint.form      = FORM_LINEAR;
   spoint.weight0   = 0.25;
@@ -410,7 +410,7 @@ void *Smooth(void *argument)
   
   int operatorID = cdoOperatorID();
 
-  if ( operatorID == SMOOTH ) smooth_set_parameter(&xnsmooth, &spoint);
+  if ( operatorID == SMOOTH ) set_parameter(&xnsmooth, &spoint);
 
   if ( spoint.radius < 0 || spoint.radius > 180 ) cdoAbort("%s=%g out of bounds (0-180 deg)!", "radius", spoint.radius);
 
diff --git a/src/Sort.cc b/src/Sort.cc
index b073ad6..257e197 100644
--- a/src/Sort.cc
+++ b/src/Sort.cc
@@ -29,8 +29,8 @@
 
 typedef struct
 {
-  int        nmiss;
   int        levelID;
+  size_t     nmiss;
   double     level;
 }
 levinfo_t;
@@ -106,7 +106,7 @@ int cmpvarlevelrev(const void *s1, const void *s2)
 }
 
 static
-void setNmiss(int varID, int levelID, int nvars, varinfo_t *varInfo, int nmiss)
+void setNmiss(int varID, int levelID, int nvars, varinfo_t *varInfo, size_t nmiss)
 {
   int vindex, lindex;
 
@@ -151,7 +151,7 @@ void *Sort(void *argument)
   int vindex, lindex;
   int nrecs, nlevs, offset;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   double *single;
   int (*cmpvarlev)(const void *, const void *) = cmpvarlevel;
 
diff --git a/src/Sorttimestamp.cc b/src/Sorttimestamp.cc
index 50e4fc6..f3f2b24 100644
--- a/src/Sorttimestamp.cc
+++ b/src/Sorttimestamp.cc
@@ -61,7 +61,7 @@ void *Sorttimestamp(void *argument)
   int tsID, lasttsID = -1;
   int nalloc = 0;
   int vlistID2 = -1, taxisID2 = -1;
-  int nmiss;
+  size_t nmiss;
   int nvars = 0, nlevel;
   int *vdate = NULL, *vtime = NULL;
   field_type ***vars = NULL;
diff --git a/src/Spectral.cc b/src/Spectral.cc
index 8d1cb23..21d2008 100644
--- a/src/Spectral.cc
+++ b/src/Spectral.cc
@@ -44,7 +44,7 @@ void *Spectral(void *argument)
   int gridIDsp = -1, gridIDgp = -1;
   int gridID1 = -1, gridID2 = -1;
   int gridID;
-  int nmiss;
+  size_t nmiss;
   int ncut = 0;
   int *wnums = NULL, *waves = NULL;
   int *vars;
diff --git a/src/Spectrum.cc b/src/Spectrum.cc
index 7103dff..b35cf91 100644
--- a/src/Spectrum.cc
+++ b/src/Spectrum.cc
@@ -169,7 +169,7 @@ void *Spectrum(void *argument)
   int gridID, varID, levelID;
   int i, k;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   int *vdate = NULL, *vtime = NULL;
   int freq;
diff --git a/src/Split.cc b/src/Split.cc
index 337c1c1..519cd7f 100644
--- a/src/Split.cc
+++ b/src/Split.cc
@@ -55,7 +55,7 @@ void *Split(void *argument)
   char filesuffix[32];
   char filename[8192];
   int nsplit = 0;
-  int nmiss;
+  size_t nmiss;
   bool swap_obase = false;
   const char *uuid_attribute = NULL;
 
diff --git a/src/Splitrec.cc b/src/Splitrec.cc
index 044a3d4..537a75e 100644
--- a/src/Splitrec.cc
+++ b/src/Splitrec.cc
@@ -35,7 +35,7 @@ void *Splitrec(void *argument)
   char filename[8192];
   const char *refname;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   double *array = NULL;
 
   cdoInitialize(argument);
diff --git a/src/Splitsel.cc b/src/Splitsel.cc
index 7b579fb..86b83bf 100644
--- a/src/Splitsel.cc
+++ b/src/Splitsel.cc
@@ -33,7 +33,7 @@ void *Splitsel(void *argument)
   int nrecs = 0;
   int varID, levelID;
   int tsID;
-  int nmiss;
+  size_t nmiss;
   int gridID;
   int nlevel;
   int i2 = 0;
diff --git a/src/Splittime.cc b/src/Splittime.cc
index 3aedb5c..6241775 100644
--- a/src/Splittime.cc
+++ b/src/Splittime.cc
@@ -62,7 +62,7 @@ void *Splittime(void *argument)
   int  streamIDs[MAX_STREAMS], tsIDs[MAX_STREAMS];
   int index = 0;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   int gridID;
   int nlevel;
   char filesuffix[32];
diff --git a/src/Splityear.cc b/src/Splityear.cc
index 47d28a2..fc9dffc 100644
--- a/src/Splityear.cc
+++ b/src/Splityear.cc
@@ -44,7 +44,7 @@ void *Splityear(void *argument)
   int gridsize;
   int ic = 0;
   int cyear[MAX_YEARS];
-  int nmiss;
+  size_t nmiss;
   int gridID;
   int nlevel;
   char filesuffix[32];
diff --git a/src/Subtrend.cc b/src/Subtrend.cc
index 748af3a..bf1f442 100644
--- a/src/Subtrend.cc
+++ b/src/Subtrend.cc
@@ -31,7 +31,7 @@
 void *Subtrend(void *argument)
 {
   int gridID, varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Tee.cc b/src/Tee.cc
index a8e9258..e55d639 100644
--- a/src/Tee.cc
+++ b/src/Tee.cc
@@ -25,7 +25,7 @@ void *Tee(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Templates.cc b/src/Templates.cc
index 632e60a..305dce2 100644
--- a/src/Templates.cc
+++ b/src/Templates.cc
@@ -25,7 +25,7 @@ void *Template1(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int gridsize, nmiss;
+  size_t gridsize, nmiss;
 
   cdoInitialize(argument);
 
@@ -93,7 +93,7 @@ void *Template2(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Test.cc b/src/Test.cc
index fdd4ddb..1885a53 100644
--- a/src/Test.cc
+++ b/src/Test.cc
@@ -69,7 +69,7 @@ void *Testdata(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Tests.cc b/src/Tests.cc
index 64bdc7d..8a7d2fa 100644
--- a/src/Tests.cc
+++ b/src/Tests.cc
@@ -26,7 +26,7 @@ void *Tests(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   double degree_of_freedom = 0, p = 0, q = 0, n = 0, d = 0;
   double missval;
 
diff --git a/src/Timcount.cc b/src/Timcount.cc
index f4f6c53..dcbfe64 100644
--- a/src/Timcount.cc
+++ b/src/Timcount.cc
@@ -38,7 +38,7 @@ void *Timcount(void *argument)
   int vdate0 = 0, vtime0 = 0;
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nwpv; // number of words per value; real:1  complex:2
 
   cdoInitialize(argument);
@@ -122,7 +122,7 @@ void *Timcount(void *argument)
 		}
 
               pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t)nmiss;
+              field.nmiss   = nmiss;
               field.grid    = vars1[varID][levelID].grid;
 	      field.missval = vars1[varID][levelID].missval;
 
@@ -149,7 +149,7 @@ void *Timcount(void *argument)
 	  if ( otsID && vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT ) continue;
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr,  (int)vars1[varID][levelID].nmiss);
+	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Timcumsum.cc b/src/Timcumsum.cc
index a426da9..5824df1 100644
--- a/src/Timcumsum.cc
+++ b/src/Timcumsum.cc
@@ -32,7 +32,7 @@ void *Timcumsum(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
@@ -74,7 +74,7 @@ void *Timcumsum(void *argument)
           if ( tsID == 0 )
             {
               pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-              // pvars1->nmiss = (size_t)nmiss;
+              // pvars1->nmiss = nmiss;
               if ( nmiss )
                 for ( int i = 0; i < gridsize; ++i )
                   if ( DBL_IS_EQUAL(pvars1->ptr[i], pvars1->missval) ) pvars1->ptr[i] = 0;
@@ -82,7 +82,7 @@ void *Timcumsum(void *argument)
           else
             {
               pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              // field.nmiss   = (size_t)nmiss;
+              // field.nmiss   = nmiss;
               field.size    = gridsize;
               field.grid    = pvars1->grid;
               field.missval = pvars1->missval;
@@ -95,7 +95,7 @@ void *Timcumsum(void *argument)
             }
           
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	  pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
         }
 
       tsID++;
diff --git a/src/Timpctl.cc b/src/Timpctl.cc
index 75139bb..f9f9a7b 100644
--- a/src/Timpctl.cc
+++ b/src/Timpctl.cc
@@ -40,7 +40,7 @@ void timpctl(int operatorID)
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int nrecs;
   int gridID, varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
   
   operatorInputArg("percentile number");
diff --git a/src/Timselpctl.cc b/src/Timselpctl.cc
index 3bc179d..00bde7d 100644
--- a/src/Timselpctl.cc
+++ b/src/Timselpctl.cc
@@ -35,7 +35,7 @@ void *Timselpctl(void *argument)
   int nrecs = 0;
   int gridID, varID, levelID;
   int tsID;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
 
   cdoInitialize(argument);
diff --git a/src/Timselstat.cc b/src/Timselstat.cc
index e75a05c..95ba0a2 100644
--- a/src/Timselstat.cc
+++ b/src/Timselstat.cc
@@ -44,7 +44,7 @@ void *Timselstat(void *argument)
   int varID, levelID;
   int tsID;
   int nsets;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
@@ -164,10 +164,10 @@ void *Timselstat(void *argument)
 	      if ( nsets == 0 )
 		{
 		  pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-		  pvars1->nmiss = (size_t)nmiss;
+		  pvars1->nmiss = nmiss;
                   if ( lrange )
                     {
-                      pvars2->nmiss = (size_t)nmiss;
+                      pvars2->nmiss = nmiss;
 		      for ( int i = 0; i < gridsize; i++ )
                         pvars2->ptr[i] = pvars1->ptr[i];
                     }
@@ -184,7 +184,7 @@ void *Timselstat(void *argument)
 	      else
 		{
 		  pstreamReadRecord(streamID1, field.ptr, &nmiss);
-                  field.nmiss   = (size_t)nmiss;
+                  field.nmiss   = nmiss;
 		  field.grid    = pvars1->grid;
 		  field.missval = pvars1->missval;
 
@@ -283,7 +283,7 @@ void *Timselstat(void *argument)
           field_type *pvars1 = &vars1[varID][levelID];
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	  pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Timsort.cc b/src/Timsort.cc
index 0a7fe15..dc082e9 100644
--- a/src/Timsort.cc
+++ b/src/Timsort.cc
@@ -50,7 +50,7 @@ void *Timsort(void *argument)
   int nrecs;
   int gridID, varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   int *vdate = NULL, *vtime = NULL;
   field_type ***vars = NULL;
diff --git a/src/Timstat.cc b/src/Timstat.cc
index 76206ad..7413470 100644
--- a/src/Timstat.cc
+++ b/src/Timstat.cc
@@ -86,7 +86,7 @@ void *Timstat(void *argument)
   int varID, levelID;
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
-  int nmiss;
+  size_t nmiss;
   bool lvfrac = false;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
diff --git a/src/Timstat2.cc b/src/Timstat2.cc
index 4dc197f..e158a86 100644
--- a/src/Timstat2.cc
+++ b/src/Timstat2.cc
@@ -106,7 +106,7 @@ void *Timstat2(void *argument)
   int vdate = 0, vtime = 0;
   int nrecs2, nlevs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Timstat3.cc b/src/Timstat3.cc
index 347b72b..47bcfea 100644
--- a/src/Timstat3.cc
+++ b/src/Timstat3.cc
@@ -42,7 +42,7 @@ void *Timstat3(void *argument)
   int nlevs;
   int is;
   int varID, levelID, gridID;
-  int nmiss;
+  size_t nmiss;
   double missval, missval1, missval2;
   double fractil_1, fractil_2, statistic;
   int ***iwork[NIWORK];
diff --git a/src/Tocomplex.cc b/src/Tocomplex.cc
index b1fab11..c8b6893 100644
--- a/src/Tocomplex.cc
+++ b/src/Tocomplex.cc
@@ -26,7 +26,7 @@ void *Tocomplex(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Transpose.cc b/src/Transpose.cc
index 15b86f7..3b1efaf 100644
--- a/src/Transpose.cc
+++ b/src/Transpose.cc
@@ -62,7 +62,7 @@ void *Transpose(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
diff --git a/src/Trend.cc b/src/Trend.cc
index 0e10ba8..9359536 100644
--- a/src/Trend.cc
+++ b/src/Trend.cc
@@ -32,7 +32,7 @@ void *Trend(void *argument)
 {
   int vdate = 0, vtime = 0;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   double temp1, temp2;
   enum {nwork = 5};
diff --git a/src/Trms.cc b/src/Trms.cc
index 319ca67..4a408a0 100644
--- a/src/Trms.cc
+++ b/src/Trms.cc
@@ -30,7 +30,8 @@
 
 void trms(field_type field1, field_type field2, double *dp, field_type *field3)
 {
-  int i, k, nlev, len, rnmiss = 0;
+  int k, nlev;
+  size_t rnmiss = 0;
   int    zaxis    = field1.zaxis;
   int    grid1    = field1.grid;
   double *array1  = field1.ptr;
@@ -42,12 +43,12 @@ void trms(field_type field1, field_type field2, double *dp, field_type *field3)
   double rsum = 0, rsumw = 0, ravg = 0, wp;
 
   nlev   = zaxisInqSize(zaxis);
-  len    = gridInqSize(grid1);
+  size_t len = gridInqSize(grid1);
   if ( len != gridInqSize(grid2) )
     cdoAbort("fields have different size!");
 
   for ( k = 0; k < nlev; k++ ) 
-    for ( i = 0; i < len; i++ ) 
+    for ( size_t i = 0; i < len; i++ ) 
       {
 	wp = w[i]*dp[k*len+i];
 	rsum  = ADDMN(rsum, MULMN(wp, MULMN( SUBMN(array2[k*len+i], array1[k*len+i]),
@@ -69,10 +70,10 @@ void *Trms(void *argument)
   int code = 0, oldcode = 0;
   int zaxisID;
   int nrecs;
-  int nmiss;
+  size_t nmiss;
   int varID, levelID;
   int pcode = 152, pvarID = -1;
-  long offset;
+  size_t offset;
   size_t vctsize = 0;
   const double *va = NULL, *vb = NULL;
   double *single;
@@ -157,7 +158,7 @@ void *Trms(void *argument)
   double **vardata1 = (double**) Malloc(nvars*sizeof(double*));
   double **vardata2 = (double**) Malloc(nvars*sizeof(double*));
 
-  int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
+  size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
   int nlevel   = vctsize/2 - 1;
   double *dp = (double*) Malloc(gridsize*nlevel*sizeof(double));
 
@@ -174,7 +175,7 @@ void *Trms(void *argument)
   field_init(&field2);
   field_init(&field3);
 
-  int lim = vlistGridsizeMax(vlistID1);
+  size_t lim = vlistGridsizeMax(vlistID1);
   field1.weight = NULL;
   if ( needWeights )
     field1.weight = (double*) Malloc(lim*sizeof(double));
@@ -211,7 +212,7 @@ void *Trms(void *argument)
 	}
 
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
-      for ( int i = 0; i < gridsize; i++ )
+      for ( size_t i = 0; i < gridsize; i++ )
 	{
 	  vardata1[pvarID][i] = exp(vardata1[pvarID][i]);
 	  vardata2[pvarID][i] = exp(vardata2[pvarID][i]);
@@ -221,7 +222,7 @@ void *Trms(void *argument)
       for ( int k = 0; k < nlevel; k++ )
 	{
 	  offset = gridsize*k;
-	  for ( int i = 0; i < gridsize; i++ )
+	  for ( size_t i = 0; i < gridsize; i++ )
 	    {
 	      double dp1 = (va[k+1] + vb[k+1]*vardata1[pvarID][i]) - (va[k] + vb[k]*vardata1[pvarID][i]);
 	      double dp2 = (va[k+1] + vb[k+1]*vardata2[pvarID][i]) - (va[k] + vb[k]*vardata2[pvarID][i]);
diff --git a/src/Tstepcount.cc b/src/Tstepcount.cc
index 1fefdbb..ddc4e87 100644
--- a/src/Tstepcount.cc
+++ b/src/Tstepcount.cc
@@ -57,7 +57,7 @@ void *Tstepcount(void *argument)
   int nrecs;
   int gridID, varID, levelID;
   int nalloc = 0;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   int vdate = 0, vtime = 0;
   double missval;
diff --git a/src/Vargen.cc b/src/Vargen.cc
index d72c0d5..73628a5 100644
--- a/src/Vargen.cc
+++ b/src/Vargen.cc
@@ -88,10 +88,10 @@ double std_atm_pressure(double height)
 }
 
 static
-void conv_generic_grid(int gridID, int gridsize, double *xvals2D, double *yvals2D)
+void conv_generic_grid(int gridID, size_t gridsize, double *xvals2D, double *yvals2D)
 {
-  int xsize = gridInqXsize(gridID);
-  int ysize = gridInqYsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
 
   assert(gridsize==xsize*ysize);
 
@@ -103,7 +103,7 @@ void conv_generic_grid(int gridID, int gridsize, double *xvals2D, double *yvals2
 
   double xmin = xcoord[0];
   double xmax = xcoord[0];
-  for ( int i = 1; i < xsize; ++i )
+  for ( size_t i = 1; i < xsize; ++i )
     {
       if ( xcoord[i] < xmin ) xmin = xcoord[i];
       if ( xcoord[i] > xmax ) xmax = xcoord[i];
@@ -111,7 +111,7 @@ void conv_generic_grid(int gridID, int gridsize, double *xvals2D, double *yvals2
 
   double ymin = ycoord[0];
   double ymax = ycoord[0];
-  for ( int i = 1; i < ysize; ++i )
+  for ( size_t i = 1; i < ysize; ++i )
     {
       if ( ycoord[i] < ymin ) ymin = ycoord[i];
       if ( ycoord[i] > ymax ) ymax = ycoord[i];
@@ -120,8 +120,8 @@ void conv_generic_grid(int gridID, int gridsize, double *xvals2D, double *yvals2
   double xrange = xmax - xmin;
   double yrange = ymax - ymin;
   
-  for ( int j = 0; j < ysize; ++j )
-    for ( int i = 0; i < xsize; ++i )
+  for ( size_t j = 0; j < ysize; ++j )
+    for ( size_t i = 0; i < xsize; ++i )
       {
         xvals2D[j*xsize+i] = xcoord[i]*M_PI/xrange; 
         yvals2D[j*xsize+i] = ycoord[j]*M_PI/yrange; 
@@ -132,13 +132,13 @@ void conv_generic_grid(int gridID, int gridsize, double *xvals2D, double *yvals2
 }
 
 static
-void remap_nn_reg2d_reg2d(int nx, int ny, const double *restrict data, int gridID, double *restrict array)
+void remap_nn_reg2d_reg2d(size_t nx, size_t ny, const double *restrict data, int gridID, double *restrict array)
 {
   if ( gridInqType(gridID) != GRID_LONLAT )
     cdoAbort("Internal error, wrong grid type!");
 
-  int nxvals = gridInqXsize(gridID);
-  int nyvals = gridInqYsize(gridID);
+  size_t nxvals = gridInqXsize(gridID);
+  size_t nyvals = gridInqYsize(gridID);
   double *xvals = (double*) Malloc(nxvals*sizeof(double));
   double *yvals = (double*) Malloc(nyvals*sizeof(double));
 
@@ -152,12 +152,12 @@ void remap_nn_reg2d_reg2d(int nx, int ny, const double *restrict data, int gridI
   gridInqYunits(gridID, units);
   grid_to_degree(units, nyvals, yvals, "grid center lat");
 
-  int ii, jj;
+  size_t ii, jj;
   double xval, yval;
-  for ( int j = 0; j < nyvals; j++ )
+  for ( size_t j = 0; j < nyvals; j++ )
     {
       yval = yvals[j];
-      for ( int i = 0; i < nxvals; i++ )
+      for ( size_t i = 0; i < nxvals; i++ )
         {
           xval = xvals[i];
           if ( xval >=  180 ) xval -= 360;
@@ -175,10 +175,10 @@ void remap_nn_reg2d_reg2d(int nx, int ny, const double *restrict data, int gridI
 }
 
 static
-void remap_nn_reg2d_nonreg2d(int nx, int ny, const double *restrict data, int gridID, double *restrict array)
+void remap_nn_reg2d_nonreg2d(size_t nx, size_t ny, const double *restrict data, int gridID, double *restrict array)
 {
   int gridID2 = gridID;
-  int gridsize = gridInqSize(gridID2);
+  size_t gridsize = gridInqSize(gridID2);
   double *xvals = (double*) Malloc(gridsize*sizeof(double));
   double *yvals = (double*) Malloc(gridsize*sizeof(double));
 
@@ -197,9 +197,9 @@ void remap_nn_reg2d_nonreg2d(int nx, int ny, const double *restrict data, int gr
   gridInqYunits(gridID2, units);
   grid_to_degree(units, gridsize, yvals, "grid center lat");
 
-  int ii, jj;
+  size_t ii, jj;
   double xval, yval;
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     {
       xval = xvals[i];
       yval = yvals[i];
@@ -219,7 +219,7 @@ void remap_nn_reg2d_nonreg2d(int nx, int ny, const double *restrict data, int gr
 }
 
 static
-void remap_nn_reg2d(int nx, int ny, const double *restrict data, int gridID, double *restrict array)
+void remap_nn_reg2d(size_t nx, size_t ny, const double *restrict data, int gridID, double *restrict array)
 {
   if ( gridInqType(gridID) == GRID_LONLAT )
     remap_nn_reg2d_reg2d(nx, ny, data, gridID, array);
@@ -239,8 +239,8 @@ void *Vargen(void *argument)
   double rconst = 0;
   double *levels = NULL;
   double lon[NLON], lat[NLAT];
-  int nlon = NLON;
-  int nlat = NLAT;
+  size_t nlon = NLON;
+  size_t nlat = NLAT;
 
   cdoInitialize(argument);
 
@@ -291,8 +291,8 @@ void *Vargen(void *argument)
       gridDefXsize(gridIDdata, nlon);
       gridDefYsize(gridIDdata, nlat);
 
-      for ( int i = 0; i < nlon; i++ ) lon[i] = -179.75 + i*0.5;
-      for ( int i = 0; i < nlat; i++ ) lat[i] = -89.75 + i*0.5;
+      for ( size_t i = 0; i < nlon; i++ ) lon[i] = -179.75 + i*0.5;
+      for ( size_t i = 0; i < nlat; i++ ) lat[i] = -89.75 + i*0.5;
 
       gridDefXvals(gridIDdata, lon);
       gridDefYvals(gridIDdata, lat);
@@ -404,8 +404,8 @@ void *Vargen(void *argument)
 
   pstreamDefVlist(streamID, vlistID);
 
-  int gridsize = gridInqSize(gridID);
-  int datasize = gridsize;
+  size_t gridsize = gridInqSize(gridID);
+  size_t datasize = gridsize;
   double *array = (double*) Malloc(gridsize*sizeof(double));
   double *data = array;
   if ( gridID != gridIDdata && gridIDdata != -1 )
@@ -444,7 +444,7 @@ void *Vargen(void *argument)
 
               if ( operatorID == RANDOM )
                 {
-                  for ( int i = 0; i < gridsize; i++ )
+                  for ( size_t i = 0; i < gridsize; i++ )
                     array[i] = ((double)rand())/((double)RAND_MAX);
                 }
               else if ( operatorID == SINCOS || operatorID == COSHILL )
@@ -476,12 +476,12 @@ void *Vargen(void *argument)
                   
 		  if ( operatorID == SINCOS )
 		    {
-		      for ( int i = 0; i < gridsize; i++ )
+		      for ( size_t i = 0; i < gridsize; i++ )
 			array[i] = cos(1.0 * xvals[i]) * sin(2.0 * yvals[i]);
 		    }
 		  else if ( operatorID == COSHILL )
 		    {		     
-		      for ( int i = 0; i < gridsize; i++ )
+		      for ( size_t i = 0; i < gridsize; i++ )
 			array[i] = 2 - cos(acos(cos(xvals[i]) * cos(yvals[i]))/1.2);
 		    }
 
@@ -490,13 +490,13 @@ void *Vargen(void *argument)
 		}
               else if ( operatorID == CONST )
                 {
-                  for ( int i = 0; i < gridsize; i++ )
+                  for ( size_t i = 0; i < gridsize; i++ )
                     array[i] = rconst;
                 }
               else if ( operatorID == TOPO )
                 {
 #if defined(ENABLE_DATA)
-                  for ( int i = 0; i < datasize; i++ )
+                  for ( size_t i = 0; i < datasize; i++ )
                     data[i] = etopo[i]/etopo_scale - etopo_offset;
 #else
                   cdoAbort("Operator support disabled!");
@@ -505,7 +505,7 @@ void *Vargen(void *argument)
               else if ( operatorID == TEMP )
                 {
 #if defined(ENABLE_DATA)
-                  for ( int i = 0; i < datasize; i++ )
+                  for ( size_t i = 0; i < datasize; i++ )
                     data[i] = temp[i]/temp_scale - temp_offset;
 #else
                   cdoAbort("Operator support disabled!");
@@ -514,7 +514,7 @@ void *Vargen(void *argument)
               else if ( operatorID == MASK )
                 {
 #if defined(ENABLE_DATA)
-                  for ( int i = 0; i < datasize; i++ )
+                  for ( size_t i = 0; i < datasize; i++ )
                     data[i] = mask[i]/mask_scale - mask_offset;
 #else
                   cdoAbort("Operator support disabled!");
diff --git a/src/Varrms.cc b/src/Varrms.cc
index 82824b4..d1a8153 100644
--- a/src/Varrms.cc
+++ b/src/Varrms.cc
@@ -35,7 +35,7 @@ void *Varrms(void *argument)
   int oldcode = 0;
   int nrecs;
   int gridsize;
-  int nmiss;
+  size_t nmiss;
   int varID, levelID;
   long offset;
   double *single;
diff --git a/src/Verifygrid.cc b/src/Verifygrid.cc
index c56142f..2caad05 100644
--- a/src/Verifygrid.cc
+++ b/src/Verifygrid.cc
@@ -157,26 +157,14 @@ void find_unit_normal(double a[3], double b[3], double c[3], double *unit_normal
 
 int find_coordinate_to_ignore(double *cell_corners_xyz)
 {
-  double corner_coordinates[3];
-  double second_corner_coordinates[3];
-  double third_corner_coordinates[3];
-
   /* Takes the first three corners/vertices of the cell and calculates the unit normal via determinants. */
       
-  corner_coordinates[0] = cell_corners_xyz[0];
-  corner_coordinates[1] = cell_corners_xyz[1];
-  corner_coordinates[2] = cell_corners_xyz[2];
-
-  second_corner_coordinates[0] = cell_corners_xyz[3 + 0];
-  second_corner_coordinates[1] = cell_corners_xyz[3 + 1];
-  second_corner_coordinates[2] = cell_corners_xyz[3 + 2];
+  double *pcorner_coordinates1 = &cell_corners_xyz[0];
+  double *pcorner_coordinates2 = &cell_corners_xyz[3];
+  double *pcorner_coordinates3 = &cell_corners_xyz[6];
 
-  third_corner_coordinates[0] = cell_corners_xyz[6 + 0];
-  third_corner_coordinates[1] = cell_corners_xyz[6 + 1];
-  third_corner_coordinates[2] = cell_corners_xyz[6 + 2];
-      
   double surface_normal_of_the_cell[3];
-  find_unit_normal(corner_coordinates, second_corner_coordinates, third_corner_coordinates, surface_normal_of_the_cell);
+  find_unit_normal(pcorner_coordinates1, pcorner_coordinates2, pcorner_coordinates3, surface_normal_of_the_cell);
 
   /* The surface normal is used to choose the coordinate to ignore. */
 
@@ -433,6 +421,12 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
   
   Free(center_point_array);
 
+  // used only actual_number_of_corners
+  int *marked_duplicate_indices = (int*) Malloc(ncorner*sizeof(int)); 
+  double *cell_corners_xyz_without_duplicates = (double*) Malloc(3*ncorner*sizeof(double));
+  double *cell_corners_xyz = (double*) Malloc(3*(ncorner+1)*sizeof(double));
+  double *cell_corners_plane_projection = (double*) Malloc(2*(ncorner+1)*sizeof(double));
+
   /* 
      Latitude and longitude are spherical coordinates on a unit circle. Each such coordinate tuple is transformed into a triple of Cartesian coordinates in Euclidean space. 
      This is first done for the presumed center point of the cell and then for all the corners of the cell. LLtoXYZ is defined in clipping/geometry.h 
@@ -494,7 +488,6 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
       
       /* Checks if there are any duplicate vertices in the list of corners. Note that the last (additional) corner has not been set yet. */
 
-      int *marked_duplicate_indices = (int*) Malloc(actual_number_of_corners*sizeof(int));
       for ( int i = 0; i < actual_number_of_corners; i++ ) marked_duplicate_indices[i] = 0;
 
       int no_duplicates = 0;
@@ -514,8 +507,6 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
             }
 
       /* Writes the unique corner vertices in a new array. */
-
-      double *cell_corners_xyz_without_duplicates = (double*) Malloc(3*(actual_number_of_corners - no_duplicates)*sizeof(double));
       
       int unique_corner_number = 0;
       
@@ -548,8 +539,6 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
 
       /* We are creating a closed polygon/cell by setting the additional last corner to be the same as the first one. */
 
-      double *cell_corners_xyz = (double*) Malloc(3*(actual_number_of_corners + 1)*sizeof(double));
-
       for ( int corner_no = 0; corner_no < actual_number_of_corners; corner_no++ )
         {
           int off = corner_no * 3;
@@ -565,8 +554,6 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
       int coordinate_to_ignore = find_coordinate_to_ignore(cell_corners_xyz);
      
       /* The remaining two-dimensional coordinates are extracted into one array for all the cell's corners and into one array for the center point. */
-
-      double *cell_corners_plane_projection = (double*) Malloc(2*(actual_number_of_corners +1)*sizeof(double));
       
       /* The following projection on the plane that two coordinate axes lie on changes the arrangement of
          the polygon vertices if the coordinate to be ignored along the third axis is smaller than 0.
@@ -643,13 +630,13 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
             printf(" %g/%g ", grid_corner_lon[cell_no * ncorner + corner_no], grid_corner_lat[cell_no * ncorner + corner_no]);
           printf("\n");
         }
-
-      Free(cell_corners_plane_projection);
-      Free(cell_corners_xyz);
-      Free(cell_corners_xyz_without_duplicates);
-      Free(marked_duplicate_indices);
     }
 
+  Free(marked_duplicate_indices);
+  Free(cell_corners_plane_projection);
+  Free(cell_corners_xyz);
+  Free(cell_corners_xyz_without_duplicates);
+
   int no_nonunique_cells = gridsize - no_unique_center_points;
   int no_nonconvex_cells = (int) gridsize - no_convex_cells;
   int no_nonusable_cells = (int) gridsize - no_usable_cells;
diff --git a/src/Vertcum.cc b/src/Vertcum.cc
index f8d7696..50b4a5e 100644
--- a/src/Vertcum.cc
+++ b/src/Vertcum.cc
@@ -60,7 +60,7 @@ void *Vertcum(void *argument)
   int nrecs;
   int i, nlevshl = 0;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
 
   cdoInitialize(argument);
 
@@ -77,7 +77,7 @@ void *Vertcum(void *argument)
   int vlistID2 = vlistDuplicate(vlistID1);
 
   int nvars = vlistNvars(vlistID1);
-  int **varnmiss = (int**) Malloc(nvars*sizeof(int*));
+  size_t **varnmiss = (size_t**) Malloc(nvars*sizeof(size_t*));
   double ***vardata1 = (double***) Malloc(nvars*sizeof(double**));
   double ***vardata2 = (double***) Malloc(nvars*sizeof(double**));
 
@@ -131,7 +131,7 @@ void *Vertcum(void *argument)
       int nlevs    = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
       int nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 
-      varnmiss[varID] = (int*) Malloc(nlevs*sizeof(int));
+      varnmiss[varID] = (size_t*) Malloc(nlevs*sizeof(size_t));
       vardata1[varID] = (double**) Malloc(nlevs*sizeof(double*));
       vardata2[varID] = (double**) Malloc(nlevs2*sizeof(double*));
       for ( levelID = 0; levelID < nlevs; ++levelID )
diff --git a/src/Vertintap.cc b/src/Vertintap.cc
index 0145f90..3b1b704 100644
--- a/src/Vertintap.cc
+++ b/src/Vertintap.cc
@@ -217,13 +217,13 @@ void *Vertintap(void *argument)
   
   std::vector<bool> vars(nvars);
   std::vector<bool> varinterp(nvars);
-  std::vector<int *> varnmiss(nvars);
+  std::vector<size_t *> varnmiss(nvars);
   std::vector<double *> vardata1(nvars);
   std::vector<double *> vardata2(nvars);
 
   int maxlev = nhlevh > nplev ? nhlevh : nplev;
 
-  int *pnmiss = extrapolate ? NULL : (int *) Malloc(nplev*sizeof(int));
+  size_t *pnmiss = extrapolate ? NULL : (size_t *) Malloc(nplev*sizeof(size_t));
 
   // check levels
   if ( zaxisIDh != -1 )
@@ -286,8 +286,8 @@ void *Vertintap(void *argument)
 	{
 	  varinterp[varID] = true;
 	  vardata2[varID]  = (double *) Malloc(gridsize*nplev*sizeof(double));
-	  varnmiss[varID]  = (int *) Malloc(maxlev*sizeof(int));
-	  memset(varnmiss[varID], 0, maxlev*sizeof(int));
+	  varnmiss[varID]  = (size_t *) Malloc(maxlev*sizeof(size_t));
+	  memset(varnmiss[varID], 0, maxlev*sizeof(size_t));
 	}
       else
 	{
@@ -300,7 +300,7 @@ void *Vertintap(void *argument)
 
 	  varinterp[varID] = false;
 	  vardata2[varID]  = vardata1[varID];
-	  varnmiss[varID]  = (int *) Malloc(nlevel*sizeof(int));
+	  varnmiss[varID]  = (size_t *) Malloc(nlevel*sizeof(size_t));
 	}
     }
   
@@ -436,7 +436,7 @@ void *Vertintap(void *argument)
 		  interp_X(vardata1[varID], vardata2[varID], hyb_press,
 			   vert_index, plev, nplev, gridsize, nlevel, missval);
 		  
-		  if ( !extrapolate ) memcpy(varnmiss[varID], pnmiss, nplev*sizeof(int));
+		  if ( !extrapolate ) memcpy(varnmiss[varID], pnmiss, nplev*sizeof(size_t));
 		}
 	    }
 	}
diff --git a/src/Vertintml.cc b/src/Vertintml.cc
index b955e37..755def2 100644
--- a/src/Vertintml.cc
+++ b/src/Vertintml.cc
@@ -186,13 +186,13 @@ void *Vertintml(void *argument)
 
   std::vector<bool> vars(nvars);
   std::vector<bool> varinterp(nvars);
-  std::vector<int *> varnmiss(nvars);
+  std::vector<size_t *> varnmiss(nvars);
   std::vector<double *> vardata1(nvars);
   std::vector<double *> vardata2(nvars);
 
   int maxlev = nhlevh > nplev ? nhlevh : nplev;
 
-  int *pnmiss = extrapolate ? NULL : (int*) Malloc(nplev*sizeof(int));
+  size_t *pnmiss = extrapolate ? NULL : (size_t*) Malloc(nplev*sizeof(size_t));
 
   // check levels
   if ( zaxisIDh != -1 )
@@ -362,8 +362,8 @@ void *Vertintml(void *argument)
 	{
 	  varinterp[varID] = true;
 	  vardata2[varID]  = (double*) Malloc(gridsize*nplev*sizeof(double));
-	  varnmiss[varID]  = (int*) Malloc(maxlev*sizeof(int));
-	  memset(varnmiss[varID], 0, maxlev*sizeof(int));
+	  varnmiss[varID]  = (size_t*) Malloc(maxlev*sizeof(size_t));
+	  memset(varnmiss[varID], 0, maxlev*sizeof(size_t));
 	}
       else
 	{
@@ -376,7 +376,7 @@ void *Vertintml(void *argument)
 
 	  varinterp[varID] = false;
 	  vardata2[varID]  = vardata1[varID];
-	  varnmiss[varID]  = (int*) Malloc(nlevel*sizeof(int));
+	  varnmiss[varID]  = (size_t*) Malloc(nlevel*sizeof(size_t));
 	}
     }
 
@@ -597,7 +597,7 @@ void *Vertintml(void *argument)
 			       vert_index, plev, nplev, gridsize, nlevel, missval);
 		    }
 		  
-		  if ( !extrapolate ) memcpy(varnmiss[varID], pnmiss, nplev*sizeof(int));
+		  if ( !extrapolate ) memcpy(varnmiss[varID], pnmiss, nplev*sizeof(size_t));
 		}
 	    }
 	}
diff --git a/src/Vertstat.cc b/src/Vertstat.cc
index bf55642..172031b 100644
--- a/src/Vertstat.cc
+++ b/src/Vertstat.cc
@@ -158,7 +158,7 @@ void *Vertstat(void *argument)
   int nrecs;
   int gridID;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   typedef struct {
     int zaxisID;
     int status;
@@ -337,10 +337,10 @@ void *Vertstat(void *argument)
 	  if ( levelID == 0 )
 	    {
 	      pstreamReadRecord(streamID1, vars1[varID].ptr, &nmiss);
-	      vars1[varID].nmiss = (size_t)nmiss;
+	      vars1[varID].nmiss = nmiss;
               if ( lrange )
                 {
-                  vars2[varID].nmiss = (size_t)nmiss;
+                  vars2[varID].nmiss = nmiss;
                   for ( int i = 0; i < gridsize; i++ )
                     vars2[varID].ptr[i] = vars1[varID].ptr[i];
                 }
@@ -376,7 +376,7 @@ void *Vertstat(void *argument)
 	  else
 	    {
 	      pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t)nmiss;
+              field.nmiss   = nmiss;
 	      field.grid    = vars1[varID].grid;
 	      field.missval = vars1[varID].missval;
 
@@ -456,7 +456,7 @@ void *Vertstat(void *argument)
                 }
 
 	      pstreamDefRecord(streamID2, varID, 0);
-	      pstreamWriteRecord(streamID2, vars1[varID].ptr, (int)vars1[varID].nmiss);
+	      pstreamWriteRecord(streamID2, vars1[varID].ptr, vars1[varID].nmiss);
 	      vars1[varID].nsamp = 0;
 	    }
 	}
diff --git a/src/Vertwind.cc b/src/Vertwind.cc
index 73f9bbc..1184319 100644
--- a/src/Vertwind.cc
+++ b/src/Vertwind.cc
@@ -37,7 +37,7 @@ void *Vertwind(void *argument)
   int nrecs;
   int varID, levelID;
   int nvct = 0;
-  int nmiss;
+  size_t nmiss;
   int tempID = -1, sqID = -1, psID = -1, omegaID = -1;
   char varname[CDI_MAX_NAME];
   double *vct = NULL;
@@ -214,7 +214,7 @@ void *Vertwind(void *argument)
 	{
 	  size_t offset = (size_t)levelID*gridsize;
 
-	  int nmiss_out = 0;
+	  size_t nmiss_out = 0;
 	  for ( int i = 0; i < gridsize; i++ )
             if ( DBL_IS_EQUAL(wms[offset+i],missval_out) )
 	      nmiss_out++;
diff --git a/src/Wct.cc b/src/Wct.cc
index 71e26ba..c8bf4a7 100644
--- a/src/Wct.cc
+++ b/src/Wct.cc
@@ -45,18 +45,17 @@ static double windchillTemperature(double t, double ff, double missval)
 
 static void farexpr(field_type *field1, field_type field2, double (*expression)(double, double, double))
 {
-  int   i, len;
+  size_t i, len;
   const int     grid1    = field1->grid;
-  const int     nmiss1   = field1->nmiss;
+  const size_t  nmiss1   = field1->nmiss;
   const double  missval1 = field1->missval;
   double       *array1   = field1->ptr;
   const int     grid2    = field2.grid;
-  const int     nmiss2   = field2.nmiss;
+  const size_t  nmiss2   = field2.nmiss;
   const double  missval2 = field2.missval;
   const double *array2   = field2.ptr;
 
   len = gridInqSize(grid1);
-
   if ( len != gridInqSize(grid2) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
@@ -83,7 +82,7 @@ static void farexpr(field_type *field1, field_type field2, double (*expression)(
 void *Wct(void *argument)
 {
   int nrecs, nrecs2;
-  int nmiss;
+  size_t nmiss;
   int varID1, varID2;
   int levelID1, levelID2;
 
@@ -145,11 +144,11 @@ void *Wct(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID1, &levelID1);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
           
 	  pstreamInqRecord(streamID2, &varID2, &levelID2);
 	  pstreamReadRecord(streamID2, field2.ptr, &nmiss);
-          field2.nmiss = (size_t) nmiss;
+          field2.nmiss = nmiss;
 	  
 	  if ( varID1 != varID2 || levelID1 != levelID2 )
 	    cdoAbort("Input streams have different structure!");
@@ -166,7 +165,7 @@ void *Wct(void *argument)
 	  farexpr(&field1, field2, windchillTemperature);
 	  
 	  pstreamDefRecord(streamID3, varID3, levelID1);
-	  pstreamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID3, field1.ptr, field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Wind.cc b/src/Wind.cc
index 43d82ae..6a56812 100644
--- a/src/Wind.cc
+++ b/src/Wind.cc
@@ -42,7 +42,7 @@ void *Wind(void *argument)
   int gridIDsp = -1, gridIDgp = -1;
   int gridID1 = -1, gridID2 = -1;
   int gridID;
-  int nmiss;
+  size_t nmiss;
   int nlon, nlat, ntr = -1;
   int code, param;
   int pnum, pcat, pdis;
diff --git a/src/WindTrans.cc b/src/WindTrans.cc
index 5fdf79a..28a6633 100644
--- a/src/WindTrans.cc
+++ b/src/WindTrans.cc
@@ -14,7 +14,7 @@
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.
 
-  This program is distributed in the hope that it will be useful,
+  This program 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 General Public License for more details.
@@ -78,9 +78,9 @@ int PROJUVLATLON;
 
 static
 void destaggerUorV(double *fu, double *fuOut,
-                   int klev, int nlat, int nlon, int UorV, long offset)
+                   int klev, long nlat, long nlon, long UorV, long offset)
 {
-  int lat0, lon0;
+  long lat0, lon0;
   double u0,u1;
   double u_dstg;
   long  next;
@@ -132,9 +132,9 @@ void destaggerUorV(double *fu, double *fuOut,
 
 static
 void destaggerUorV_positiveOrder(double *fu, double *fuOut,
-                   int klev, int nlat, int nlon, int UorV, long offset)
+                   int klev, long nlat, long nlon, int UorV, long offset)
 {
-  int latE, lonE;
+  long latE, lonE;
   double u0,u1;
   double u_dstg;
   long next;
@@ -157,9 +157,9 @@ void destaggerUorV_positiveOrder(double *fu, double *fuOut,
 
   for ( int lev = 0; lev < klev; lev++ )
     {
-      for ( int lat = 0; lat < latE; lat++ )
+      for ( long lat = 0; lat < latE; lat++ )
         {
-          for ( int lon = 0; lon < lonE; lon++ )
+          for ( long lon = 0; lon < lonE; lon++ )
             {
               u0 = fu[idx];
               u1 = fu[idx+next];
@@ -175,7 +175,7 @@ void destaggerUorV_positiveOrder(double *fu, double *fuOut,
             }
         }
       if (latE<nlat)   // the last row we let as it is
-        for ( int lon = 0; lon < nlon; lon++ )
+        for ( long lon = 0; lon < nlon; lon++ )
           {
             u0 = fu[idx];
             fuOut[idx] = u0;
@@ -192,7 +192,7 @@ void *DestaggerUV()
   int varID1 = CDI_UNDEFID, varID2 = CDI_UNDEFID;
   int zaxisID1 = CDI_UNDEFID, zaxisID2 = CDI_UNDEFID;
   int varID1stg = CDI_UNDEFID, varID2stg = CDI_UNDEFID;
-  int gridsize;
+  size_t gridsize;
   int chcodes[MAXARG];
   char *chvars[MAXARG];
   char varname[CDI_MAX_NAME];
@@ -202,7 +202,7 @@ void *DestaggerUV()
   int gridID;
   bool lcopy = false;
   int UorV;
-  int nlon = 0, nlat = 0;
+  size_t nlon = 0, nlat = 0;
   double *ivar = NULL, *ovar = NULL;
   double dxU = 0, dyU = 0, dxV = 0, dyV = 0;
 
@@ -410,7 +410,7 @@ void *DestaggerUV()
           cdoPrint("Grid info: (xfirst_R = %3.2f; yfirst_R = %3.2f); (xfirst_U = %3.2f; yfirst_U = %3.2f); (xfirst_V = %3.2f; yfirst_V = %3.2f);",
                    xfirst_R,yfirst_R,xfirst_U,yfirst_U,xfirst_V,yfirst_V);
           cdoPrint("Grid info: (dxU; dyU) = (%3.2f; %3.2f); (dxV; dyV) = (%3.2f; %3.2f) ", dxU, dyU, dxV, dyV);
-          cdoPrint("Grid info: nlon=%d, nlat=%d ", nlon, nlat);
+          cdoPrint("Grid info: nlon=%zu, nlat=%zu ", nlon, nlat);
         }
       if ( cdoDebugExt )
         {
@@ -460,7 +460,7 @@ void *DestaggerUV()
 
       gridsize = gridInqSize(gridID1);  // actual size of U-wind should be same as V-wind
       if ( cdoDebugExt )
-        cdoPrint("Allocating memory for gridsize (destaggered output)= %ld; nlon=%d, nlat=%d",gridsize,nlon,nlat );
+        cdoPrint("Allocating memory for gridsize (destaggered output)= %ld; nlon=%zu, nlat=%zu",gridsize,nlon,nlat );
       ovar = (double *) Malloc(gridsize*sizeof(double));
     } // end of  if (!lcopy)
 
@@ -540,7 +540,7 @@ void *DestaggerUV()
 
               if (UorV>=0)  // re-check again since it could mean that current record with U or V is not staggered
                 {
-                  int nmiss;
+                  size_t nmiss;
                   pstreamReadRecord(streamID1, ivar, &nmiss);
                   // read the original record with staggered u or v
                   gridsize = gridInqSize(gridID1);
@@ -665,8 +665,8 @@ void rot_uv_north(int gridID, double *us, double *vs)
         iDirectionIncrementInDegrees = 0.1;
   */
 
-  int nx = gridInqXsize(gridID);
-  int ny = gridInqYsize(gridID);
+  size_t nx = gridInqXsize(gridID);
+  size_t ny = gridInqYsize(gridID);
     
   double *xvals = (double *) Malloc(nx*ny*sizeof(double));
   double *yvals = (double *) Malloc(nx*ny*sizeof(double));
@@ -693,10 +693,10 @@ void rot_uv_north(int gridID, double *us, double *vs)
 
 
   if (cdoDebugExt)
-    cdoPrint("%s(gridname=%s) .. processing grid with UV [nx*ny] (%d * %d)", __func__, gridNamePtr(gridInqType(gridID)), nx, ny );
+    cdoPrint("%s(gridname=%s) .. processing grid with UV [nx*ny] (%zu * %zu)", __func__, gridNamePtr(gridInqType(gridID)), nx, ny );
 
   if (gridInqSize(gridID) != (nx*ny) )
-    cdoAbort("Incorrect gridsize (%d) != nx*ny (%d * %d)", gridInqSize(gridID), nx, ny);
+    cdoAbort("Incorrect gridsize (%zu) != nx*ny (%zu * %zu)", gridInqSize(gridID), nx, ny);
   // this should never happen
 
 #define OPTrotuvNorth 1   // ACTIVATE SPEED - OPTIMIZATION
@@ -980,8 +980,8 @@ void project_uv_latlon(int gridID, double *us, double *vs)
   double uu;
   double vv;
 
-  int nx = gridInqXsize(gridID);
-  int ny = gridInqYsize(gridID);
+  size_t nx = gridInqXsize(gridID);
+  size_t ny = gridInqYsize(gridID);
     
   double *xvals = (double *) Malloc(nx*ny*sizeof(double));
   double *yvals = (double *) Malloc(nx*ny*sizeof(double));
@@ -992,10 +992,10 @@ void project_uv_latlon(int gridID, double *us, double *vs)
   int signLat=( (yvals[1] - yvals[0]) < 0 )?-1:1;
 
   if (cdoDebugExt)
-    cdoPrint("%s(gridname=%s) .. processing grid with UV [nx*ny] (%d * %d)", __func__, gridNamePtr(gridInqType(gridID)), nx, ny );
+    cdoPrint("%s(gridname=%s) .. processing grid with UV [nx*ny] (%zu * %zu)", __func__, gridNamePtr(gridInqType(gridID)), nx, ny );
 
   if (gridInqSize(gridID) != (nx*ny) )
-    cdoAbort("Incorrect gridsize (%d) != nx*ny (%d * %d)", gridInqSize(gridID), nx, ny);
+    cdoAbort("Incorrect gridsize (%zu) != nx*ny (%zu * %zu)", gridInqSize(gridID), nx, ny);
   // this should never happen
 
   for ( j = 0; j < ny; j++ )
@@ -1072,11 +1072,11 @@ void *TransformUV(int operatorID)
 {
   int varID, levelID;
   int varID1, varID2, nlevel1, nlevel2;
-  int gridsize = 0;
+  size_t gridsize = 0;
   int code, gridID;
   int param, ltype, level, nlevs, zaxisID;
   int pnum, pcat, pdis;
-  int offset;
+  size_t offset;
   int chcodes[MAXARG];
   char *chvars[MAXARG];
   char varname[CDI_MAX_NAME];
@@ -1124,7 +1124,7 @@ void *TransformUV(int operatorID)
   int *recVarID   = (int *) Malloc(nrecs*sizeof(int));
   int *recLevelID = (int *) Malloc(nrecs*sizeof(int));
 
-  int **varnmiss   = (int **) Malloc(nvars*sizeof(int *));
+  size_t **varnmiss = (size_t **) Malloc(nvars*sizeof(size_t *));
   double **vardata = (double **) Malloc(nvars*sizeof(double *));
 
   // 0: set to '0'; 1: set to '1'
@@ -1186,9 +1186,9 @@ void *TransformUV(int operatorID)
         {
           gridsize = gridInqSize(gridID);
           if ( cdoDebugExt )
-            cdoPrint("Allocating memory for variableID %4d (code=%3d): gridsize(%d)*nlevels(%d) = %ld [%4.3f MB]",
+            cdoPrint("Allocating memory for variableID %4d (code=%3d): gridsize(%zu)*nlevels(%d) = %zu [%4.3f MB]",
                      varID, vlistInqVarCode(vlistID2, varID), gridsize, nlevs, gridsize*nlevs,gridsize*nlevs*sizeof(double)/(1024.0*1024));
-          varnmiss[varID] = (int *)    Malloc(nlevs*sizeof(int));
+          varnmiss[varID] = (size_t *) Malloc(nlevs*sizeof(size_t));
           vardata[varID]  = (double *) Malloc(gridsize*nlevs*sizeof(double));
         }
     }
@@ -1356,7 +1356,7 @@ void *TransformUV(int operatorID)
                               cdoPrint("grid Xlast   %4.3f, grid Ylast   %4.3f", gridInqXval(gridIDcurvl, gridInqSize(gridIDcurvl) -1), gridInqYval(gridIDcurvl, gridInqSize(gridIDcurvl) -1));
                               if ( cdoDebugExt>=20 )
                                 {
-                                  printf("Xvals (size=%d):\n",gridInqSize(gridIDcurvl));
+                                  printf("Xvals (size=%zu):\n",gridInqSize(gridIDcurvl));
                                   int ii;
                                   for (ii=0; ii< 10; ii++)
                                     printf("%4.3f ", gridInqXval(gridIDcurvl,ii));
@@ -1364,7 +1364,7 @@ void *TransformUV(int operatorID)
                                   for (ii=gridInqSize(gridIDcurvl)-10; ii< gridInqSize(gridIDcurvl); ii++)
                                     printf("%4.3f ", gridInqXval(gridIDcurvl,ii));
                                   printf("\n");
-                                  printf("Yvals (size=%d):\n",gridInqSize(gridIDcurvl));
+                                  printf("Yvals (size=%zu):\n",gridInqSize(gridIDcurvl));
                                   for (ii=0; ii< 10; ii++)
                                     printf("%4.3f ", gridInqYval(gridIDcurvl,ii));
                                   printf("\n...\n");
diff --git a/src/Writerandom.cc b/src/Writerandom.cc
index b88469f..2f7ad1f 100644
--- a/src/Writerandom.cc
+++ b/src/Writerandom.cc
@@ -58,7 +58,7 @@ void *Writerandom(void *argument)
       double **recdata = (double**) Malloc(nrecs*sizeof(double*));
       int *recvarID   = (int*) Malloc(nrecs*sizeof(int));
       int *reclevelID = (int*) Malloc(nrecs*sizeof(int));
-      int *recnmiss   = (int*) Malloc(nrecs*sizeof(int));
+      size_t *recnmiss = (size_t*) Malloc(nrecs*sizeof(size_t));
       int *recindex   = (int*) Malloc(nrecs*sizeof(int));
 
       for ( int recID = 0; recID < nrecs; recID++ )
diff --git a/src/XTimstat.cc b/src/XTimstat.cc
index e2e6b00..51980a3 100644
--- a/src/XTimstat.cc
+++ b/src/XTimstat.cc
@@ -87,7 +87,8 @@ static int num_recs = 0;
 static
 void *cdoReadTimestep(void *rarg)
 {
-  int varID, levelID, nmiss;
+  int varID, levelID;
+  size_t nmiss;
   readarg_t *readarg = (readarg_t *) rarg;
   field_type **input_vars = readarg->vars;
   recinfo_type *recinfo = readarg->recinfo;
@@ -158,7 +159,7 @@ void *XTimstat(void *argument)
   int varID;
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
-  int nmiss;
+  size_t nmiss;
   bool lvfrac = false;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
@@ -370,7 +371,7 @@ void *XTimstat(void *argument)
 
                   int nwpv     = pvars1->nwpv;
                   int gridsize = pvars1->size;
-                  int nmiss    = pinput_var->nmiss;
+                  size_t nmiss    = pinput_var->nmiss;
 
                   farcpy(pvars1, *pinput_var);
                   pvars1->nmiss = nmiss;
@@ -399,7 +400,7 @@ void *XTimstat(void *argument)
 
                   int nwpv     = pvars1->nwpv;
                   int gridsize = pvars1->size;
-                  int nmiss    = pinput_var->nmiss;
+                  size_t nmiss    = pinput_var->nmiss;
 
                   if ( nmiss > 0 || samp1[varID][levelID].ptr )
                     {
diff --git a/src/YAR.cc b/src/YAR.cc
index 8776a68..42c6687 100644
--- a/src/YAR.cc
+++ b/src/YAR.cc
@@ -361,7 +361,7 @@ void yar_remap_bil(field_type *field1, field_type *field2)
 	    remap.vars.num_wts, remap.vars.tgt_cell_add, remap.vars.src_cell_add, array1);
   if ( cdoTimer ) timer_stop(timer_yar_remap);
 
-  int nmiss = 0;
+  size_t nmiss = 0;
   for ( int i = 0; i < gridInqSize(gridIDout); ++i )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
@@ -658,7 +658,7 @@ void yar_remap_con(field_type *field1, field_type *field2)
 	    remap.vars.num_wts, remap.vars.tgt_cell_add, remap.vars.src_cell_add, array1);
   if ( cdoTimer ) timer_stop(timer_yar_remap);
 
-  int nmiss = 0;
+  size_t nmiss = 0;
   for ( int i = 0; i < gridInqSize(gridIDout); ++i )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
@@ -689,7 +689,7 @@ void *YAR(void *argument)
   int index;
   int varID, levelID;
   int gridID1 = -1;
-  int nmiss;
+  size_t nmiss;
   double missval;
 
   if ( cdoTimer )
diff --git a/src/Ydayarith.cc b/src/Ydayarith.cc
index 0a8b509..a7a0c1c 100644
--- a/src/Ydayarith.cc
+++ b/src/Ydayarith.cc
@@ -36,9 +36,9 @@ void *Ydayarith(void *argument)
 {
   int nrecs;
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   int year, month, day;
-  int **varnmiss2[MAX_DOY];
+  size_t **varnmiss2[MAX_DOY];
   double **vardata2[MAX_DOY];
 
   cdoInitialize(argument);
@@ -96,14 +96,14 @@ void *Ydayarith(void *argument)
       if ( vardata2[dayoy] != NULL ) cdoAbort("Day of year %d already allocatd (date=%d)!", dayoy, vdate);
 
       vardata2[dayoy]  = (double **) Malloc(nvars*sizeof(double *));
-      varnmiss2[dayoy] = (int **) Malloc(nvars*sizeof(int *));
+      varnmiss2[dayoy] = (size_t **) Malloc(nvars*sizeof(size_t *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
           size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  size_t nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	  vardata2[dayoy][varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	  varnmiss2[dayoy][varID] = (int*) Malloc(nlev*sizeof(int));
+	  varnmiss2[dayoy][varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	}
 
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -142,7 +142,7 @@ void *Ydayarith(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss = nmiss;
 
           size_t gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
           size_t offset   = gridsize*levelID;
@@ -158,7 +158,7 @@ void *Ydayarith(void *argument)
 
 	  farfun(&field1, field2, operfunc);
 
-          nmiss = (int) field1.nmiss;
+          nmiss = field1.nmiss;
 	  pstreamDefRecord(streamID3, varID, levelID);
 	  pstreamWriteRecord(streamID3, field1.ptr, nmiss);
 	}
diff --git a/src/Ydaypctl.cc b/src/Ydaypctl.cc
index 2869b12..cc8833b 100644
--- a/src/Ydaypctl.cc
+++ b/src/Ydaypctl.cc
@@ -40,7 +40,7 @@ void *Ydaypctl(void *argument)
   int year, month, day, dayoy;
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
   int vdates1[NDAY], vtimes1[NDAY];
   int vdates2[NDAY];
diff --git a/src/Ydaystat.cc b/src/Ydaystat.cc
index 0c976f6..23eda70 100644
--- a/src/Ydaystat.cc
+++ b/src/Ydaystat.cc
@@ -38,6 +38,36 @@
 
 #define  MAX_DOY       373
 
+int yearMode = 0;
+
+static
+void set_parameter(void)
+{
+  int pargc = operatorArgc();
+  if ( pargc )
+    { 
+      char **pargv = operatorArgv();
+
+      list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "PARAMETER");
+      if ( kvlist_parse_cmdline(kvlist, pargc, pargv) != 0 ) cdoAbort("Parse error!");
+      if ( cdoVerbose ) kvlist_print(kvlist);
+
+      for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+        {
+          keyValues_t *kv = *(keyValues_t **)kvnode->data;
+          const char *key = kv->key;
+          if ( kv->nvalues > 1 ) cdoAbort("Too many values for parameter key >%s<!", key);
+          if ( kv->nvalues < 1 ) cdoAbort("Missing value for parameter key >%s<!", key);
+          const char *value = kv->values[0];
+          
+          if ( STR_IS_EQ(key, "yearMode") ) yearMode = parameter2int(value);
+          else cdoAbort("Invalid parameter key >%s<!", key);
+        }          
+          
+      list_destroy(kvlist);
+    }
+}
+
 
 void *Ydaystat(void *argument)
 {
@@ -45,12 +75,14 @@ void *Ydaystat(void *argument)
   int year, month, day;
   int nrecs;
   int dayoy_nsets[MAX_DOY];
-  int nmiss;
+  size_t nmiss;
   int vdates[MAX_DOY], vtimes[MAX_DOY];
   field_type **vars1[MAX_DOY], **vars2[MAX_DOY], **samp1[MAX_DOY];
 
   cdoInitialize(argument);
 
+  set_parameter();
+
   // clang-format off
   cdoOperatorAdd("ydayrange", func_range, 0, NULL);
   cdoOperatorAdd("ydaymin",   func_min,   0, NULL);
@@ -152,7 +184,7 @@ void *Ydaystat(void *argument)
 	  if ( nsets == 0 )
 	    {
 	      pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-	      pvars1->nmiss = (size_t)nmiss;
+	      pvars1->nmiss = nmiss;
               if ( lrange )
                 {
                   pvars2->nmiss = pvars1->nmiss;
@@ -172,7 +204,7 @@ void *Ydaystat(void *argument)
 	  else
 	    {
 	      pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t)nmiss;
+              field.nmiss   = nmiss;
 	      field.grid    = pvars1->grid;
 	      field.missval = pvars1->missval;
 
@@ -225,20 +257,23 @@ void *Ydaystat(void *argument)
     }
 
   // set the year to the minimum of years found on output timestep
-  int outyear = 1e9;
-  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
-    if ( dayoy_nsets[dayoy] )
-      {
-        cdiDecodeDate(vdates[dayoy], &year, &month, &day);
-        if ( year < outyear ) outyear = year;
-      }
-  for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
-    if ( dayoy_nsets[dayoy] )
-      {
-        cdiDecodeDate(vdates[dayoy], &year, &month, &day);
-        if ( year > outyear ) vdates[dayoy] = cdiEncodeDate(outyear, month, day);
-        //  printf("vdates[%d] = %d  nsets = %d\n", dayoy, vdates[dayoy], nsets[dayoy]);
-      }
+  if ( yearMode )
+    {
+      int outyear = 1e9;
+      for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
+        if ( dayoy_nsets[dayoy] )
+          {
+            cdiDecodeDate(vdates[dayoy], &year, &month, &day);
+            if ( year < outyear ) outyear = year;
+          }
+      for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
+        if ( dayoy_nsets[dayoy] )
+          {
+            cdiDecodeDate(vdates[dayoy], &year, &month, &day);
+            if ( year > outyear ) vdates[dayoy] = cdiEncodeDate(outyear, month, day);
+            //  printf("vdates[%d] = %d  nsets = %d\n", dayoy, vdates[dayoy], nsets[dayoy]);
+          }
+    }
 
   for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     if ( dayoy_nsets[dayoy] )
@@ -291,7 +326,7 @@ void *Ydaystat(void *argument)
             field_type *pvars1 = &vars1[dayoy][varID][levelID];
 
 	    pstreamDefRecord(streamID2, varID, levelID);
-	    pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	    pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	  }
 
 	otsID++;
diff --git a/src/Ydrunpctl.cc b/src/Ydrunpctl.cc
index 8c83906..2d584ec 100644
--- a/src/Ydrunpctl.cc
+++ b/src/Ydrunpctl.cc
@@ -46,7 +46,7 @@ void *Ydrunpctl(void *argument)
   int nrecs;
   int levelID;
   int inp, its;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
   int year, month, day, dayoy;
   int vdate, vtime;
diff --git a/src/Ydrunstat.cc b/src/Ydrunstat.cc
index 1083e88..213af61 100644
--- a/src/Ydrunstat.cc
+++ b/src/Ydrunstat.cc
@@ -64,7 +64,7 @@ void *Ydrunstat(void *argument)
   int levelID;
   int tsID;
   int inp, its;
-  int nmiss;
+  size_t nmiss;
     
   cdoInitialize(argument);
 
diff --git a/src/Yearmonstat.cc b/src/Yearmonstat.cc
index daa8b59..cd20b9b 100644
--- a/src/Yearmonstat.cc
+++ b/src/Yearmonstat.cc
@@ -41,7 +41,7 @@ void *Yearmonstat(void *argument)
   int dpm;
   int year0 = 0, month0 = 0;
   int year, month, day;
-  int nmiss;
+  size_t nmiss;
   int nlevel;
   long nsets;
   double dsets;
@@ -135,7 +135,7 @@ void *Yearmonstat(void *argument)
 	      if ( nsets == 0 )
 		{
 		  pstreamReadRecord(streamID1, vars1[varID][levelID].ptr, &nmiss);
-		  vars1[varID][levelID].nmiss = (size_t) nmiss;
+		  vars1[varID][levelID].nmiss = nmiss;
 
 		  farcmul(&vars1[varID][levelID], dpm);
 
@@ -154,7 +154,7 @@ void *Yearmonstat(void *argument)
 	      else
 		{
 		  pstreamReadRecord(streamID1, field.ptr, &nmiss);
-                  field.nmiss   = (size_t) nmiss;
+                  field.nmiss   = nmiss;
 		  field.grid    = vars1[varID][levelID].grid;
 		  field.missval = vars1[varID][levelID].missval;
 
@@ -219,7 +219,7 @@ void *Yearmonstat(void *argument)
 	  if ( otsID && vlistInqVarTimetype(vlistID1, varID) == TIME_CONSTANT ) continue;
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr,  (int)vars1[varID][levelID].nmiss);
+	  pstreamWriteRecord(streamID2, vars1[varID][levelID].ptr,  vars1[varID][levelID].nmiss);
 	}
 
       if ( nrecs == 0 ) break;
diff --git a/src/Yhourarith.cc b/src/Yhourarith.cc
index 1415a1f..3ce2002 100644
--- a/src/Yhourarith.cc
+++ b/src/Yhourarith.cc
@@ -64,9 +64,9 @@ void *Yhourarith(void *argument)
   int varID, levelID;
   int offset;
   int vdate, vtime;
-  int nmiss;
+  size_t nmiss;
   int houroy;
-  int **varnmiss2[MAX_HOUR];
+  size_t **varnmiss2[MAX_HOUR];
   double **vardata2[MAX_HOUR];
 
   cdoInitialize(argument);
@@ -118,14 +118,14 @@ void *Yhourarith(void *argument)
       if ( vardata2[houroy] != NULL ) cdoAbort("Hour of year %d already allocatd!", houroy);
 
       vardata2[houroy]  = (double **) Malloc(nvars*sizeof(double *));
-      varnmiss2[houroy] = (int **) Malloc(nvars*sizeof(int *));
+      varnmiss2[houroy] = (size_t **) Malloc(nvars*sizeof(size_t *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	  vardata2[houroy][varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	  varnmiss2[houroy][varID] = (int*) Malloc(nlev*sizeof(int));
+	  varnmiss2[houroy][varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	}
 
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -159,7 +159,7 @@ void *Yhourarith(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss   = nmiss;
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 
@@ -173,7 +173,7 @@ void *Yhourarith(void *argument)
 	  farfun(&field1, field2, operfunc);
 
 	  pstreamDefRecord(streamID3, varID, levelID);
-	  pstreamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID3, field1.ptr, field1.nmiss);
 	}
 
       tsID++;
diff --git a/src/Yhourstat.cc b/src/Yhourstat.cc
index 3ecdb10..c81d1d7 100644
--- a/src/Yhourstat.cc
+++ b/src/Yhourstat.cc
@@ -71,7 +71,7 @@ void *Yhourstat(void *argument)
   int nrecs;
   int levelID;
   int houroy_nsets[MAX_HOUR];
-  int nmiss;
+  size_t nmiss;
   int vdates[MAX_HOUR], vtimes[MAX_HOUR];
   field_type **vars1[MAX_HOUR], **vars2[MAX_HOUR], **samp1[MAX_HOUR];
 
@@ -172,7 +172,7 @@ void *Yhourstat(void *argument)
 	  if ( nsets == 0 )
 	    {
 	      pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-	      pvars1->nmiss = (size_t) nmiss;
+	      pvars1->nmiss = nmiss;
               if ( lrange )
                 {
                   pvars2->nmiss = pvars1->nmiss;
@@ -192,7 +192,7 @@ void *Yhourstat(void *argument)
 	  else
 	    {
 	      pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t) nmiss;
+              field.nmiss   = nmiss;
 	      field.grid    = pvars1->grid;
 	      field.missval = pvars1->missval;
 
@@ -295,7 +295,7 @@ void *Yhourstat(void *argument)
             field_type *pvars1 = &vars1[houroy][varID][levelID];
 
 	    pstreamDefRecord(streamID2, varID, levelID);
-	    pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	    pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	  }
 
 	otsID++;
diff --git a/src/Ymonarith.cc b/src/Ymonarith.cc
index 13371d2..9c2bcbb 100644
--- a/src/Ymonarith.cc
+++ b/src/Ymonarith.cc
@@ -43,9 +43,9 @@ void *Ymonarith(void *argument)
   int nrecs, nlev;
   int varID, levelID;
   int offset;
-  int nmiss;
+  size_t nmiss;
   int vdate, year, mon, day;
-  int **varnmiss2[MAX_MON];
+  size_t **varnmiss2[MAX_MON];
   double **vardata2[MAX_MON];
   const char *seas_name[4];
 
@@ -117,14 +117,14 @@ void *Ymonarith(void *argument)
 	}
 
       vardata2[mon]  = (double **) Malloc(nvars*sizeof(double *));
-      varnmiss2[mon] = (int **) Malloc(nvars*sizeof(int *));
+      varnmiss2[mon] = (size_t **) Malloc(nvars*sizeof(size_t *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
 	  nlev     = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	  vardata2[mon][varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
-	  varnmiss2[mon][varID] = (int*) Malloc(nlev*sizeof(int));
+	  varnmiss2[mon][varID] = (size_t*) Malloc(nlev*sizeof(size_t));
 	}
 
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -168,7 +168,7 @@ void *Ymonarith(void *argument)
 	{
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
-          field1.nmiss = (size_t) nmiss;
+          field1.nmiss   = nmiss;
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
           
@@ -176,14 +176,14 @@ void *Ymonarith(void *argument)
 	  offset   = gridsize*levelID;
 
 	  memcpy(field2.ptr, vardata2[mon][varID]+offset, gridsize*sizeof(double));
-	  field2.nmiss = varnmiss2[mon][varID][levelID];
+	  field2.nmiss   = varnmiss2[mon][varID][levelID];
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
 	  field2.missval = vlistInqVarMissval(vlistID2, varID);
 
 	  farfun(&field1, field2, operfunc);
 
 	  pstreamDefRecord(streamID3, varID, levelID);
-	  pstreamWriteRecord(streamID3, field1.ptr, (int)field1.nmiss);
+	  pstreamWriteRecord(streamID3, field1.ptr, field1.nmiss);
 	}
       tsID++;
     }
diff --git a/src/Ymonpctl.cc b/src/Ymonpctl.cc
index a5d5dd9..e1f04e7 100644
--- a/src/Ymonpctl.cc
+++ b/src/Ymonpctl.cc
@@ -45,7 +45,7 @@ void *Ymonpctl(void *argument)
   int vdate, vtime;
   int year, month, day;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int nrecs, nlevels;
   int vdates1[NMONTH], vtimes1[NMONTH];
   int vdates2[NMONTH];
diff --git a/src/Ymonstat.cc b/src/Ymonstat.cc
index 88fd8f3..af53301 100644
--- a/src/Ymonstat.cc
+++ b/src/Ymonstat.cc
@@ -62,7 +62,7 @@ void *Ymonstat(void *argument)
   int nrecs;
   int levelID;
   int month_nsets[NMONTH];
-  int nmiss;
+  size_t nmiss;
   int vdates[NMONTH], vtimes[NMONTH];
   int mon[NMONTH];
   int nmon = 0;
@@ -168,7 +168,7 @@ void *Ymonstat(void *argument)
 	  if ( nsets == 0 )
 	    {
 	      pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-	      pvars1->nmiss = (size_t) nmiss;
+	      pvars1->nmiss = nmiss;
               if ( lrange )
                 {
                   pvars2->nmiss = pvars1->nmiss;
@@ -188,7 +188,7 @@ void *Ymonstat(void *argument)
 	  else
 	    {
 	      pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t) nmiss;
+              field.nmiss   = nmiss;
 	      field.grid    = pvars1->grid;
 	      field.missval = pvars1->missval;
 
@@ -319,7 +319,7 @@ void *Ymonstat(void *argument)
           field_type *pvars1 = &vars1[month][varID][levelID];
 
 	  pstreamDefRecord(streamID2, varID, levelID);
-	  pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	  pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	}
 
       otsID++;
diff --git a/src/Yseaspctl.cc b/src/Yseaspctl.cc
index 24b6739..f57795e 100644
--- a/src/Yseaspctl.cc
+++ b/src/Yseaspctl.cc
@@ -49,7 +49,7 @@ void *Yseaspctl(void *argument)
   int year, month, day, seas;
   int nrecs;
   int levelID;
-  int nmiss;
+  size_t nmiss;
   int nlevels;
   long nsets[NSEAS];
   date_time_t datetime1[NSEAS], datetime2[NSEAS];
diff --git a/src/Yseasstat.cc b/src/Yseasstat.cc
index aa142ef..bc0bde0 100644
--- a/src/Yseasstat.cc
+++ b/src/Yseasstat.cc
@@ -67,7 +67,7 @@ void *Yseasstat(void *argument)
   int nrecs;
   int levelID;
   int seas_nsets[NSEAS];
-  int nmiss;
+  size_t nmiss;
   date_time_t datetime[NSEAS];
   field_type **vars1[NSEAS], **vars2[NSEAS], **samp1[NSEAS];
 
@@ -168,7 +168,7 @@ void *Yseasstat(void *argument)
 	  if ( nsets == 0 )
 	    {
 	      pstreamReadRecord(streamID1, pvars1->ptr, &nmiss);
-	      pvars1->nmiss = (size_t)nmiss;
+	      pvars1->nmiss = nmiss;
               if ( lrange )
                 {
                   pvars2->nmiss = pvars1->nmiss;
@@ -188,7 +188,7 @@ void *Yseasstat(void *argument)
 	  else
 	    {
 	      pstreamReadRecord(streamID1, field.ptr, &nmiss);
-              field.nmiss   = (size_t)nmiss;
+              field.nmiss   = nmiss;
 	      field.grid    = pvars1->grid;
 	      field.missval = pvars1->missval;
 
@@ -291,7 +291,7 @@ void *Yseasstat(void *argument)
             field_type *pvars1 = &vars1[seas][varID][levelID];
 
 	    pstreamDefRecord(streamID2, varID, levelID);
-	    pstreamWriteRecord(streamID2, pvars1->ptr, (int)pvars1->nmiss);
+	    pstreamWriteRecord(streamID2, pvars1->ptr, pvars1->nmiss);
 	  }
 
 	otsID++;
diff --git a/src/Zonstat.cc b/src/Zonstat.cc
index 0a3421f..d0210d7 100644
--- a/src/Zonstat.cc
+++ b/src/Zonstat.cc
@@ -44,7 +44,7 @@ void *Zonstat(void *argument)
   int gridID1 = -1, gridID2 = -1;
   int zongridID = -1;
   int index;
-  int nmiss;
+  size_t nmiss;
   int nrecs;
   int varID, levelID;
 
@@ -156,7 +156,7 @@ void *Zonstat(void *argument)
 	  pstreamInqRecord(streamID1, &varID, &levelID);
 	  pstreamReadRecord(streamID1, field1.ptr, &nmiss);
 
-          field1.nmiss   = (size_t) nmiss;
+          field1.nmiss   = nmiss;
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field1.missval = vlistInqVarMissval(vlistID1, varID);
 	  field2.missval = vlistInqVarMissval(vlistID1, varID);
@@ -175,7 +175,7 @@ void *Zonstat(void *argument)
 	    }
 
 	  pstreamDefRecord(streamID2, varID,  levelID);
-	  pstreamWriteRecord(streamID2, field2.ptr, (int)field2.nmiss);
+	  pstreamWriteRecord(streamID2, field2.ptr, field2.nmiss);
 	}
 
       tsID++;
diff --git a/src/after_vertint.cc b/src/after_vertint.cc
index 26eaae1..7980d64 100644
--- a/src/after_vertint.cc
+++ b/src/after_vertint.cc
@@ -100,7 +100,7 @@ void genind(int *nx, const double *restrict plev, const double *restrict fullp,
 }  /* genind */
 
 
-void genindmiss(int *nx, const double *restrict plev, int ngp, int nplev, const double *restrict ps_prog, int *restrict pnmiss)
+void genindmiss(int *nx, const double *restrict plev, int ngp, int nplev, const double *restrict ps_prog, size_t *restrict pnmiss)
 {
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(nx,plev,ngp,nplev,ps_prog,pnmiss)
diff --git a/src/after_vertint.h b/src/after_vertint.h
index 4ddfbeb..4b23175 100644
--- a/src/after_vertint.h
+++ b/src/after_vertint.h
@@ -1,5 +1,5 @@
-#ifndef _VINTERP_H
-#define _VINTERP_H
+#ifndef VINTERP_H
+#define VINTERP_H
 
 #include <stdbool.h>
 
@@ -7,25 +7,25 @@
 extern "C" {
 #endif
 
-void height2pressure(double * restrict phlev, const double * restrict hlev, long nphlev);
+void height2pressure(double *restrict phlev, const double *restrict hlev, long nphlev);
 
-void presh(double * restrict fullp, double * halfp, const double *restrict vct,
+void presh(double *restrict fullp, double *halfp, const double *restrict vct,
 	   const double *restrict ps, long nhlev, long ngp);
 
-void genind(int *nx, const double * restrict plev, const double * restrict fullp, long ngp, long nplev, long nhlev);
-void genindmiss(int *nx, const double * restrict plev, int ngp, int nplev, const double * restrict ps_prog, int * restrict pnmiss);
+void genind(int *nx, const double *restrict plev, const double *restrict fullp, long ngp, long nplev, long nhlev);
+void genindmiss(int *nx, const double *restrict plev, int ngp, int nplev, const double *restrict ps_prog, size_t *restrict pnmiss);
 
-void extra_P(double * restrict slp, const double * restrict halfp, const double * restrict fullp,
-	     const double * restrict geop, const double * restrict temp, long ngp);
+void extra_P(double *restrict slp, const double *restrict halfp, const double *restrict fullp,
+	     const double *restrict geop, const double *restrict temp, long ngp);
 
-void interp_T(const double * restrict geop, const double * restrict gt, double *pt, const double * restrict fullp,
-	      const double * restrict halfp, const int *nx, const double * restrict plev, long nplev, long ngp,
+void interp_T(const double *restrict geop, const double *restrict gt, double *pt, const double *restrict fullp,
+	      const double *restrict halfp, const int *nx, const double *restrict plev, long nplev, long ngp,
 	      long nhlev, double missval);
-void interp_Z(const double * restrict geop, const double * restrict gz, double *pz, const double * restrict fullp,
-	      const double * restrict halfp, const int *nx, const double * restrict gt, const double * restrict plev,
+void interp_Z(const double *restrict geop, const double *restrict gz, double *pz, const double *restrict fullp,
+	      const double *restrict halfp, const int *nx, const double *restrict gt, const double *restrict plev,
 	      long nplev, long ngp, long nhlev, double missval);
-void interp_X(const double * restrict gt, double *pt, const double * restrict hyb_press, const int *nx,
-	      const double * restrict plev, long nplev, long ngp, long nhlev, double missval);
+void interp_X(const double *restrict gt, double *pt, const double *restrict hyb_press, const int *nx,
+	      const double *restrict plev, long nplev, long ngp, long nhlev, double missval);
 
 
 void vert_interp_lev3d(int gridsize, double missval, double *vardata1, double *vardata2,
@@ -39,4 +39,4 @@ void vert_gen_weights3d1d(bool expol, int nlev1, int gridsize, double *lev1, int
 }
 #endif
 
-#endif  /* _VINTERP_H */
+#endif  /* VINTERP_H */
diff --git a/src/afterburner.h b/src/afterburner.h
index 29884be..ae1d0b7 100644
--- a/src/afterburner.h
+++ b/src/afterburner.h
@@ -80,7 +80,7 @@ struct Control
   double *vct;
 
   int    *vert_index;
-  int    *pnmiss;
+  size_t *pnmiss;
   double *Orography;
   double *p_of_height;
 
@@ -141,8 +141,8 @@ struct Variable
   int     ogridID;
   int     izaxisID;
   int     ozaxisID;
-  int     nmiss0;
-  int     nmiss;
+  size_t  nmiss0;
+  size_t  nmiss;
   double  missval;
   double *spectral;
   double *spectral0;
@@ -241,9 +241,9 @@ void after_EchamCompGP(struct Control *globs, struct Variable *vars);
 void after_processPL(struct Control *globs, struct Variable *vars);
 void after_processML(struct Control *globs, struct Variable *vars);
 
-void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss);
+void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, size_t nmiss);
 double *after_get_dataptr(struct Variable *vars, int code, int gridID, int zaxisID, int levelID);
-void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss);
+void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, size_t nmiss);
 
 void  after_AnalysisDependencies(struct Variable *vars, int ncodes);
 void  after_EchamDependencies(struct Variable *vars, int ncodes, int type, int source);
diff --git a/src/afterburnerlib.cc b/src/afterburnerlib.cc
index 5190630..a7c35c7 100644
--- a/src/afterburnerlib.cc
+++ b/src/afterburnerlib.cc
@@ -148,7 +148,7 @@ void VarQuaSum(double *Variance, const double *restrict Sum, int len, int n)
 }
 
 static
-void AddVector(double * restrict dest, const double *restrict src, long len, int *nmiss, double missval)
+void AddVector(double * restrict dest, const double *restrict src, long len, size_t *nmiss, double missval)
 {
   if ( *nmiss > 0 )
     {
@@ -191,7 +191,7 @@ void Sub2Vectors(double *dest, const double *restrict srcA, const double *restri
 }
 
 static
-void MultVectorScalar(double *dest, const double *restrict src, double factor, int len, int nmiss, double missval)
+void MultVectorScalar(double *dest, const double *restrict src, double factor, int len, size_t nmiss, double missval)
 {
   if ( nmiss > 0 )
     {
@@ -210,7 +210,7 @@ void MultVectorScalar(double *dest, const double *restrict src, double factor, i
 }
 
 static
-void DivVectorIvector(double *dest, const double *restrict src, const int *samp, int len, int *nmiss, double missval)
+void DivVectorIvector(double *dest, const double *restrict src, const int *samp, int len, size_t *nmiss, double missval)
 {
   *nmiss = 0;
 
@@ -1565,7 +1565,7 @@ void after_processML(struct Control *globs, struct Variable *vars)
   int lindex, nlevel;
   int offset;
   int leveltype;
-  int nmiss;
+  size_t nmiss;
   double *pressureLevel = NULL;
 
   globs->MeanCount++;
@@ -1923,7 +1923,7 @@ void after_processML(struct Control *globs, struct Variable *vars)
       nmiss = 0;
       if ( ! globs->Extrapolate )
 	{
-	  if ( globs->pnmiss == NULL ) globs->pnmiss = (int *) Malloc(globs->NumLevelRequest*sizeof(int));  
+	  if ( globs->pnmiss == NULL ) globs->pnmiss = (size_t *) Malloc(globs->NumLevelRequest*sizeof(size_t));  
 	  genindmiss(globs->vert_index, pressureLevel, globs->DimGP, globs->NumLevelRequest, vars[PS_PROG].hybrid, globs->pnmiss);
 	  for ( i = 0; i < globs->NumLevelRequest; i++ ) nmiss += globs->pnmiss[i];
 	}
@@ -2393,7 +2393,7 @@ void after_processML(struct Control *globs, struct Variable *vars)
     }
 }
 
-void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss)
+void after_AnalysisAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, size_t nmiss)
 {
   long fieldSize;
   int truncation;
@@ -2506,7 +2506,7 @@ double *after_get_dataptr(struct Variable *vars, int code, int gridID, int zaxis
 }
 
 
-void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, int nmiss)
+void after_EchamAddRecord(struct Control *globs, struct Variable *vars, int code, int gridID, int zaxisID, int levelID, size_t nmiss)
 {
   int gridtype   = gridInqType(gridID);
   int leveltype  = zaxisInqType(zaxisID);
diff --git a/src/argument.cc b/src/argument.cc
index 34e0f03..0c7b99d 100644
--- a/src/argument.cc
+++ b/src/argument.cc
@@ -97,7 +97,7 @@ void argument_free(argument_t *argument)
           argument->args = NULL;
         }
 
-      Free(argument);
+      delete(argument);
     }
 }
 
@@ -109,16 +109,34 @@ void argument_fill(argument_t *argument, int argc, char *argv[])
     argument->argv[iarg] = strdup(argv[iarg]);
 }
 
-void print_argument(argument_t * p_argument)
+std::string print_argument(argument_t * p_argument)
 {
-    std::cout << "argv with " << p_argument->argc << " arguments:" << std::endl;
+    std::string output = "";
+    output += "argv with " + std::to_string(p_argument->argc) + " arguments:\n" ;
     for(int i = 0; i < p_argument->argc; i++)
     {
-        std::cout << p_argument->argv[i] << " ";
+        output += std::string(p_argument->argv[i]) + " ";
     }
-    std::cout << std::endl;
+    output += "\n";
+
+    output += "OperatorName: " + p_argument->operatorName + "\n";
 
-    std::cout << "OperatorName: "<< p_argument->operatorName << std::endl;
+    output += "operatorArguments";
+    if(p_argument->operatorArguments){
+    output += ": " + std::string(p_argument->operatorArguments) + "\n";
+    }
+    else
+    {
+        output += " not set\n";
+    }
 
-    std::cout << "operatorArguments: " << p_argument->operatorArguments << std::endl;
+    output += "args";
+    if(p_argument->operatorArguments){
+    output += ": " + std::string(p_argument->args) + "\n";
+    }
+    else
+    {
+        output += " not set\n";
+    }
+    return output;
 }
diff --git a/src/argument.h b/src/argument.h
index f45cdc3..394ef11 100644
--- a/src/argument.h
+++ b/src/argument.h
@@ -22,5 +22,5 @@ void        file_argument_free(argument_t *argument);
 argument_t *argument_new(size_t argc, size_t len);
 void        argument_free(argument_t *argument);
 void        argument_fill(argument_t *argument, int argc, char *argv[]);
-void print_argument(argument_t *argument);
+std::string print_argument(argument_t *argument);
 #endif
diff --git a/src/cdo.cc b/src/cdo.cc
index 2b3902b..a109c10 100644
--- a/src/cdo.cc
+++ b/src/cdo.cc
@@ -49,6 +49,7 @@
 #include "cdo_task.h"
 
 #include "cdo_getopt.h"
+#include "cdoDebugOutput.h"
 
 #if defined(HAVE_LIBPTHREAD)
 #include "pstream_int.h"
@@ -56,6 +57,7 @@
 #endif
 
 #include "modules.h"
+#include "process.h"
 #include "error.h"
 #include "grid_proj.h"
 
@@ -79,7 +81,7 @@ static int numThreads = 0;
 static int timer_total;
 static int CDO_netcdf_hdr_pad = 0;
 static int CDO_Rusage = 0;
-static const char *username;
+const char *CDO_username;
 
 #ifdef __cplusplus
 extern "C" {
@@ -111,7 +113,7 @@ void gridsearch_set_method(const char *methodstr);
           } \
       }
 
-#define ITSME  (strcmp(username, "\x6d\x32\x31\x34\x30\x30\x33") == 0)
+#define ITSME  (strcmp(CDO_username, "\x6d\x32\x31\x34\x30\x30\x33") == 0)
 
 static
 void cdo_stackframe(void)
@@ -190,22 +192,28 @@ void cdo_version(void)
   const int   filetypes[] = {CDI_FILETYPE_SRV, CDI_FILETYPE_EXT, CDI_FILETYPE_IEG, CDI_FILETYPE_GRB, CDI_FILETYPE_GRB2, CDI_FILETYPE_NC, CDI_FILETYPE_NC2, CDI_FILETYPE_NC4, CDI_FILETYPE_NC4C, CDI_FILETYPE_NC5};
   const char* typenames[] = {        "srv",        "ext",        "ieg",       "grb1",        "grb2",       "nc1",        "nc2",        "nc4",        "nc4c",        "nc5"};
 
-  fprintf(stderr, "%s\n", CDO_Version);
+  fprintf(stderr, "%s\n", CDO_version);
 #if defined(USER_NAME) && defined(HOST_NAME) && defined(SYSTEM_TYPE)
   fprintf(stderr, "Compiled: by %s on %s (%s) %s %s\n", USER_NAME, HOST_NAME, SYSTEM_TYPE, __DATE__, __TIME__);
 #endif
 #if defined(CXX_COMPILER)
   fprintf(stderr, "CXX Compiler: %s\n", CXX_COMPILER);
-#endif
 #if defined(CXX_VERSION)
   fprintf(stderr, "CXX version : %s\n", CXX_VERSION);
 #endif
+#endif
 #if defined(C_COMPILER)
   fprintf(stderr, "C Compiler: %s\n", C_COMPILER);
-#endif
 #if defined(C_VERSION)
   fprintf(stderr, "C version : %s\n", C_VERSION);
 #endif
+#endif
+#if defined(F77_COMPILER)
+  fprintf(stderr, "F77 Compiler: %s\n", F77_COMPILER);
+#if defined(F77_VERSION)
+  fprintf(stderr, "F77 version : %s\n", F77_VERSION);
+#endif
+#endif
 
   printFeatures();
   printLibraries();
@@ -226,7 +234,7 @@ void cdo_usage(void)
 {
   const char *name;
 
-  /*  fprintf(stderr, "%s\n", CDO_Version);*/
+  /*  fprintf(stderr, "%s\n", CDO_version);*/
   /*  fprintf(stderr, "\n");*/
   fprintf(stderr, "usage : cdo  [Options]  Operator1  [-Operator2  [-OperatorN]]\n");
   fprintf(stderr, "\n");
@@ -340,7 +348,7 @@ void cdoPrintHelp(std::vector<std::string> help/*, char *xoperator*/)
       for(unsigned long i =  0; i < help.size(); i++)
         {
           lprint = !(help[i][0] == '\0'  && help[i+1][0] == ' ');
-          
+
           if ( lprint )
             {
               if ( COLOR_STDOUT )
@@ -725,11 +733,11 @@ void defineVarnames(const char *arg)
 static
 void get_env_vars(void)
 {
-  username = getenv("LOGNAME");
-  if ( username == NULL )
+  CDO_username = getenv("LOGNAME");
+  if ( CDO_username == NULL )
     {
-      username = getenv("USER");
-      if ( username == NULL ) username = "unknown";
+      CDO_username = getenv("USER");
+      if ( CDO_username == NULL ) CDO_username = "unknown";
     }
 
   char *envstr = getenv("CDO_GRID_SEARCH_DIR");
@@ -912,6 +920,7 @@ void print_system_info()
 #endif 
   fprintf(stderr, "\n");
 
+  fprintf(stderr, "sizeof(size_t)      = %zu\n", sizeof(size_t));
   fprintf(stderr, "mem alignment       = %d\n\n", getMemAlignment());
 
 #if defined(HAVE_MMAP)
@@ -1103,6 +1112,7 @@ int parse_options_long(int argc, char *argv[])
   int lsortparam;
   int ldebLevel;
   int lscmode;
+  bool sepDebugFromLog;
 
   // clang-format off
   struct cdo_option opt_long[] =
@@ -1141,6 +1151,7 @@ int parse_options_long(int argc, char *argv[])
       { "version",                 no_argument,                NULL, 'V' },
       { "Dkext",             required_argument,          &ldebLevel,  1  },
       { "outputGribDataScanningMode", required_argument,  &lscmode,   1  },
+      { "seperateDebugFromLog", required_argument,             NULL,  2  },
       { NULL,                                0,                NULL,  0  }
     };
   // clang-format on
@@ -1205,7 +1216,7 @@ int parse_options_long(int argc, char *argv[])
               else if ( strcmp(CDO_optarg, "UNDERFLOW")  == 0 ) except = FE_UNDERFLOW;
               else if ( strcmp(CDO_optarg, "ALL_EXCEPT") == 0 ) except = FE_ALL_EXCEPT;
               if ( except < 0 ) cdoAbort("option --%s: unsupported argument: %s", "enableexcept", CDO_optarg);
-              cdo_feenableexcept((unsigned)except);
+              cdo_feenableexcept(except);
               if ( signal(SIGFPE, cdo_sig_handler) == SIG_ERR ) cdoWarning("can't catch SIGFPE!");
             }
           else if ( ltimestat_date )
@@ -1247,7 +1258,7 @@ int parse_options_long(int argc, char *argv[])
               int intarg = parameter2int(CDO_optarg);
               if ( intarg != 0 && intarg != 1 )
                 cdoAbort("Unsupported value for option --remap_genweights %d [0/1]", intarg);
-              remap_genweights = intarg;
+              REMAP_genweights = intarg;
             }
           else if ( lsortname )
             {
@@ -1413,6 +1424,12 @@ int parse_options_long(int argc, char *argv[])
         case 'z':
           defineCompress(CDO_optarg);
           break;
+        case 2:
+#ifdef DEBUG
+          CdoDebug::outfile = CDO_optarg;
+          CdoDebug::print_to_seperate_file = true;
+#endif
+          break;
         }
     }
 
@@ -1474,11 +1491,9 @@ int main(int argc, char *argv[])
  
   setCommandLine(argc, argv);
 
-  Progname = getProgname(argv[0]);
-
-  if ( strncmp(Progname, "cdo", 3) == 0 && strlen(Progname) > 3 ) noff = 3;
-
-  if ( noff ) setDefaultFileType(Progname+noff, 0);
+  CDO_progname = getProgname(argv[0]);
+  if ( strncmp(CDO_progname, "cdo", 3) == 0 && strlen(CDO_progname) > 3 ) noff = 3;
+  if ( noff ) setDefaultFileType(CDO_progname+noff, 0);
 
   get_env_vars();
   init_modules();
@@ -1608,13 +1623,18 @@ int main(int argc, char *argv[])
 
       timer_start(timer_total);
 
+#ifdef DEBUG
+    CdoDebug::Message_(":==CDO==","Start");
+#endif
 #ifdef CUSTOM_MODULES
       load_custom_modules("custom_modules");
       operatorModule(operatorName)(argument);
       close_library_handles();
 #else
       operatorModule(operatorName)(argument);
-
+#endif
+#ifdef DEBUG
+    CdoDebug::Message_(":==CDO==","End\n");
 #endif
 
       timer_stop(timer_total);
diff --git a/src/cdoDebugOutput.cc b/src/cdoDebugOutput.cc
new file mode 100644
index 0000000..1bd3c0d
--- /dev/null
+++ b/src/cdoDebugOutput.cc
@@ -0,0 +1,22 @@
+#include "cdoDebugOutput.h"
+
+
+
+namespace CdoDebug{
+
+#if defined(DEBUG_PSTREAM) || defined(DEBUG)
+   int PSTREAM = 1;
+#else
+   int PSTREAM = 0;
+#endif
+
+#if defined(DEBUG_PROCESS) || defined(DEBUG)
+   bool PROCESS = true;
+#else 
+   bool PROCESS = false;
+#endif
+
+   std::string outfile = "";
+   bool print_to_seperate_file = false;
+}
+
diff --git a/src/cdoDebugOutput.h b/src/cdoDebugOutput.h
new file mode 100644
index 0000000..28fc437
--- /dev/null
+++ b/src/cdoDebugOutput.h
@@ -0,0 +1,112 @@
+#ifndef DEBUG_SWITCHES_H
+#define DEBUG_SWITCHES_H
+#include <iostream>
+#include <sstream>
+
+#include <fstream>
+
+namespace CdoDebug
+{
+    extern int  PSTREAM;
+    extern bool PROCESS;
+    extern std::string outfile;
+    extern bool print_to_seperate_file;
+
+    namespace{
+        void printMessageToFile(std::stringstream &p_message)
+        {
+            if(!outfile.empty()){
+                std::fstream outfile_stream(outfile,std::fstream::in | std::fstream::app );
+
+                outfile_stream <<  p_message.str();
+            }
+        }
+    }
+
+
+    template <typename ...T>
+    void Message_ (std::stringstream &p_message, T&& ...args)
+    {
+           //for showing that the dummy array is never used
+           using expander = int[];
+           //creating dummy array with expanding the parameter pack in its
+           //initializer list while writing each element of the pack into message
+           expander{0,(void(p_message << std::forward<T>(args)),0)...};
+           p_message << std::endl;
+    }
+
+    template <typename ...T>
+    void Message_ (const char * p_func, T&& ...args)
+    {
+        std::stringstream message;
+        message << p_func <<": ";
+        Message_(message, args...);
+        if(print_to_seperate_file)
+        {
+            printMessageToFile(message);
+        }
+        else
+        {
+            std::cout << message.str();
+        }
+    }
+}
+
+namespace CdoError{
+    static int _ExitOnError = 1;
+
+    template <typename ...T>
+    void Error_(const char* p_file, const int p_line, const char* caller, T&& ...args)
+    {
+          std::stringstream message;
+          message << "Error in: " << p_file << ":" << p_line << " ";
+          CdoDebug::Message_(message, args...);
+          std::cout << message.str();
+          if ( CdoError::_ExitOnError )
+          {
+              exit(EXIT_FAILURE);
+          }
+    }
+    template <typename ...T>
+    void Warning_(T&& ...args)
+    {
+        std::stringstream message;
+        message << "Warning: ";
+        CdoDebug::Message_(message, args...);
+        std::cout << message.str();
+    }
+
+    template <typename ...T>
+    void SysError_(const char* p_file, const int p_line,  const char* p_func, T&& ...args)
+    {
+        int saved_errno = errno;
+        std::stringstream message;
+        message << "SysError in:" << p_file << std::endl;
+        message << "    " << "in function: p_func ,line: " << p_line << std::endl;
+        CdoDebug::Message_(message, args...);
+
+        if(saved_errno)
+        {
+            errno = saved_errno;
+            perror("Sytem error message");
+        }
+        exit(EXIT_FAILURE);
+    }
+}
+#if  defined  WITH_CALLER_NAME
+#  define  SYS_ERROR(...)    CdoError::SysError_( __FILE__ , __LINE__ , __func__ , __VA_ARGS__)
+#  define    ERROR_C(...)    CdoError::Error_( __FILE__ , __LINE__ ,  caller, __VA_ARGS__)
+#  define    ERROR(...)    CdoError::Error_( __FILE__ , __LINE__ , __func__ , __VA_ARGS__)
+#  define   WARNING(...)    CdoError::Warning_( __func__ , __VA_ARGS__)
+#  define  MESSAGE_C(...)    CdoDebug::Message_(   caller , __VA_ARGS__)
+#  define   MESSAGE(...)    CdoDebug::Message_( __func__ , __VA_ARGS__)
+#else
+#  define  SYS_ERROR(...)    CdoError::SysError_(__FILE__, __LINE__,"", __VA_ARGS__)
+#  define    ERROR_C(...)    CdoError::Error_(__FILE__, __LINE__,"", __VA_ARGS__)
+#  define    ERROR(...)      CdoError::Error_(__FILE__, __LINE__,"", __VA_ARGS__)
+#  define   WARNING(...)     CdoError::Warning_(__VA_ARGS__)
+#  define  MESSAGE_C(...)    CdoDebug::Message_(__VA_ARGS__)
+#  define   MESSAGE(...)     CdoDebug::Message_(__func__,__VA_ARGS__)
+#endif
+
+#endif
diff --git a/src/cdo_int.h b/src/cdo_int.h
index 8ba955c..b83eac9 100644
--- a/src/cdo_int.h
+++ b/src/cdo_int.h
@@ -15,11 +15,11 @@
   GNU General Public License for more details.
 */
 
-#ifndef _CDO_INT_H
-#define _CDO_INT_H
+#ifndef  CDO_INT_H
+#define  CDO_INT_H
 
-#if defined(HAVE_CONFIG_H)
-#  include "config.h"
+#ifdef  HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include <assert.h>
@@ -103,10 +103,10 @@ enum T_EIGEN_MODE  {JACOBI, DANIELSON_LANCZOS};
 #endif
 
 
-#define NEW_2D(T, P2D, N, M)     T **P2D = (N)?new T*[(N)]:nullptr;                          \
-                                 if ((N)) { P2D[0] = (M)?new T[(N)*(M)]:nullptr;             \
-                                            for ( size_t i = 1; i < (size_t) (N); ++i ) P2D[i] = P2D[0] + i*(M); }
-#define DELETE_2D(P2D) if (P2D) { if (P2D[0]) delete[] P2D[0]; delete[] P2D; P2D = nullptr; }
+#define  NEW_2D(T, P2D, N, M)     T **P2D = (N)?new T*[(N)]:nullptr;                          \
+                                  if ((N)) { P2D[0] = (M)?new T[(N)*(M)]:nullptr;             \
+                                             for ( size_t i = 1; i < (size_t) (N); ++i ) P2D[i] = P2D[0] + i*(M); }
+#define  DELETE_2D(P2D) if (P2D) { if (P2D[0]) delete[] P2D[0]; delete[] P2D; P2D = nullptr; }
 
 
 #define  IX2D(y,x,nx)  ((y)*(nx)+(x))
@@ -163,6 +163,7 @@ const char *parameter2word(const char *string);
 double parameter2double(const char *string);
 bool   parameter2bool(const char *string);
 int    parameter2int(const char *string);
+size_t parameter2sizet(const char *string);
 int    parameter2intlist(const char *string);
 
 int referenceToGrid(int gridID1);
@@ -204,4 +205,4 @@ int  vlistCompareX(int vlistID1, int vlistID2, int flag);
 }
 #endif
 
-#endif  /* _CDO_INT_H */
+#endif  /* CDO_INT_H */
diff --git a/src/cdo_read.cc b/src/cdo_read.cc
index ebed97f..41c0cae 100644
--- a/src/cdo_read.cc
+++ b/src/cdo_read.cc
@@ -45,7 +45,7 @@ bool *cdo_read_timestepmask(const char *maskfile, int *n)
       if ( nrecs != 1 ) cdoAbort("Internal error; unexprected number of records!");
 
       int varID, levelID;
-      int nmiss;
+      size_t nmiss;
       double value;
       streamInqRecord(streamID, &varID, &levelID);
       streamReadRecord(streamID, &value, &nmiss);
@@ -86,7 +86,7 @@ bool *cdo_read_mask(const char *maskfile, int *n)
   if ( nrecs != 1 ) cdoAbort("Internal error; unexprected number of records!");
 
   int varID, levelID;
-  int nmiss;
+  size_t nmiss;
   streamInqRecord(streamID, &varID, &levelID);
   streamReadRecord(streamID, dmask, &nmiss);
 
diff --git a/src/cdo_vlist.cc b/src/cdo_vlist.cc
index a7874d4..bf21271 100644
--- a/src/cdo_vlist.cc
+++ b/src/cdo_vlist.cc
@@ -50,7 +50,7 @@ int cdoZaxisInqLevels(int zaxisID, double *levels)
 }
 
 static
-void compare_lat_reg2d(int ysize, int gridID1, int gridID2)
+void compare_lat_reg2d(size_t ysize, int gridID1, int gridID2)
 {
   if ( ysize > 1 )
     {      
@@ -70,7 +70,7 @@ void compare_lat_reg2d(int ysize, int gridID1, int gridID2)
 	}
       else
 	{
-	  for ( int i = 0; i < ysize; ++i )
+	  for ( size_t i = 0; i < ysize; ++i )
 	    if ( fabs(yvals1[i] - yvals2[i]) > 3.e-5 )
 	      {
 		cdoWarning("Grid latitudes differ!");
@@ -84,7 +84,7 @@ void compare_lat_reg2d(int ysize, int gridID1, int gridID2)
 }
 
 static
-void compare_lon_reg2d(int xsize, int gridID1, int gridID2)
+void compare_lon_reg2d(size_t xsize, int gridID1, int gridID2)
 {
   if ( xsize > 1 )
     {
@@ -94,7 +94,7 @@ void compare_lon_reg2d(int xsize, int gridID1, int gridID2)
       gridInqXvals(gridID1, xvals1);
       gridInqXvals(gridID2, xvals2);
 		  
-      for ( int i = 0; i < xsize; ++i )
+      for ( size_t i = 0; i < xsize; ++i )
 	if ( fabs(xvals1[i] - xvals2[i]) > 3.e-5 )
 	  {
 	    cdoWarning("Grid longitudes differ!");
@@ -112,7 +112,7 @@ void compare_grid_unstructured(int gridID1, int gridID2)
   if ( gridInqXvals(gridID1, NULL) && gridInqXvals(gridID1, NULL) == gridInqXvals(gridID2, NULL) &&
        gridInqYvals(gridID1, NULL) && gridInqYvals(gridID1, NULL) == gridInqYvals(gridID2, NULL) )
     {
-      int gridsize = gridInqSize(gridID1);
+      size_t gridsize = gridInqSize(gridID1);
       
       double *xvals1 = (double*) Malloc(gridsize*sizeof(double));
       double *xvals2 = (double*) Malloc(gridsize*sizeof(double));
@@ -125,7 +125,7 @@ void compare_grid_unstructured(int gridID1, int gridID2)
       gridInqYvals(gridID2, yvals2);
 
       int inc = gridsize > 10000 ? gridsize/1000 : 1;
-      for ( int i = 0; i < gridsize; i += inc )
+      for ( size_t i = 0; i < gridsize; i += inc )
         if ( fabs(xvals1[i] - xvals2[i]) > 2.e-5 || fabs(yvals1[i] - yvals2[i]) > 2.e-5 )
           {
             // printf("%d %g %g %g %g %g %g\n", i, xvals1[i], xvals2[i], yvals1[i], yvals2[i], xvals1[i] - xvals2[i], yvals1[i] - yvals2[i]);
@@ -149,8 +149,8 @@ void cdoCompareGrids(int gridID1, int gridID2)
     {
       if ( gridInqType(gridID1) == GRID_GAUSSIAN || gridInqType(gridID1) == GRID_LONLAT )
 	{
-	  int xsize = gridInqXsize(gridID1);
-	  int ysize = gridInqYsize(gridID1);
+	  size_t xsize = gridInqXsize(gridID1);
+	  size_t ysize = gridInqYsize(gridID1);
 		
 	  if ( ysize == gridInqYsize(gridID2) )
 	    compare_lat_reg2d(ysize, gridID1, gridID2);
@@ -367,12 +367,12 @@ int vlistInqNWPV(int vlistID, int varID)
 }
 
 
-int vlist_check_gridsize(int vlistID)
+size_t vlist_check_gridsize(int vlistID)
 {
   bool lerror = false;
   int ngrids = vlistNgrids(vlistID);
   int gridID = vlistGrid(vlistID, 0);
-  int ngp    = gridInqSize(gridID);
+  size_t ngp    = gridInqSize(gridID);
 
   /* check gridsize */
   for ( int index = 0; index < ngrids; ++index )
@@ -392,7 +392,7 @@ int vlist_check_gridsize(int vlistID)
       for ( int index = 0; index < ngrids; ++index )
 	{
 	  gridID = vlistGrid(vlistID, index);
-	  cdoPrint("  grid=%d  type=%s  points=%d", index+1, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID));
+	  cdoPrint("  grid=%d  type=%s  points=%zu", index+1, gridNamePtr(gridInqType(gridID)), gridInqSize(gridID));
 	}
       cdoAbort("The input stream contains variables on different horizontal grids!");
     }
diff --git a/src/cdotest.cc b/src/cdotest.cc
index 3b2516e..03ef603 100644
--- a/src/cdotest.cc
+++ b/src/cdotest.cc
@@ -54,7 +54,8 @@ void readNcFile(const char path[], double **vars, int nvars, int nts)
 {
   int taxisID;
   int vlistID, varID, streamID, tsID;
-  int nmiss, nrecs;
+  size_t nmiss;
+  int nrecs;
   
   streamID = streamOpenRead(path);
   if ( streamID < 0 )
@@ -93,7 +94,7 @@ void writeNcFile(const char path[], const double array[], int length)
 {
   int gridID, zaxisID, taxisID;
   int vlistID, varID, streamID, tsID;
-  int nmiss;
+  size_t nmiss;
   
   double lons[] = {0.0};
   double lats[] = {0.0};
diff --git a/src/cellsearchorder.h b/src/cellsearchorder.h
new file mode 100644
index 0000000..4126e7d
--- /dev/null
+++ b/src/cellsearchorder.h
@@ -0,0 +1,30000 @@
+0,0,0,13,
+0,0,1,18,
+0,1,1,24,
+1,1,1,31,
+0,0,2,31,
+0,1,2,33,
+1,1,2,39,
+0,2,2,42,
+1,2,2,49,
+0,0,3,49,
+0,1,3,49,
+1,1,3,51,
+2,2,2,56,
+0,2,3,56,
+1,2,3,61,
+0,0,4,61,
+0,1,4,61,
+2,2,3,72,
+0,3,3,72,
+1,1,4,72,
+1,3,3,75,
+0,2,4,75,
+1,2,4,77,
+2,3,3,86,
+2,2,4,89,
+0,0,5,89,
+0,3,4,89,
+0,1,5,89,
+1,3,4,92,
+1,1,5,92,
+3,3,3,101,
+2,3,4,104,
+0,2,5,104,
+1,2,5,104,
+0,4,4,104,
+2,2,5,110,
+1,4,4,110,
+3,3,4,120,
+0,3,5,120,
+1,3,5,120,
+0,0,6,120,
+2,4,4,121,
+0,1,6,121,
+1,1,6,121,
+2,3,5,128,
+0,2,6,128,
+3,4,4,135,
+0,4,5,135,
+1,2,6,135,
+1,4,5,135,
+3,3,5,141,
+2,2,6,141,
+2,4,5,147,
+0,3,6,147,
+1,3,6,147,
+4,4,4,159,
+2,3,6,159,
+0,0,7,159,
+0,1,7,159,
+0,5,5,159,
+3,4,5,164,
+1,1,7,164,
+1,5,5,164,
+0,4,6,164,
+1,4,6,164,
+0,2,7,164,
+1,2,7,164,
+3,3,6,170,
+2,5,5,170,
+2,4,6,173,
+2,2,7,173,
+4,4,5,182,
+0,3,7,182,
+3,5,5,187,
+1,3,7,187,
+3,4,6,191,
+0,5,6,191,
+1,5,6,191,
+2,3,7,191,
+0,0,8,191,
+0,4,7,191,
+0,1,8,191,
+2,5,6,199,
+1,1,8,199,
+1,4,7,199,
+4,5,5,211,
+3,3,7,211,
+4,4,6,213,
+0,2,8,213,
+2,4,7,213,
+1,2,8,213,
+3,5,6,218,
+0,6,6,218,
+2,2,8,218,
+0,3,8,218,
+1,6,6,218,
+1,3,8,218,
+3,4,7,224,
+0,5,7,224,
+5,5,5,236,
+1,5,7,236,
+2,6,6,236,
+4,5,6,241,
+2,3,8,241,
+2,5,7,241,
+0,4,8,241,
+4,4,7,251,
+1,4,8,251,
+3,6,6,251,
+0,0,9,251,
+3,3,8,251,
+0,1,9,251,
+3,5,7,255,
+1,1,9,255,
+2,4,8,255,
+0,6,7,255,
+0,2,9,255,
+5,5,6,268,
+1,6,7,268,
+1,2,9,268,
+4,6,6,272,
+2,6,7,272,
+3,4,8,272,
+2,2,9,272,
+0,5,8,272,
+4,5,7,277,
+0,3,9,277,
+1,5,8,277,
+1,3,9,277,
+2,5,8,277,
+3,6,7,285,
+2,3,9,285,
+4,4,8,290,
+5,6,6,300,
+0,4,9,300,
+1,4,9,300,
+3,5,8,300,
+0,7,7,300,
+5,5,7,306,
+1,7,7,306,
+3,3,9,306,
+0,6,8,306,
+0,0,10,306,
+4,6,7,311,
+2,4,9,311,
+1,6,8,311,
+0,1,10,311,
+2,7,7,311,
+1,1,10,311,
+0,2,10,311,
+2,6,8,311,
+1,2,10,311,
+4,5,8,320,
+0,5,9,320,
+3,4,9,320,
+3,7,7,325,
+1,5,9,325,
+2,2,10,325,
+6,6,6,331,
+0,3,10,331,
+3,6,8,331,
+5,6,7,339,
+2,5,9,339,
+1,3,10,339,
+2,3,10,339,
+4,4,9,339,
+0,7,8,339,
+1,7,8,339,
+4,7,7,350,
+5,5,8,350,
+3,5,9,350,
+4,6,8,353,
+0,4,10,353,
+2,7,8,353,
+0,6,9,353,
+1,4,10,353,
+3,3,10,353,
+1,6,9,353,
+2,4,10,353,
+6,6,7,378,
+2,6,9,378,
+0,0,11,378,
+4,5,9,378,
+0,1,11,378,
+3,7,8,378,
+1,1,11,378,
+5,7,7,382,
+0,2,11,382,
+5,6,8,386,
+3,4,10,386,
+0,5,10,386,
+3,6,9,386,
+1,5,10,386,
+1,2,11,386,
+0,8,8,386,
+1,8,8,386,
+4,7,8,393,
+2,2,11,393,
+2,5,10,393,
+0,7,9,393,
+0,3,11,393,
+5,5,9,399,
+1,7,9,399,
+1,3,11,399,
+4,4,10,399,
+2,8,8,399,
+4,6,9,404,
+3,5,10,404,
+2,3,11,404,
+6,7,7,416,
+2,7,9,416,
+0,6,10,416,
+6,6,8,421,
+1,6,10,421,
+3,8,8,421,
+0,4,11,421,
+1,4,11,421,
+5,7,8,429,
+3,3,11,429,
+3,7,9,429,
+2,6,10,429,
+4,5,10,429,
+2,4,11,429,
+5,6,9,439,
+0,0,12,439,
+4,8,8,442,
+0,1,12,442,
+0,8,9,442,
+3,6,10,442,
+4,7,9,447,
+1,1,12,447,
+3,4,11,447,
+0,5,11,447,
+1,8,9,447,
+7,7,7,459,
+1,5,11,459,
+0,2,12,459,
+2,8,9,459,
+6,7,8,465,
+0,7,10,465,
+1,2,12,465,
+5,5,10,465,
+2,5,11,465,
+1,7,10,465,
+2,2,12,465,
+4,6,10,465,
+5,8,8,475,
+0,3,12,475,
+2,7,10,475,
+6,6,9,475,
+4,4,11,475,
+3,8,9,475,
+1,3,12,475,
+5,7,9,483,
+3,5,11,483,
+2,3,12,483,
+0,6,11,483,
+1,6,11,483,
+3,7,10,483,
+0,4,12,483,
+2,6,11,483,
+5,6,10,494,
+4,8,9,494,
+1,4,12,494,
+7,7,8,509,
+3,3,12,509,
+0,9,9,509,
+4,5,11,509,
+1,9,9,509,
+6,8,8,512,
+2,4,12,512,
+0,8,10,512,
+4,7,10,512,
+1,8,10,512,
+2,9,9,512,
+6,7,9,520,
+3,6,11,520,
+2,8,10,520,
+3,4,12,520,
+0,5,12,520,
+0,0,13,520,
+0,1,13,520,
+0,7,11,520,
+5,8,9,533,
+1,5,12,533,
+1,7,11,533,
+3,9,9,533,
+5,5,11,533,
+1,1,13,533,
+6,6,10,535,
+4,6,11,535,
+2,5,12,535,
+0,2,13,535,
+3,8,10,535,
+5,7,10,541,
+2,7,11,541,
+1,2,13,541,
+4,4,12,541,
+7,8,8,559,
+2,2,13,559,
+4,9,9,559,
+3,5,12,559,
+0,3,13,559,
+1,3,13,559,
+7,7,9,563,
+3,7,11,563,
+0,6,12,563,
+4,8,10,563,
+1,6,12,563,
+0,9,10,563,
+6,8,9,567,
+5,6,11,567,
+2,3,13,567,
+1,9,10,567,
+2,6,12,567,
+0,8,11,567,
+6,7,10,576,
+0,4,13,576,
+4,5,12,576,
+2,9,10,576,
+1,8,11,576,
+1,4,13,576,
+4,7,11,576,
+3,3,13,576,
+5,9,9,585,
+2,8,11,585,
+3,6,12,585,
+2,4,13,585,
+5,8,10,592,
+3,9,10,592,
+8,8,8,613,
+6,6,11,613,
+0,7,12,613,
+7,8,9,618,
+1,7,12,618,
+3,4,13,618,
+5,5,12,618,
+0,5,13,618,
+3,8,11,618,
+5,7,11,618,
+1,5,13,618,
+0,0,14,618,
+4,6,12,618,
+2,7,12,618,
+4,9,10,618,
+0,1,14,618,
+2,5,13,618,
+1,1,14,618,
+6,9,9,631,
+7,7,10,631,
+0,2,14,631,
+6,8,10,635,
+0,10,10,635,
+4,4,13,635,
+4,8,11,635,
+1,2,14,635,
+1,10,10,635,
+3,7,12,635,
+0,9,11,635,
+3,5,13,635,
+1,9,11,635,
+2,10,10,635,
+2,2,14,635,
+0,3,14,635,
+5,6,12,638,
+0,6,13,638,
+1,6,13,638,
+5,9,10,651,
+6,7,11,651,
+1,3,14,651,
+2,9,11,651,
+0,8,12,651,
+1,8,12,651,
+4,7,12,651,
+2,6,13,651,
+3,10,10,651,
+2,3,14,651,
+8,8,9,667,
+4,5,13,667,
+5,8,11,667,
+7,9,9,672,
+3,9,11,672,
+2,8,12,672,
+0,4,14,672,
+7,8,10,681,
+1,4,14,681,
+3,3,14,681,
+3,6,13,681,
+2,4,14,681,
+4,10,10,681,
+6,6,12,681,
+3,8,12,681,
+6,9,10,695,
+4,9,11,695,
+0,7,13,695,
+5,7,12,695,
+7,7,11,699,
+5,5,13,699,
+1,7,13,699,
+0,5,14,699,
+0,10,11,699,
+6,8,11,704,
+4,6,13,704,
+3,4,14,704,
+2,7,13,704,
+1,5,14,704,
+1,10,11,704,
+4,8,12,704,
+2,10,11,704,
+5,10,10,711,
+0,0,15,711,
+0,9,12,711,
+2,5,14,711,
+8,9,9,735,
+1,9,12,735,
+0,1,15,735,
+5,9,11,735,
+1,1,15,735,
+3,7,13,735,
+8,8,10,738,
+4,4,14,738,
+0,2,15,738,
+6,7,12,738,
+2,9,12,738,
+5,6,13,738,
+3,10,11,738,
+7,9,10,743,
+3,5,14,743,
+1,2,15,743,
+0,6,14,743,
+5,8,12,743,
+0,8,13,743,
+2,2,15,743,
+1,6,14,743,
+1,8,13,743,
+0,3,15,743,
+4,7,13,743,
+7,8,11,755,
+3,9,12,755,
+1,3,15,755,
+6,10,10,756,
+2,6,14,756,
+2,8,13,756,
+4,10,11,756,
+4,5,14,756,
+6,9,11,766,
+2,3,15,766,
+3,6,14,766,
+0,4,15,766,
+4,9,12,766,
+6,6,13,766,
+1,4,15,766,
+0,11,11,766,
+3,8,13,766,
+7,7,12,776,
+5,7,13,776,
+1,11,11,776,
+9,9,9,792,
+3,3,15,792,
+6,8,12,792,
+0,10,12,792,
+0,7,14,792,
+2,4,15,792,
+8,9,10,799,
+1,10,12,799,
+5,10,11,799,
+5,5,14,799,
+1,7,14,799,
+2,11,11,799,
+4,6,14,799,
+2,10,12,799,
+7,10,10,810,
+8,8,11,810,
+4,8,13,810,
+2,7,14,810,
+3,4,15,810,
+5,9,12,810,
+0,9,13,810,
+0,5,15,810,
+1,5,15,810,
+1,9,13,810,
+7,9,11,818,
+3,11,11,818,
+3,10,12,818,
+6,7,13,818,
+2,5,15,818,
+3,7,14,818,
+2,9,13,818,
+0,0,16,818,
+4,4,15,818,
+6,10,11,837,
+0,1,16,837,
+5,6,14,837,
+7,8,12,837,
+4,11,11,837,
+1,1,16,837,
+5,8,13,837,
+3,9,13,837,
+3,5,15,837,
+0,2,16,837,
+0,8,14,837,
+4,10,12,837,
+4,7,14,837,
+6,9,12,848,
+1,2,16,848,
+1,8,14,848,
+0,6,15,848,
+9,9,10,859,
+1,6,15,859,
+2,2,16,859,
+2,8,14,859,
+8,10,10,865,
+0,3,16,865,
+0,11,12,865,
+2,6,15,865,
+4,5,15,865,
+1,3,16,865,
+4,9,13,865,
+8,9,11,875,
+1,11,12,875,
+5,11,11,875,
+7,7,13,875,
+6,6,14,875,
+5,10,12,875,
+2,3,16,875,
+0,10,13,875,
+3,8,14,875,
+6,8,13,875,
+2,11,12,875,
+7,10,11,885,
+1,10,13,885,
+5,7,14,885,
+3,6,15,885,
+0,4,16,885,
+8,8,12,892,
+2,10,13,892,
+1,4,16,892,
+7,9,12,899,
+0,7,15,899,
+3,3,16,899,
+3,11,12,899,
+5,9,13,899,
+1,7,15,899,
+5,5,15,899,
+4,8,14,899,
+2,4,16,899,
+4,6,15,899,
+0,9,14,899,
+1,9,14,899,
+6,11,11,912,
+3,10,13,912,
+2,7,15,912,
+6,10,12,917,
+2,9,14,917,
+6,7,14,917,
+9,10,10,933,
+4,11,12,933,
+0,5,16,933,
+3,4,16,933,
+7,8,13,933,
+1,5,16,933,
+9,9,11,942,
+3,7,15,942,
+4,10,13,942,
+8,10,11,947,
+2,5,16,947,
+5,8,14,947,
+3,9,14,947,
+5,6,15,947,
+6,9,13,947,
+0,12,12,947,
+4,4,16,947,
+8,9,12,958,
+0,8,15,958,
+1,12,12,958,
+0,0,17,958,
+1,8,15,958,
+3,5,16,958,
+0,11,13,958,
+4,7,15,958,
+0,1,17,958,
+5,11,12,958,
+7,11,11,966,
+1,11,13,966,
+1,1,17,966,
+0,6,16,966,
+2,12,12,966,
+0,2,17,966,
+1,6,16,966,
+2,8,15,966,
+7,10,12,971,
+4,9,14,971,
+1,2,17,971,
+2,11,13,971,
+5,10,13,971,
+7,7,14,971,
+6,8,14,971,
+2,6,16,971,
+0,10,14,971,
+4,5,16,971,
+6,6,15,971,
+8,8,13,985,
+1,10,14,985,
+2,2,17,985,
+3,12,12,985,
+3,8,15,985,
+0,3,17,985,
+5,7,15,985,
+3,11,13,985,
+1,3,17,985,
+7,9,13,992,
+10,10,10,1003,
+2,10,14,1003,
+3,6,16,1003,
+6,11,12,1003,
+5,9,14,1003,
+2,3,17,1003,
+9,10,11,1013,
+4,12,12,1013,
+3,10,14,1013,
+0,4,17,1013,
+4,8,15,1013,
+0,7,16,1013,
+6,10,13,1013,
+4,11,13,1013,
+9,9,12,1025,
+5,5,16,1025,
+8,11,11,1025,
+0,9,15,1025,
+1,7,16,1025,
+1,4,17,1025,
+3,3,17,1025,
+1,9,15,1025,
+4,6,16,1025,
+8,10,12,1028,
+7,8,14,1028,
+2,7,16,1028,
+2,4,17,1028,
+2,9,15,1028,
+6,7,15,1028,
+4,10,14,1028,
+5,12,12,1035,
+6,9,14,1035,
+0,12,13,1035,
+8,9,13,1052,
+1,12,13,1052,
+0,5,17,1052,
+3,4,17,1052,
+3,7,16,1052,
+5,8,15,1052,
+7,11,12,1052,
+1,5,17,1052,
+5,11,13,1052,
+3,9,15,1052,
+2,12,13,1052,
+0,11,14,1052,
+5,6,16,1052,
+1,11,14,1052,
+2,5,17,1052,
+7,10,13,1065,
+0,8,16,1065,
+5,10,14,1065,
+2,11,14,1065,
+10,10,11,1085,
+4,4,17,1085,
+1,8,16,1085,
+4,7,16,1085,
+4,9,15,1085,
+3,12,13,1085,
+3,5,17,1085,
+7,7,15,1085,
+9,11,11,1098,
+2,8,16,1098,
+0,0,18,1098,
+6,12,12,1098,
+8,8,14,1098,
+0,1,18,1098,
+0,10,15,1098,
+6,8,15,1098,
+9,10,12,1107,
+0,6,17,1107,
+1,10,15,1107,
+7,9,14,1107,
+3,11,14,1107,
+1,6,17,1107,
+6,11,13,1107,
+1,1,18,1107,
+0,2,18,1107,
+6,6,16,1107,
+4,12,13,1107,
+2,6,17,1107,
+2,10,15,1107,
+1,2,18,1107,
+8,11,12,1115,
+3,8,16,1115,
+4,5,17,1115,
+5,7,16,1115,
+5,9,15,1115,
+9,9,13,1122,
+6,10,14,1122,
+2,2,18,1122,
+8,10,13,1129,
+4,11,14,1129,
+0,3,18,1129,
+1,3,18,1129,
+3,10,15,1129,
+3,6,17,1129,
+4,8,16,1129,
+2,3,18,1129,
+7,12,12,1140,
+0,9,16,1140,
+7,8,15,1140,
+0,13,13,1140,
+5,12,13,1140,
+1,9,16,1140,
+0,7,17,1140,
+1,7,17,1140,
+5,5,17,1140,
+7,11,13,1148,
+1,13,13,1148,
+0,12,14,1148,
+0,4,18,1148,
+8,9,14,1153,
+1,4,18,1153,
+4,10,15,1153,
+6,7,16,1153,
+1,12,14,1153,
+4,6,17,1153,
+2,9,16,1153,
+2,13,13,1153,
+5,11,14,1153,
+10,11,11,1167,
+6,9,15,1167,
+3,3,18,1167,
+2,7,17,1167,
+10,10,12,1172,
+2,4,18,1172,
+2,12,14,1172,
+5,8,16,1172,
+7,10,14,1172,
+0,11,15,1172,
+9,11,12,1186,
+3,9,16,1186,
+3,13,13,1186,
+1,11,15,1186,
+3,7,17,1186,
+0,5,18,1186,
+3,12,14,1186,
+6,12,13,1186,
+3,4,18,1186,
+1,5,18,1186,
+5,6,17,1186,
+5,10,15,1186,
+2,11,15,1186,
+9,10,13,1199,
+8,12,12,1206,
+0,8,17,1206,
+4,9,16,1206,
+8,8,15,1206,
+2,5,18,1206,
+6,11,14,1206,
+8,11,13,1217,
+4,13,13,1217,
+1,8,17,1217,
+4,7,17,1217,
+7,7,16,1217,
+7,9,15,1217,
+3,11,15,1217,
+4,4,18,1217,
+0,10,16,1217,
+6,8,16,1217,
+4,12,14,1217,
+1,10,16,1217,
+2,8,17,1217,
+3,5,18,1217,
+9,9,14,1226,
+0,6,18,1226,
+2,10,16,1226,
+8,10,14,1232,
+6,10,15,1232,
+6,6,17,1232,
+1,6,18,1232,
+0,0,19,1232,
+3,8,17,1232,
+7,12,13,1240,
+5,9,16,1240,
+0,1,19,1240,
+4,11,15,1240,
+5,7,17,1240,
+11,11,11,1256,
+1,1,19,1256,
+5,13,13,1256,
+2,6,18,1256,
+10,11,12,1264,
+0,2,19,1264,
+4,5,18,1264,
+5,12,14,1264,
+0,13,14,1264,
+3,10,16,1264,
+1,13,14,1264,
+1,2,19,1264,
+7,11,14,1264,
+0,12,15,1264,
+7,8,16,1264,
+2,13,14,1264,
+10,10,13,1275,
+9,12,12,1275,
+2,2,19,1275,
+3,6,18,1275,
+4,8,17,1275,
+0,9,17,1275,
+1,12,15,1275,
+8,9,15,1275,
+0,3,19,1275,
+9,11,13,1283,
+5,11,15,1283,
+1,9,17,1283,
+1,3,19,1283,
+4,10,16,1283,
+2,12,15,1283,
+0,7,18,1283,
+6,9,16,1283,
+6,13,13,1283,
+7,10,15,1283,
+1,7,18,1283,
+2,3,19,1283,
+2,9,17,1283,
+6,7,17,1283,
+5,5,18,1283,
+3,13,14,1283,
+6,12,14,1287,
+4,6,18,1287,
+0,4,19,1287,
+0,11,16,1287,
+8,12,13,1305,
+2,7,18,1305,
+9,10,14,1305,
+1,4,19,1305,
+5,8,17,1305,
+3,12,15,1305,
+1,11,16,1305,
+3,9,17,1305,
+3,3,19,1305,
+5,10,16,1305,
+8,11,14,1319,
+2,11,16,1319,
+4,13,14,1319,
+2,4,19,1319,
+3,7,18,1319,
+6,11,15,1319,
+8,8,16,1319,
+5,6,18,1319,
+4,12,15,1319,
+7,9,16,1322,
+3,4,19,1322,
+0,5,19,1322,
+3,11,16,1322,
+4,9,17,1322,
+11,11,12,1353,
+9,9,15,1353,
+7,13,13,1353,
+1,5,19,1353,
+7,7,17,1353,
+0,8,18,1353,
+10,12,12,1357,
+1,8,18,1357,
+0,10,17,1357,
+6,8,17,1357,
+7,12,14,1357,
+8,10,15,1357,
+4,7,18,1357,
+2,5,19,1357,
+5,13,14,1357,
+1,10,17,1357,
+10,11,13,1364,
+0,14,14,1364,
+6,10,16,1364,
+2,8,18,1364,
+1,14,14,1364,
+4,11,16,1364,
+2,10,17,1364,
+4,4,19,1364,
+5,12,15,1364,
+9,12,13,1378,
+0,13,15,1378,
+7,11,15,1378,
+1,13,15,1378,
+3,5,19,1378,
+5,9,17,1378,
+10,10,14,1380,
+2,14,14,1380,
+6,6,18,1380,
+3,8,18,1380,
+0,6,19,1380,
+1,6,19,1380,
+3,10,17,1380,
+9,11,14,1395,
+5,7,18,1395,
+2,13,15,1395,
+0,12,16,1395,
+0,0,20,1395,
+8,9,16,1395,
+1,12,16,1395,
+3,14,14,1395,
+0,1,20,1395,
+2,6,19,1395,
+6,13,14,1395,
+5,11,16,1395,
+1,1,20,1395,
+7,8,17,1395,
+8,13,13,1412,
+4,5,19,1412,
+3,13,15,1412,
+0,2,20,1412,
+4,8,18,1412,
+8,12,14,1414,
+2,12,16,1414,
+6,12,15,1414,
+1,2,20,1414,
+0,9,18,1414,
+4,10,17,1414,
+7,10,16,1414,
+9,10,15,1422,
+1,9,18,1422,
+3,6,19,1422,
+6,9,17,1422,
+2,2,20,1422,
+4,14,14,1422,
+0,3,20,1422,
+2,9,18,1422,
+11,12,12,1444,
+6,7,18,1444,
+3,12,16,1444,
+1,3,20,1444,
+0,11,17,1444,
+0,7,19,1444,
+8,11,15,1444,
+4,13,15,1444,
+5,5,19,1444,
+1,7,19,1444,
+11,11,13,1452,
+1,11,17,1452,
+4,6,19,1452,
+6,11,16,1452,
+10,12,13,1458,
+5,8,18,1458,
+2,3,20,1458,
+2,7,19,1458,
+2,11,17,1458,
+7,13,14,1458,
+5,10,17,1458,
+3,9,18,1458,
+0,4,20,1458,
+4,12,16,1458,
+10,11,14,1476,
+1,4,20,1476,
+8,8,17,1476,
+5,14,14,1476,
+3,3,20,1476,
+7,12,15,1476,
+9,9,16,1476,
+3,7,19,1476,
+5,13,15,1476,
+9,13,13,1483,
+7,9,17,1483,
+3,11,17,1483,
+2,4,20,1483,
+8,10,16,1483,
+4,9,18,1483,
+9,12,14,1487,
+0,14,15,1487,
+5,6,19,1487,
+1,14,15,1487,
+7,7,18,1487,
+6,8,18,1487,
+0,10,18,1487,
+6,10,17,1487,
+0,13,16,1487,
+0,8,19,1487,
+0,5,20,1487,
+2,14,15,1487,
+5,12,16,1487,
+1,10,18,1487,
+3,4,20,1487,
+10,10,15,1496,
+7,11,16,1496,
+4,11,17,1496,
+1,13,16,1496,
+1,5,20,1496,
+4,7,19,1496,
+1,8,19,1496,
+9,11,15,1507,
+2,10,18,1507,
+6,14,14,1507,
+8,13,14,1517,
+2,8,19,1517,
+2,13,16,1517,
+2,5,20,1517,
+3,14,15,1517,
+5,9,18,1517,
+6,13,15,1517,
+12,12,12,1545,
+4,4,20,1545,
+8,12,15,1545,
+0,12,17,1545,
+6,6,19,1545,
+3,10,18,1545,
+1,12,17,1545,
+8,9,17,1545,
+11,12,13,1554,
+3,13,16,1554,
+3,8,19,1554,
+3,5,20,1554,
+5,11,17,1554,
+5,7,19,1554,
+0,6,20,1554,
+6,12,16,1554,
+4,14,15,1554,
+2,12,17,1554,
+1,6,20,1554,
+7,8,18,1554,
+9,10,16,1554,
+10,13,13,1572,
+7,10,17,1572,
+11,11,14,1572,
+4,10,18,1572,
+2,6,20,1572,
+10,12,14,1578,
+4,5,20,1578,
+6,9,18,1578,
+4,8,19,1578,
+4,13,16,1578,
+8,11,16,1578,
+7,14,14,1578,
+0,0,21,1578,
+0,1,21,1578,
+0,9,19,1578,
+3,12,17,1578,
+7,13,15,1578,
+1,9,19,1578,
+1,1,21,1578,
+0,11,18,1578,
+3,6,20,1578,
+0,2,21,1578,
+9,13,14,1598,
+2,9,19,1598,
+5,14,15,1598,
+1,2,21,1598,
+10,11,15,1598,
+1,11,18,1598,
+6,11,17,1598,
+6,7,19,1598,
+5,10,18,1598,
+4,12,17,1598,
+7,12,16,1598,
+2,11,18,1598,
+2,2,21,1598,
+0,7,20,1598,
+1,7,20,1598,
+9,12,15,1612,
+5,5,20,1612,
+0,15,15,1612,
+5,8,19,1612,
+0,3,21,1612,
+5,13,16,1612,
+9,9,17,1612,
+1,15,15,1612,
+1,3,21,1612,
+3,9,19,1612,
+0,14,16,1612,
+8,8,18,1612,
+4,6,20,1612,
+2,7,20,1612,
+8,10,17,1612,
+1,14,16,1612,
+2,15,15,1612,
+7,9,18,1612,
+3,11,18,1612,
+2,3,21,1612,
+8,14,14,1632,
+10,10,16,1632,
+2,14,16,1632,
+0,4,21,1632,
+6,14,15,1632,
+12,12,13,1650,
+3,7,20,1650,
+4,9,19,1650,
+1,4,21,1650,
+8,13,15,1650,
+5,12,17,1650,
+0,13,17,1650,
+9,11,16,1650,
+3,15,15,1650,
+7,11,17,1650,
+7,7,19,1650,
+3,3,21,1650,
+1,13,17,1650,
+11,13,13,1656,
+6,10,18,1656,
+6,13,16,1656,
+2,4,21,1656,
+3,14,16,1656,
+11,12,14,1666,
+5,6,20,1666,
+6,8,19,1666,
+0,10,19,1666,
+4,11,18,1666,
+2,13,17,1666,
+1,10,19,1666,
+8,12,16,1666,
+0,8,20,1666,
+1,8,20,1666,
+4,7,20,1666,
+10,13,14,1674,
+2,10,19,1674,
+0,5,21,1674,
+3,4,21,1674,
+4,15,15,1674,
+3,13,17,1674,
+1,5,21,1674,
+5,9,19,1674,
+11,11,15,1688,
+4,14,16,1688,
+2,8,20,1688,
+0,12,18,1688,
+10,12,15,1700,
+1,12,18,1700,
+6,12,17,1700,
+8,9,18,1700,
+7,14,15,1700,
+2,5,21,1700,
+9,10,17,1700,
+5,11,18,1700,
+3,10,19,1700,
+2,12,18,1700,
+6,6,20,1700,
+9,14,14,1713,
+4,4,21,1713,
+7,10,18,1713,
+3,8,20,1713,
+5,7,20,1713,
+4,13,17,1713,
+7,13,16,1713,
+7,8,19,1713,
+8,11,17,1713,
+3,5,21,1713,
+9,13,15,1722,
+5,15,15,1722,
+10,11,16,1726,
+0,6,21,1726,
+5,14,16,1726,
+4,10,19,1726,
+3,12,18,1726,
+1,6,21,1726,
+6,9,19,1726,
+4,8,20,1726,
+0,15,16,1726,
+9,12,16,1740,
+0,9,20,1740,
+2,6,21,1740,
+6,11,18,1740,
+12,13,13,1760,
+7,12,17,1760,
+1,9,20,1760,
+1,15,16,1760,
+0,11,19,1760,
+4,5,21,1760,
+1,11,19,1760,
+5,13,17,1760,
+12,12,14,1764,
+4,12,18,1764,
+0,0,22,1764,
+8,14,15,1764,
+2,9,20,1764,
+0,1,22,1764,
+6,7,20,1764,
+0,14,17,1764,
+2,15,16,1764,
+1,1,22,1764,
+9,9,18,1764,
+5,10,19,1764,
+3,6,21,1764,
+6,15,15,1764,
+2,11,19,1764,
+11,13,14,1779,
+1,14,17,1779,
+0,2,22,1779,
+6,14,16,1779,
+8,10,18,1779,
+2,14,17,1779,
+1,2,22,1779,
+10,10,17,1779,
+8,13,16,1779,
+8,8,19,1779,
+5,8,20,1779,
+3,15,16,1779,
+3,9,20,1779,
+11,12,15,1795,
+0,7,21,1795,
+5,5,21,1795,
+7,9,19,1795,
+3,11,19,1795,
+9,11,17,1795,
+1,7,21,1795,
+10,14,14,1798,
+2,2,22,1798,
+0,3,22,1798,
+5,12,18,1798,
+0,13,18,1798,
+4,6,21,1798,
+3,14,17,1798,
+6,13,17,1798,
+10,13,15,1807,
+2,7,21,1807,
+7,11,18,1807,
+1,13,18,1807,
+1,3,22,1807,
+2,3,22,1807,
+6,10,19,1807,
+4,15,16,1807,
+8,12,17,1807,
+4,9,20,1807,
+2,13,18,1807,
+7,7,20,1807,
+11,11,16,1826,
+4,11,19,1826,
+7,15,15,1826,
+3,7,21,1826,
+6,8,20,1826,
+0,4,22,1826,
+0,10,20,1826,
+10,12,16,1829,
+1,10,20,1829,
+4,14,17,1829,
+1,4,22,1829,
+7,14,16,1829,
+3,13,18,1829,
+3,3,22,1829,
+5,6,21,1829,
+9,14,15,1843,
+6,12,18,1843,
+2,10,20,1843,
+2,4,22,1843,
+0,12,19,1843,
+9,10,18,1843,
+0,8,21,1843,
+5,9,20,1843,
+1,8,21,1843,
+9,13,16,1851,
+5,15,16,1851,
+1,12,19,1851,
+8,9,19,1851,
+4,7,21,1851,
+5,11,19,1851,
+13,13,13,1869,
+7,13,17,1869,
+2,12,19,1869,
+3,10,20,1869,
+4,13,18,1869,
+3,4,22,1869,
+12,13,14,1880,
+8,11,18,1880,
+0,5,22,1880,
+2,8,21,1880,
+7,10,19,1880,
+1,5,22,1880,
+10,11,17,1880,
+5,14,17,1880,
+0,16,16,1880,
+7,8,20,1880,
+12,12,15,1896,
+6,6,21,1896,
+1,16,16,1896,
+11,14,14,1896,
+2,5,22,1896,
+0,15,17,1896,
+8,15,15,1896,
+9,12,17,1896,
+3,12,19,1896,
+3,8,21,1896,
+11,13,15,1902,
+5,7,21,1902,
+1,15,17,1902,
+2,16,16,1902,
+4,10,20,1902,
+4,4,22,1902,
+8,14,16,1902,
+6,9,20,1902,
+6,15,16,1902,
+7,12,18,1902,
+3,5,22,1902,
+5,13,18,1902,
+2,15,17,1902,
+6,11,19,1902,
+0,14,18,1902,
+0,6,22,1902,
+11,12,16,1930,
+4,8,21,1930,
+4,12,19,1930,
+0,11,20,1930,
+1,14,18,1930,
+10,14,15,1930,
+6,14,17,1930,
+3,16,16,1930,
+1,6,22,1930,
+1,11,20,1930,
+8,13,17,1930,
+0,9,21,1930,
+1,9,21,1930,
+9,9,19,1930,
+3,15,17,1930,
+2,14,18,1930,
+2,6,22,1930,
+10,10,18,1930,
+2,11,20,1930,
+4,5,22,1930,
+5,10,20,1930,
+10,13,16,1947,
+8,10,19,1947,
+9,11,18,1947,
+2,9,21,1947,
+6,7,21,1947,
+4,16,16,1947,
+8,8,20,1947,
+3,14,18,1947,
+0,0,23,1947,
+3,6,22,1947,
+6,13,18,1947,
+7,15,16,1950,
+7,9,20,1950,
+5,12,19,1950,
+4,15,17,1950,
+0,1,23,1950,
+0,13,19,1950,
+5,8,21,1950,
+3,11,20,1950,
+11,11,17,1970,
+9,15,15,1970,
+3,9,21,1970,
+7,11,19,1970,
+1,13,19,1970,
+1,1,23,1970,
+8,12,18,1970,
+10,12,17,1979,
+9,14,16,1979,
+0,7,22,1979,
+0,2,23,1979,
+2,13,19,1979,
+1,7,22,1979,
+1,2,23,1979,
+13,13,14,1997,
+7,14,17,1997,
+5,5,22,1997,
+4,6,22,1997,
+4,14,18,1997,
+12,14,14,2002,
+6,10,20,2002,
+2,2,23,2002,
+4,11,20,2002,
+2,7,22,2002,
+5,16,16,2002,
+0,3,23,2002,
+12,13,15,2013,
+4,9,21,2013,
+3,13,19,2013,
+9,13,17,2013,
+1,3,23,2013,
+7,7,21,2013,
+5,15,17,2013,
+6,8,21,2013,
+0,10,21,2013,
+6,12,19,2013,
+1,10,21,2013,
+11,14,15,2028,
+3,7,22,2028,
+7,13,18,2028,
+9,10,19,2028,
+2,3,23,2028,
+12,12,16,2033,
+0,12,20,2033,
+1,12,20,2033,
+0,16,17,2033,
+0,4,23,2033,
+5,14,18,2033,
+8,9,20,2033,
+8,15,16,2033,
+10,11,18,2033,
+2,10,21,2033,
+5,6,22,2033,
+8,11,19,2033,
+1,4,23,2033,
+5,11,20,2033,
+1,16,17,2033,
+11,13,16,2040,
+4,13,19,2040,
+5,9,21,2040,
+3,3,23,2040,
+2,12,20,2040,
+6,16,16,2040,
+0,8,22,2040,
+9,12,18,2040,
+4,7,22,2040,
+1,8,22,2040,
+0,15,18,2040,
+8,14,17,2040,
+2,4,23,2040,
+2,16,17,2040,
+7,10,20,2040,
+10,15,15,2052,
+6,15,17,2052,
+1,15,18,2052,
+3,10,21,2052,
+2,8,22,2052,
+10,14,16,2058,
+2,15,18,2058,
+3,12,20,2058,
+11,12,17,2074,
+0,5,23,2074,
+3,4,23,2074,
+7,8,21,2074,
+7,12,19,2074,
+3,16,17,2074,
+1,5,23,2074,
+5,13,19,2074,
+6,6,22,2074,
+6,14,18,2074,
+8,13,18,2074,
+3,8,22,2074,
+4,10,21,2074,
+0,14,19,2074,
+6,11,20,2074,
+5,7,22,2074,
+3,15,18,2074,
+6,9,21,2074,
+10,13,17,2090,
+1,14,19,2090,
+2,5,23,2090,
+4,12,20,2090,
+4,16,17,2090,
+2,14,19,2090,
+13,14,14,2118,
+10,10,19,2118,
+4,4,23,2118,
+7,16,16,2118,
+9,15,16,2118,
+9,9,20,2118,
+0,11,21,2118,
+7,15,17,2118,
+3,5,23,2118,
+1,11,21,2118,
+9,11,19,2118,
+13,13,15,2128,
+8,10,20,2128,
+4,8,22,2128,
+0,6,23,2128,
+4,15,18,2128,
+0,9,22,2128,
+12,14,15,2139,
+5,10,21,2139,
+1,9,22,2139,
+1,6,23,2139,
+2,11,21,2139,
+3,14,19,2139,
+9,14,17,2139,
+6,13,19,2139,
+11,11,18,2139,
+10,12,18,2139,
+6,7,22,2139,
+8,12,19,2139,
+2,9,22,2139,
+2,6,23,2139,
+5,12,20,2139,
+12,13,16,2149,
+8,8,21,2149,
+7,14,18,2149,
+0,13,20,2149,
+4,5,23,2149,
+7,11,20,2149,
+5,16,17,2149,
+1,13,20,2149,
+7,9,21,2149,
+3,11,21,2149,
+11,15,15,2162,
+5,8,22,2162,
+4,14,19,2162,
+2,13,20,2162,
+11,14,16,2172,
+3,9,22,2172,
+5,15,18,2172,
+3,6,23,2172,
+9,13,18,2172,
+8,16,16,2172,
+0,0,24,2172,
+6,10,21,2172,
+12,12,17,2182,
+0,1,24,2182,
+0,7,23,2182,
+8,15,17,2182,
+1,1,24,2182,
+4,11,21,2182,
+0,17,17,2182,
+3,13,20,2182,
+5,5,23,2182,
+7,13,19,2182,
+1,7,23,2182,
+1,17,17,2182,
+11,13,17,2194,
+0,16,18,2194,
+6,12,20,2194,
+0,2,24,2194,
+1,16,18,2194,
+10,15,16,2201,
+6,16,17,2201,
+9,10,20,2201,
+4,6,23,2201,
+1,2,24,2201,
+4,9,22,2201,
+7,7,22,2201,
+2,7,23,2201,
+10,11,19,2201,
+2,17,17,2201,
+5,14,19,2201,
+2,2,24,2201,
+8,14,18,2201,
+2,16,18,2201,
+6,8,22,2201,
+0,10,22,2201,
+0,3,24,2201,
+6,15,18,2201,
+0,12,21,2201,
+1,10,22,2201,
+10,14,17,2219,
+8,11,20,2219,
+4,13,20,2219,
+9,12,19,2219,
+1,12,21,2219,
+1,3,24,2219,
+0,15,19,2219,
+8,9,21,2219,
+3,17,17,2219,
+3,7,23,2219,
+5,11,21,2219,
+1,15,19,2219,
+14,14,14,2237,
+2,10,22,2237,
+2,3,24,2237,
+3,16,18,2237,
+11,12,18,2237,
+2,12,21,2237,
+13,14,15,2251,
+5,6,23,2251,
+5,9,22,2251,
+2,15,19,2251,
+7,10,21,2251,
+0,4,24,2251,
+10,13,18,2251,
+3,10,22,2251,
+6,14,19,2251,
+1,4,24,2251,
+0,8,23,2251,
+7,12,20,2251,
+9,16,16,2251,
+4,17,17,2251,
+3,12,21,2251,
+8,13,19,2251,
+13,13,16,2273,
+5,13,20,2273,
+3,3,24,2273,
+7,16,17,2273,
+12,15,15,2273,
+1,8,23,2273,
+4,7,23,2273,
+3,15,19,2273,
+9,15,17,2273,
+2,4,24,2273,
+12,14,16,2279,
+4,16,18,2279,
+0,14,20,2279,
+1,14,20,2279,
+7,8,22,2279,
+2,8,23,2279,
+7,15,18,2279,
+6,11,21,2279,
+4,10,22,2279,
+2,14,20,2279,
+10,10,20,2279,
+9,14,18,2283,
+3,4,24,2283,
+6,9,22,2283,
+0,5,24,2283,
+4,12,21,2283,
+6,6,23,2283,
+1,5,24,2283,
+4,15,19,2283,
+11,15,16,2306,
+3,8,23,2306,
+12,13,17,2306,
+9,11,20,2306,
+9,9,21,2306,
+11,11,19,2306,
+5,7,23,2306,
+5,17,17,2306,
+10,12,19,2306,
+5,16,18,2306,
+0,11,22,2306,
+2,5,24,2306,
+8,10,21,2306,
+3,14,20,2306,
+6,13,20,2306,
+11,14,17,2318,
+1,11,22,2318,
+7,14,19,2318,
+8,12,20,2318,
+4,4,24,2318,
+8,16,17,2318,
+2,11,22,2318,
+4,8,23,2318,
+5,10,22,2318,
+0,13,21,2318,
+0,9,23,2318,
+3,5,24,2318,
+5,12,21,2318,
+1,13,21,2318,
+5,15,19,2318,
+1,9,23,2318,
+9,13,19,2321,
+7,11,21,2321,
+8,8,22,2321,
+10,16,16,2340,
+12,12,18,2340,
+0,6,24,2340,
+4,14,20,2340,
+0,17,18,2340,
+8,15,18,2340,
+1,6,24,2340,
+10,15,17,2354,
+2,13,21,2354,
+3,11,22,2354,
+6,17,17,2354,
+11,13,18,2354,
+6,7,23,2354,
+2,9,23,2354,
+7,9,22,2354,
+1,17,18,2354,
+2,6,24,2354,
+6,16,18,2354,
+0,16,19,2354,
+14,14,15,2382,
+2,17,18,2382,
+4,5,24,2382,
+1,16,19,2382,
+5,8,23,2382,
+7,13,20,2382,
+13,15,15,2392,
+3,9,23,2392,
+3,13,21,2392,
+10,14,18,2392,
+6,10,22,2392,
+3,6,24,2392,
+2,16,19,2392,
+13,14,16,2400,
+4,11,22,2400,
+10,11,20,2400,
+6,12,21,2400,
+8,14,19,2400,
+5,14,20,2400,
+3,17,18,2400,
+9,10,21,2400,
+6,15,19,2400,
+0,15,20,2400,
+12,15,16,2418,
+0,0,25,2418,
+9,12,20,2418,
+0,7,24,2418,
+1,15,20,2418,
+4,9,23,2418,
+1,7,24,2418,
+5,5,24,2418,
+11,12,19,2418,
+4,13,21,2418,
+8,11,21,2418,
+9,16,17,2418,
+0,1,25,2418,
+3,16,19,2418,
+13,13,17,2431,
+7,17,17,2431,
+1,1,25,2431,
+7,7,23,2431,
+4,6,24,2431,
+0,12,22,2431,
+6,8,23,2431,
+12,14,17,2436,
+7,16,18,2436,
+0,10,23,2436,
+8,9,22,2436,
+2,7,24,2436,
+2,15,20,2436,
+0,2,25,2436,
+4,17,18,2436,
+1,12,22,2436,
+10,13,19,2436,
+1,2,25,2436,
+1,10,23,2436,
+5,11,22,2436,
+9,15,18,2436,
+2,12,22,2436,
+6,14,20,2436,
+2,2,25,2436,
+11,16,16,2445,
+7,10,22,2445,
+4,16,19,2445,
+2,10,23,2445,
+8,13,20,2445,
+7,12,21,2445,
+3,15,20,2445,
+0,3,25,2445,
+3,7,24,2445,
+5,13,21,2445,
+11,15,17,2458,
+5,9,23,2458,
+7,15,19,2458,
+1,3,25,2458,
+3,12,22,2458,
+0,14,21,2458,
+12,13,18,2469,
+5,6,24,2469,
+2,3,25,2469,
+3,10,23,2469,
+1,14,21,2469,
+9,14,19,2469,
+5,17,18,2469,
+0,8,24,2469,
+11,14,18,2488,
+1,8,24,2488,
+4,7,24,2488,
+0,4,25,2488,
+10,10,21,2488,
+6,11,22,2488,
+4,15,20,2488,
+2,14,21,2488,
+1,4,25,2488,
+7,8,23,2488,
+11,11,20,2488,
+5,16,19,2488,
+8,17,17,2488,
+3,3,25,2488,
+9,11,21,2488,
+4,12,22,2488,
+8,16,18,2488,
+2,8,24,2488,
+10,12,20,2488,
+7,14,20,2488,
+2,4,25,2488,
+4,10,23,2488,
+10,16,17,2501,
+6,13,21,2501,
+14,15,15,2520,
+6,9,23,2520,
+9,9,22,2520,
+3,14,21,2520,
+14,14,16,2529,
+6,6,24,2529,
+8,10,22,2529,
+0,18,18,2529,
+12,12,19,2529,
+10,15,18,2529,
+8,12,21,2529,
+3,8,24,2529,
+6,17,18,2529,
+1,18,18,2529,
+0,17,19,2529,
+13,15,16,2537,
+5,7,24,2537,
+0,5,25,2537,
+3,4,25,2537,
+0,11,23,2537,
+9,13,20,2537,
+5,15,20,2537,
+8,15,19,2537,
+1,5,25,2537,
+1,17,19,2537,
+11,13,19,2537,
+1,11,23,2537,
+2,18,18,2537,
+6,16,19,2537,
+5,12,22,2537,
+4,14,21,2537,
+0,13,22,2537,
+2,11,23,2537,
+5,10,23,2537,
+13,14,17,2551,
+2,5,25,2551,
+7,11,22,2551,
+1,13,22,2551,
+2,17,19,2551,
+0,16,20,2551,
+12,16,16,2557,
+4,8,24,2557,
+2,13,22,2557,
+1,16,20,2557,
+10,14,19,2557,
+8,8,23,2557,
+0,9,24,2557,
+4,4,25,2557,
+3,18,18,2557,
+12,15,17,2576,
+1,9,24,2576,
+9,17,17,2576,
+7,9,23,2576,
+3,5,25,2576,
+7,13,21,2576,
+3,11,23,2576,
+3,17,19,2576,
+8,14,20,2576,
+2,16,20,2576,
+6,7,24,2576,
+0,6,25,2576,
+2,9,24,2576,
+6,15,20,2576,
+9,16,18,2576,
+10,11,21,2576,
+13,13,18,2593,
+7,17,18,2593,
+5,14,21,2593,
+1,6,25,2593,
+3,13,22,2593,
+4,18,18,2593,
+12,14,18,2600,
+6,12,22,2600,
+5,8,24,2600,
+2,6,25,2600,
+6,10,23,2600,
+3,16,20,2600,
+11,12,20,2600,
+9,10,22,2600,
+4,17,19,2600,
+9,12,21,2600,
+3,9,24,2600,
+7,16,19,2600,
+4,5,25,2600,
+4,11,23,2600,
+11,16,17,2614,
+0,15,21,2614,
+1,15,21,2614,
+9,15,19,2614,
+8,11,22,2614,
+10,13,20,2614,
+4,13,22,2614,
+2,15,21,2614,
+11,15,18,2629,
+3,6,25,2629,
+4,16,20,2629,
+4,9,24,2629,
+6,14,21,2629,
+0,12,23,2629,
+5,18,18,2629,
+12,13,19,2641,
+8,9,23,2641,
+1,12,23,2641,
+7,15,20,2641,
+8,13,21,2641,
+0,7,25,2641,
+7,7,24,2641,
+1,7,25,2641,
+5,11,23,2641,
+5,5,25,2641,
+5,17,19,2641,
+3,15,21,2641,
+15,15,15,2666,
+6,8,24,2666,
+0,0,26,2666,
+0,10,24,2666,
+9,14,20,2666,
+4,6,25,2666,
+0,1,26,2666,
+7,12,22,2666,
+2,12,23,2666,
+14,15,16,2676,
+1,10,24,2676,
+8,17,18,2676,
+5,13,22,2676,
+11,14,19,2676,
+1,1,26,2676,
+2,7,25,2676,
+10,17,17,2676,
+7,10,23,2676,
+10,16,18,2676,
+0,2,26,2676,
+2,10,24,2676,
+0,14,22,2676,
+5,16,20,2676,
+13,16,16,2690,
+1,14,22,2690,
+8,16,19,2690,
+1,2,26,2690,
+14,14,17,2690,
+3,12,23,2690,
+4,15,21,2690,
+5,9,24,2690,
+3,7,25,2690,
+13,15,17,2701,
+11,11,21,2701,
+2,14,22,2701,
+10,10,22,2701,
+6,18,18,2701,
+2,2,26,2701,
+3,10,24,2701,
+0,18,19,2701,
+10,12,21,2701,
+0,3,26,2701,
+7,14,21,2701,
+1,3,26,2701,
+10,15,19,2701,
+6,17,19,2701,
+9,11,22,2701,
+1,18,19,2701,
+5,6,25,2701,
+6,11,23,2701,
+12,12,20,2704,
+6,13,22,2704,
+4,12,23,2704,
+8,15,20,2704,
+12,16,17,2723,
+7,8,24,2723,
+0,17,20,2723,
+2,3,26,2723,
+13,14,18,2723,
+3,14,22,2723,
+0,8,25,2723,
+2,18,19,2723,
+11,13,20,2723,
+1,8,25,2723,
+1,17,20,2723,
+4,7,25,2723,
+9,9,23,2723,
+9,13,21,2723,
+5,15,21,2723,
+6,16,20,2723,
+0,4,26,2723,
+4,10,24,2723,
+8,12,22,2723,
+2,8,25,2723,
+12,15,18,2744,
+1,4,26,2744,
+2,17,20,2744,
+6,9,24,2744,
+8,10,23,2744,
+3,3,26,2744,
+9,17,18,2744,
+3,18,19,2744,
+10,14,20,2744,
+4,14,22,2744,
+2,4,26,2744,
+6,6,25,2744,
+0,11,24,2744,
+0,16,21,2744,
+7,18,18,2744,
+1,16,21,2744,
+0,13,23,2744,
+1,11,24,2744,
+3,17,20,2744,
+3,8,25,2744,
+5,12,23,2744,
+9,16,19,2749,
+13,13,19,2770,
+7,17,19,2770,
+11,17,17,2770,
+1,13,23,2770,
+5,7,25,2770,
+7,11,23,2770,
+8,14,21,2770,
+4,18,19,2770,
+2,16,21,2770,
+3,4,26,2770,
+0,5,26,2770,
+2,11,24,2770,
+12,14,19,2777,
+11,16,18,2777,
+5,10,24,2777,
+6,15,21,2777,
+7,13,22,2777,
+1,5,26,2777,
+2,13,23,2777,
+8,8,24,2777,
+2,5,26,2777,
+7,16,20,2777,
+10,11,22,2777,
+4,8,25,2777,
+4,17,20,2777,
+5,14,22,2777,
+3,11,24,2777,
+9,15,20,2784,
+15,15,16,2820,
+3,16,21,2820,
+7,9,24,2820,
+0,9,25,2820,
+11,12,21,2820,
+3,13,23,2820,
+1,9,25,2820,
+11,15,19,2820,
+4,4,26,2820,
+14,16,16,2823,
+0,15,22,2823,
+9,12,22,2823,
+6,12,23,2823,
+5,18,19,2823,
+6,7,25,2823,
+2,9,25,2823,
+9,10,23,2823,
+10,13,21,2823,
+3,5,26,2823,
+14,15,17,2837,
+1,15,22,2837,
+6,10,24,2837,
+0,6,26,2837,
+8,18,18,2837,
+4,11,24,2837,
+12,13,20,2837,
+2,15,22,2837,
+1,6,26,2837,
+4,16,21,2837,
+10,17,18,2837,
+13,16,17,2857,
+5,17,20,2857,
+4,13,23,2857,
+8,11,23,2857,
+8,17,19,2857,
+5,8,25,2857,
+7,15,21,2857,
+3,9,25,2857,
+6,14,22,2857,
+2,6,26,2857,
+14,14,18,2859,
+8,13,22,2859,
+10,16,19,2859,
+11,14,20,2859,
+4,5,26,2859,
+13,15,18,2873,
+3,15,22,2873,
+9,14,21,2873,
+8,16,20,2873,
+0,12,24,2873,
+8,9,24,2873,
+1,12,24,2873,
+6,18,19,2873,
+3,6,26,2873,
+4,9,25,2873,
+7,12,23,2873,
+12,17,17,2891,
+5,11,24,2891,
+5,16,21,2891,
+0,19,19,2891,
+7,7,25,2891,
+1,19,19,2891,
+5,13,23,2891,
+0,18,20,2891,
+12,16,18,2896,
+2,12,24,2896,
+6,17,20,2896,
+6,8,25,2896,
+0,10,25,2896,
+10,15,20,2896,
+7,10,24,2896,
+0,14,23,2896,
+4,15,22,2896,
+1,18,20,2896,
+0,7,26,2896,
+5,5,26,2896,
+1,7,26,2896,
+2,19,19,2896,
+13,14,19,2907,
+1,14,23,2907,
+1,10,25,2907,
+11,11,22,2907,
+4,6,26,2907,
+2,18,20,2907,
+10,12,22,2907,
+9,18,18,2907,
+12,12,21,2907,
+2,7,26,2907,
+3,12,24,2907,
+2,10,25,2907,
+10,10,23,2907,
+7,14,22,2907,
+0,0,27,2907,
+2,14,23,2907,
+0,17,21,2907,
+8,15,21,2907,
+0,1,27,2907,
+12,15,19,2927,
+3,19,19,2927,
+5,9,25,2927,
+9,11,23,2927,
+9,17,19,2927,
+1,1,27,2927,
+1,17,21,2927,
+11,13,21,2927,
+6,16,21,2927,
+6,11,24,2927,
+3,18,20,2927,
+0,2,27,2927,
+11,17,18,2944,
+3,14,23,2944,
+6,13,23,2944,
+7,18,19,2944,
+3,10,25,2944,
+9,13,22,2944,
+3,7,26,2944,
+5,15,22,2944,
+2,17,21,2944,
+1,2,27,2944,
+4,12,24,2944,
+10,14,21,2944,
+9,16,20,2944,
+2,2,27,2944,
+15,16,16,2974,
+5,6,26,2974,
+8,12,23,2974,
+11,16,19,2974,
+4,19,19,2974,
+0,3,27,2974,
+9,9,24,2974,
+7,17,20,2974,
+13,13,20,2974,
+7,8,25,2974,
+15,15,17,2983,
+1,3,27,2983,
+3,17,21,2983,
+4,18,20,2983,
+0,8,26,2983,
+12,14,20,2983,
+8,10,24,2983,
+0,16,22,2983,
+4,14,23,2983,
+4,10,25,2983,
+1,8,26,2983,
+1,16,22,2983,
+4,7,26,2983,
+14,16,17,2996,
+2,3,27,2996,
+6,9,25,2996,
+8,14,22,2996,
+2,8,26,2996,
+2,16,22,2996,
+0,4,27,2996,
+14,15,18,3009,
+6,15,22,3009,
+5,12,24,3009,
+0,13,24,3009,
+1,4,27,3009,
+7,11,24,3009,
+1,13,24,3009,
+11,15,20,3009,
+4,17,21,3009,
+0,11,25,3009,
+7,16,21,3009,
+5,19,19,3009,
+3,3,27,3009,
+9,15,21,3009,
+7,13,23,3009,
+1,11,25,3009,
+13,17,17,3017,
+6,6,26,3017,
+10,18,18,3017,
+13,16,18,3024,
+3,8,26,3024,
+8,18,19,3024,
+5,18,20,3024,
+2,13,24,3024,
+2,4,27,3024,
+3,16,22,3024,
+11,12,22,3024,
+5,14,23,3024,
+2,11,25,3024,
+10,11,23,3024,
+5,7,26,3024,
+5,10,25,3024,
+10,17,19,3024,
+10,13,22,3024,
+14,14,19,3046,
+8,8,25,3046,
+8,17,20,3046,
+3,4,27,3046,
+9,12,23,3046,
+0,5,27,3046,
+0,15,23,3046,
+12,13,21,3046,
+3,13,24,3046,
+1,15,23,3046,
+3,11,25,3046,
+5,17,21,3046,
+13,15,19,3056,
+7,9,25,3056,
+1,5,27,3056,
+4,8,26,3056,
+10,16,20,3056,
+6,12,24,3056,
+4,16,22,3056,
+0,9,26,3056,
+12,17,18,3060,
+9,10,24,3060,
+6,19,19,3060,
+2,5,27,3060,
+1,9,26,3060,
+2,15,23,3060,
+11,14,21,3060,
+7,15,22,3060,
+6,18,20,3060,
+6,10,25,3060,
+4,13,24,3060,
+0,19,20,3060,
+2,9,26,3060,
+12,16,19,3069,
+6,7,26,3069,
+8,11,24,3069,
+6,14,23,3069,
+8,16,21,3069,
+4,4,27,3069,
+9,14,22,3069,
+8,13,23,3069,
+4,11,25,3069,
+1,19,20,3069,
+3,5,27,3069,
+3,15,23,3069,
+5,8,26,3069,
+0,6,27,3069,
+5,16,22,3069,
+13,14,20,3099,
+0,18,21,3099,
+2,19,20,3099,
+3,9,26,3099,
+1,6,27,3099,
+10,15,21,3099,
+9,18,19,3099,
+1,18,21,3099,
+6,17,21,3099,
+16,16,16,3133,
+7,12,24,3133,
+0,12,25,3133,
+11,18,18,3133,
+12,15,20,3133,
+2,18,21,3133,
+2,6,27,3133,
+1,12,25,3133,
+8,9,25,3133,
+5,13,24,3133,
+15,16,17,3145,
+3,19,20,3145,
+9,17,20,3145,
+4,5,27,3145,
+4,15,23,3145,
+5,11,25,3145,
+7,19,19,3145,
+11,17,19,3145,
+11,11,23,3145,
+12,12,22,3145,
+0,14,24,3145,
+8,15,22,3145,
+2,12,25,3145,
+10,12,23,3145,
+0,17,22,3145,
+1,14,24,3145,
+4,9,26,3145,
+7,18,20,3145,
+7,14,23,3145,
+7,7,26,3145,
+15,15,18,3160,
+11,13,22,3160,
+1,17,22,3160,
+14,17,17,3160,
+3,6,27,3160,
+7,10,25,3160,
+3,18,21,3160,
+14,16,18,3169,
+6,16,22,3169,
+2,14,24,3169,
+6,8,26,3169,
+10,10,24,3169,
+0,10,26,3169,
+11,16,20,3169,
+4,19,20,3169,
+1,10,26,3169,
+2,17,22,3169,
+9,11,24,3169,
+3,12,25,3169,
+0,7,27,3169,
+9,16,21,3169,
+7,17,21,3169,
+5,5,27,3169,
+1,7,27,3169,
+5,15,23,3169,
+13,13,21,3169,
+9,13,23,3169,
+10,14,22,3169,
+2,10,26,3169,
+12,14,21,3177,
+4,18,21,3177,
+6,13,24,3177,
+4,6,27,3177,
+3,14,24,3177,
+14,15,19,3203,
+5,9,26,3203,
+2,7,27,3203,
+6,11,25,3203,
+3,17,22,3203,
+13,17,18,3203,
+0,0,28,3203,
+8,12,24,3203,
+4,12,25,3203,
+0,16,23,3203,
+0,1,28,3203,
+10,18,19,3203,
+3,10,26,3203,
+8,19,19,3203,
+1,1,28,3203,
+13,16,19,3225,
+1,16,23,3225,
+5,19,20,3225,
+3,7,27,3225,
+9,9,25,3225,
+11,15,21,3225,
+4,14,24,3225,
+0,2,28,3225,
+8,18,20,3225,
+1,2,28,3225,
+8,14,23,3225,
+7,8,26,3225,
+8,10,25,3225,
+10,17,20,3225,
+4,17,22,3225,
+7,16,22,3225,
+2,16,23,3225,
+5,18,21,3225,
+9,15,22,3225,
+5,6,27,3225,
+6,15,23,3225,
+12,18,18,3243,
+14,14,20,3243,
+4,10,26,3243,
+2,2,28,3243,
+6,9,26,3243,
+0,3,28,3243,
+0,8,27,3243,
+1,8,27,3243,
+5,12,25,3243,
+3,16,23,3243,
+0,13,25,3243,
+8,17,21,3243,
+7,13,24,3243,
+4,7,27,3243,
+12,17,19,3254,
+13,15,20,3254,
+11,12,23,3254,
+1,3,28,3254,
+1,13,25,3254,
+7,11,25,3254,
+10,11,24,3254,
+6,19,20,3254,
+10,16,21,3254,
+12,13,22,3254,
+5,14,24,3254,
+2,3,28,3254,
+2,8,27,3254,
+0,11,26,3254,
+5,17,22,3254,
+2,13,25,3254,
+1,11,26,3254,
+10,13,23,3254,
+12,16,20,3279,
+0,4,28,3279,
+0,20,20,3279,
+1,4,28,3279,
+1,20,20,3279,
+4,16,23,3279,
+2,11,26,3279,
+9,12,24,3279,
+16,16,17,3294,
+0,15,24,3294,
+6,18,21,3294,
+11,14,22,3294,
+5,10,26,3294,
+6,6,27,3294,
+1,15,24,3294,
+3,8,27,3294,
+3,3,28,3294,
+0,19,21,3294,
+7,15,23,3294,
+9,19,19,3294,
+1,19,21,3294,
+5,7,27,3294,
+15,17,17,3309,
+3,13,25,3309,
+2,4,28,3309,
+2,20,20,3309,
+8,8,26,3309,
+8,16,22,3309,
+6,12,25,3309,
+9,18,20,3309,
+15,16,18,3317,
+2,15,24,3317,
+13,14,21,3317,
+2,19,21,3317,
+9,10,25,3317,
+7,9,26,3317,
+9,14,23,3317,
+11,18,19,3317,
+3,11,26,3317,
+6,14,24,3317,
+0,18,22,3317,
+3,4,28,3317,
+4,8,27,3317,
+1,18,22,3317,
+14,17,18,3337,
+3,20,20,3337,
+10,15,22,3337,
+6,17,22,3337,
+0,5,28,3337,
+8,13,24,3337,
+3,15,24,3337,
+7,19,20,3337,
+1,5,28,3337,
+12,15,21,3337,
+5,16,23,3337,
+4,13,25,3337,
+0,9,27,3337,
+11,17,20,3337,
+8,11,25,3337,
+3,19,21,3337,
+15,15,19,3349,
+9,17,21,3349,
+1,9,27,3349,
+6,10,26,3349,
+2,18,22,3349,
+14,16,19,3355,
+2,5,28,3355,
+4,11,26,3355,
+2,9,27,3355,
+6,7,27,3355,
+7,18,21,3355,
+4,20,20,3355,
+4,4,28,3355,
+12,12,23,3355,
+3,18,22,3355,
+4,15,24,3355,
+13,18,18,3376,
+3,5,28,3376,
+11,16,21,3376,
+7,12,25,3376,
+11,11,24,3376,
+5,8,27,3376,
+4,19,21,3376,
+0,17,23,3376,
+8,15,23,3376,
+13,17,19,3388,
+11,13,23,3388,
+3,9,27,3388,
+5,13,25,3388,
+1,17,23,3388,
+0,6,28,3388,
+0,12,26,3388,
+10,12,24,3388,
+7,14,24,3388,
+1,12,26,3388,
+1,6,28,3388,
+14,15,20,3401,
+0,14,25,3401,
+6,16,23,3401,
+9,16,22,3401,
+8,9,26,3401,
+1,14,25,3401,
+7,17,22,3401,
+13,13,22,3401,
+10,19,19,3401,
+5,11,26,3401,
+2,17,23,3401,
+4,18,22,3401,
+2,12,26,3401,
+10,18,20,3401,
+12,14,22,3401,
+2,6,28,3401,
+10,14,23,3401,
+5,20,20,3401,
+7,10,26,3401,
+4,5,28,3401,
+13,16,20,3411,
+2,14,25,3411,
+10,10,25,3411,
+8,19,20,3411,
+5,15,24,3411,
+4,9,27,3411,
+9,13,24,3411,
+5,19,21,3411,
+3,17,23,3411,
+9,11,25,3411,
+7,7,27,3411,
+3,12,26,3411,
+0,10,27,3411,
+8,18,21,3411,
+6,8,27,3411,
+3,6,28,3411,
+12,18,19,3435,
+3,14,25,3435,
+11,15,22,3435,
+10,17,21,3435,
+6,13,25,3435,
+1,10,27,3435,
+0,16,24,3435,
+1,16,24,3435,
+8,12,25,3435,
+12,17,20,3451,
+6,11,26,3451,
+5,18,22,3451,
+0,7,28,3451,
+14,14,21,3451,
+2,10,27,3451,
+16,17,17,3479,
+1,7,28,3479,
+5,5,28,3479,
+4,17,23,3479,
+7,16,23,3479,
+5,9,27,3479,
+13,15,21,3479,
+9,15,23,3479,
+4,12,26,3479,
+2,16,24,3479,
+4,6,28,3479,
+8,14,24,3479,
+6,20,20,3479,
+16,16,18,3481,
+6,15,24,3481,
+8,17,22,3481,
+2,7,28,3481,
+4,14,25,3481,
+3,10,27,3481,
+15,17,18,3500,
+6,19,21,3500,
+9,9,26,3500,
+8,10,26,3500,
+10,16,22,3500,
+0,0,29,3500,
+3,16,24,3500,
+0,20,21,3500,
+12,16,21,3500,
+11,12,24,3500,
+1,20,21,3500,
+15,16,19,3516,
+3,7,28,3516,
+7,8,27,3516,
+0,1,29,3516,
+12,13,23,3516,
+9,19,20,3516,
+11,19,19,3516,
+7,13,25,3516,
+5,17,23,3516,
+1,1,29,3516,
+6,18,22,3516,
+14,18,18,3519,
+0,19,22,3519,
+10,13,24,3519,
+5,6,28,3519,
+4,10,27,3519,
+5,12,26,3519,
+11,18,20,3519,
+0,13,26,3519,
+0,2,29,3519,
+2,20,21,3519,
+1,19,22,3519,
+7,11,26,3519,
+10,11,25,3519,
+14,17,19,3530,
+6,9,27,3530,
+1,2,29,3530,
+5,14,25,3530,
+9,18,21,3530,
+11,14,23,3530,
+1,13,26,3530,
+0,8,28,3530,
+4,16,24,3530,
+1,8,28,3530,
+2,19,22,3530,
+8,16,23,3530,
+4,7,28,3530,
+2,2,29,3530,
+13,14,22,3530,
+7,20,20,3530,
+2,13,26,3530,
+15,15,20,3553,
+9,12,25,3553,
+0,3,29,3553,
+0,15,25,3553,
+3,20,21,3553,
+0,11,27,3553,
+7,15,24,3553,
+1,11,27,3553,
+1,15,25,3553,
+7,19,21,3553,
+1,3,29,3553,
+11,17,21,3553,
+14,16,20,3558,
+2,8,28,3558,
+12,15,22,3558,
+9,14,24,3558,
+0,18,23,3558,
+3,13,26,3558,
+10,15,23,3558,
+1,18,23,3558,
+9,17,22,3558,
+2,11,27,3558,
+2,15,25,3558,
+13,18,19,3568,
+2,3,29,3568,
+3,19,22,3568,
+5,10,27,3568,
+6,17,23,3568,
+6,6,28,3568,
+6,12,26,3568,
+8,8,27,3568,
+4,20,21,3568,
+2,18,23,3568,
+0,4,29,3568,
+7,18,22,3568,
+6,14,25,3568,
+9,10,26,3568,
+3,8,28,3568,
+5,16,24,3568,
+8,13,25,3568,
+13,17,20,3594,
+5,7,28,3594,
+1,4,29,3594,
+7,9,27,3594,
+3,3,29,3594,
+3,11,27,3594,
+3,15,25,3594,
+4,19,22,3594,
+4,13,26,3594,
+11,16,22,3594,
+10,19,20,3594,
+2,4,29,3594,
+8,11,26,3594,
+14,15,21,3611,
+3,18,23,3611,
+8,20,20,3611,
+12,12,24,3611,
+4,8,28,3611,
+0,9,28,3611,
+0,17,24,3611,
+6,10,27,3611,
+8,15,24,3611,
+10,18,21,3611,
+9,16,23,3611,
+4,11,27,3611,
+0,5,29,3611,
+4,15,25,3611,
+12,19,19,3632,
+11,13,24,3632,
+5,20,21,3632,
+1,17,24,3632,
+13,16,21,3632,
+8,19,21,3632,
+3,4,29,3632,
+1,9,28,3632,
+13,13,23,3632,
+11,11,25,3632,
+1,5,29,3632,
+7,17,23,3632,
+17,17,17,3651,
+6,16,24,3651,
+12,18,20,3651,
+7,12,26,3651,
+12,14,23,3651,
+2,17,24,3651,
+10,12,25,3651,
+16,17,18,3659,
+4,18,23,3659,
+6,7,28,3659,
+2,9,28,3659,
+5,13,26,3659,
+7,14,25,3659,
+5,19,22,3659,
+2,5,29,3659,
+0,14,26,3659,
+8,18,22,3659,
+10,14,24,3659,
+16,16,19,3679,
+10,17,22,3679,
+4,4,29,3679,
+0,12,27,3679,
+5,8,28,3679,
+15,18,18,3679,
+1,14,26,3679,
+1,12,27,3679,
+12,17,21,3679,
+8,9,27,3679,
+3,9,28,3679,
+3,17,24,3679,
+5,15,25,3679,
+15,17,19,3692,
+9,13,25,3692,
+5,11,27,3692,
+11,15,23,3692,
+3,5,29,3692,
+14,14,22,3692,
+2,14,26,3692,
+10,10,26,3692,
+0,6,29,3692,
+2,12,27,3692,
+6,20,21,3692,
+13,15,22,3692,
+5,18,23,3692,
+7,10,27,3692,
+9,11,26,3692,
+1,6,29,3692,
+7,16,24,3692,
+4,17,24,3692,
+6,13,26,3692,
+9,20,20,3692,
+6,19,22,3692,
+3,14,26,3692,
+14,18,19,3718,
+2,6,29,3718,
+15,16,20,3718,
+0,16,25,3718,
+4,9,28,3718,
+1,16,25,3718,
+4,5,29,3718,
+0,21,21,3718,
+8,17,23,3718,
+3,12,27,3718,
+7,7,28,3718,
+9,15,24,3718,
+11,19,20,3718,
+1,21,21,3718,
+9,19,21,3718,
+0,20,22,3718,
+0,10,28,3718,
+6,8,28,3718,
+8,12,26,3718,
+12,16,22,3718,
+8,14,25,3718,
+10,16,23,3718,
+14,17,20,3739,
+1,20,22,3739,
+2,16,25,3739,
+1,10,28,3739,
+6,11,27,3739,
+6,15,25,3739,
+2,21,21,3739,
+3,6,29,3739,
+11,18,21,3739,
+4,14,26,3739,
+2,10,28,3739,
+2,20,22,3739,
+12,13,24,3739,
+6,18,23,3739,
+9,18,22,3739,
+4,12,27,3739,
+3,16,25,3739,
+5,9,28,3739,
+7,20,21,3739,
+0,19,23,3739,
+0,7,29,3739,
+11,12,25,3739,
+5,17,24,3739,
+1,19,23,3739,
+15,15,21,3770,
+3,21,21,3770,
+1,7,29,3770,
+5,5,29,3770,
+13,19,19,3770,
+9,9,27,3770,
+4,6,29,3770,
+13,18,20,3785,
+14,16,21,3785,
+3,20,22,3785,
+11,14,24,3785,
+8,10,27,3785,
+3,10,28,3785,
+7,13,26,3785,
+13,14,23,3785,
+10,13,25,3785,
+2,19,23,3785,
+2,7,29,3785,
+7,19,22,3785,
+11,17,22,3785,
+8,16,24,3785,
+4,16,25,3785,
+5,14,26,3785,
+10,11,26,3785,
+7,8,28,3785,
+5,12,27,3785,
+0,13,27,3785,
+4,21,21,3785,
+12,15,23,3789,
+13,17,21,3808,
+9,17,23,3808,
+7,11,27,3808,
+3,7,29,3808,
+7,15,25,3808,
+1,13,27,3808,
+3,19,23,3808,
+4,10,28,3808,
+4,20,22,3808,
+10,20,20,3808,
+0,0,30,3808,
+0,18,24,3808,
+6,9,28,3808,
+0,15,26,3808,
+6,17,24,3808,
+1,18,24,3808,
+9,12,26,3808,
+0,1,30,3808,
+10,15,24,3808,
+5,6,29,3808,
+17,17,18,3840,
+1,1,30,3840,
+10,19,21,3840,
+2,13,27,3840,
+7,18,23,3840,
+9,14,25,3840,
+1,15,26,3840,
+0,2,30,3840,
+16,18,18,3849,
+2,18,24,3849,
+1,2,30,3849,
+8,20,21,3849,
+14,15,22,3849,
+0,11,28,3849,
+12,19,20,3849,
+2,15,26,3849,
+0,8,29,3849,
+1,8,29,3849,
+11,16,23,3849,
+5,16,25,3849,
+1,11,28,3849,
+16,17,19,3865,
+4,19,23,3865,
+4,7,29,3865,
+3,13,27,3865,
+5,21,21,3865,
+2,2,30,3865,
+6,14,26,3865,
+10,18,22,3865,
+13,16,22,3865,
+2,11,28,3865,
+0,3,30,3865,
+6,12,27,3865,
+12,18,21,3865,
+8,19,22,3865,
+8,13,26,3865,
+3,18,24,3865,
+5,20,22,3865,
+5,10,28,3865,
+2,8,29,3865,
+3,15,26,3865,
+1,3,30,3865,
+15,18,19,3884,
+9,10,27,3884,
+8,8,28,3884,
+16,16,20,3890,
+9,16,24,3890,
+6,6,29,3890,
+2,3,30,3890,
+12,12,25,3890,
+15,17,20,3906,
+8,15,25,3906,
+7,9,28,3906,
+3,11,28,3906,
+4,13,27,3906,
+3,8,29,3906,
+7,17,24,3906,
+0,17,25,3906,
+8,11,27,3906,
+13,13,24,3906,
+5,7,29,3906,
+11,13,25,3906,
+1,17,25,3906,
+5,19,23,3906,
+0,4,30,3906,
+4,18,24,3906,
+12,14,24,3906,
+12,17,22,3906,
+4,15,26,3906,
+8,18,23,3906,
+6,16,25,3906,
+1,4,30,3906,
+11,11,26,3906,
+6,21,21,3906,
+3,3,30,3906,
+14,19,19,3916,
+10,17,23,3916,
+2,17,25,3916,
+10,12,26,3916,
+6,20,22,3916,
+14,18,20,3929,
+2,4,30,3929,
+6,10,28,3929,
+4,11,28,3929,
+11,20,20,3929,
+10,14,25,3929,
+4,8,29,3929,
+7,14,26,3929,
+14,14,23,3929,
+7,12,27,3929,
+15,16,21,3940,
+9,20,21,3940,
+0,9,29,3940,
+11,15,24,3940,
+5,13,27,3940,
+13,15,23,3940,
+3,17,25,3940,
+11,19,21,3940,
+1,9,29,3940,
+0,5,30,3940,
+0,14,27,3940,
+0,21,22,3940,
+5,18,24,3940,
+3,4,30,3940,
+9,13,26,3940,
+9,19,22,3940,
+5,15,26,3940,
+6,19,23,3940,
+1,5,30,3940,
+14,17,21,3958,
+1,14,27,3958,
+2,9,29,3958,
+6,7,29,3958,
+1,21,22,3958,
+0,12,28,3958,
+0,20,23,3958,
+2,5,30,3958,
+8,17,24,3958,
+12,16,23,3958,
+8,9,28,3958,
+1,12,28,3958,
+10,10,27,3958,
+11,18,22,3958,
+2,14,27,3958,
+2,21,22,3958,
+5,11,28,3958,
+1,20,23,3958,
+13,19,20,3970,
+5,8,29,3970,
+4,17,25,3970,
+7,16,25,3970,
+7,21,21,3970,
+3,9,29,3970,
+9,15,25,3970,
+9,11,27,3970,
+10,16,24,3970,
+0,16,26,3970,
+2,12,28,3970,
+4,4,30,3970,
+2,20,23,3970,
+1,16,26,3970,
+7,10,28,3970,
+7,20,22,3970,
+3,14,27,3970,
+3,5,30,3970,
+15,15,22,3992,
+6,13,27,3992,
+13,18,21,3992,
+9,18,23,3992,
+3,21,22,3992,
+2,16,26,3992,
+6,18,24,3992,
+14,16,22,4000,
+0,6,30,4000,
+8,14,26,4000,
+3,12,28,4000,
+0,19,24,4000,
+17,18,18,4035,
+1,6,30,4035,
+6,15,26,4035,
+8,12,27,4035,
+1,19,24,4035,
+3,20,23,4035,
+12,13,25,4035,
+4,9,29,4035,
+7,7,29,4035,
+5,17,25,4035,
+11,17,23,4035,
+7,19,23,4035,
+17,17,19,4042,
+2,6,30,4042,
+11,12,26,4042,
+13,14,24,4042,
+0,10,29,4042,
+4,14,27,4042,
+6,8,29,4042,
+10,20,21,4042,
+3,16,26,4042,
+2,19,24,4042,
+6,11,28,4042,
+4,21,22,4042,
+16,18,19,4051,
+4,5,30,4051,
+13,17,22,4051,
+11,14,25,4051,
+1,10,29,4051,
+12,20,20,4051,
+4,12,28,4051,
+8,16,25,4051,
+10,13,26,4051,
+12,15,24,4051,
+3,6,30,4051,
+2,10,29,4051,
+4,20,23,4051,
+16,17,20,4074,
+10,19,22,4074,
+12,19,21,4074,
+8,21,21,4074,
+9,9,28,4074,
+3,19,24,4074,
+9,17,24,4074,
+5,9,29,4074,
+15,19,19,4084,
+7,13,27,4084,
+4,16,26,4084,
+8,20,22,4084,
+8,10,28,4084,
+7,18,24,4084,
+0,18,25,4084,
+0,7,30,4084,
+15,18,20,4095,
+5,21,22,4095,
+7,15,26,4095,
+10,11,27,4095,
+10,15,25,4095,
+1,18,25,4095,
+5,14,27,4095,
+14,15,23,4095,
+5,5,30,4095,
+1,7,30,4095,
+6,17,25,4095,
+3,10,29,4095,
+12,18,22,4095,
+4,6,30,4095,
+9,14,26,4095,
+11,16,24,4095,
+2,7,30,4095,
+2,18,25,4095,
+16,16,21,4111,
+5,12,28,4111,
+10,18,23,4111,
+4,19,24,4111,
+0,13,28,4111,
+9,12,27,4111,
+13,16,23,4111,
+7,11,28,4111,
+8,19,23,4111,
+1,13,28,4111,
+5,20,23,4111,
+0,15,27,4111,
+7,8,29,4111,
+1,15,27,4111,
+15,17,21,4124,
+14,19,20,4136,
+4,10,29,4136,
+5,16,26,4136,
+2,13,28,4136,
+3,7,30,4136,
+6,9,29,4136,
+3,18,25,4136,
+2,15,27,4136,
+5,6,30,4136,
+6,21,22,4136,
+6,14,27,4136,
+0,0,31,4136,
+14,18,21,4148,
+0,1,31,4148,
+5,19,24,4148,
+11,20,21,4148,
+12,17,23,4148,
+8,13,27,4148,
+0,11,29,4148,
+3,13,28,4148,
+9,16,25,4148,
+7,17,25,4148,
+1,1,31,4148,
+9,21,21,4148,
+1,11,29,4148,
+3,15,27,4148,
+13,13,25,4148,
+6,12,28,4148,
+8,18,24,4148,
+12,12,26,4148,
+0,8,30,4148,
+6,20,23,4148,
+1,8,30,4148,
+9,10,28,4148,
+4,7,30,4148,
+10,17,24,4148,
+8,15,26,4148,
+9,20,22,4148,
+4,18,25,4148,
+15,16,22,4172,
+12,14,25,4172,
+0,2,31,4172,
+0,17,26,4172,
+11,13,26,4172,
+11,19,22,4172,
+1,17,26,4172,
+2,11,29,4172,
+5,10,29,4172,
+1,2,31,4172,
+2,8,30,4172,
+6,16,26,4172,
+14,14,24,4172,
+0,22,22,4172,
+13,20,20,4194,
+1,22,22,4194,
+2,2,31,4194,
+8,8,29,4194,
+14,17,22,4194,
+4,13,28,4194,
+8,11,28,4194,
+2,17,26,4194,
+0,3,31,4194,
+13,15,24,4194,
+4,15,27,4194,
+0,21,23,4194,
+13,19,21,4205,
+3,11,29,4205,
+11,11,27,4205,
+1,3,31,4205,
+1,21,23,4205,
+7,9,29,4205,
+11,15,25,4205,
+9,19,23,4205,
+2,22,22,4205,
+18,18,18,4219,
+6,6,30,4219,
+10,14,26,4219,
+10,12,27,4219,
+6,19,24,4219,
+3,8,30,4219,
+3,17,26,4219,
+7,21,22,4219,
+5,7,30,4219,
+2,21,23,4219,
+7,14,27,4219,
+2,3,31,4219,
+17,18,19,4231,
+11,18,23,4231,
+5,18,25,4231,
+12,16,24,4231,
+0,20,24,4231,
+1,20,24,4231,
+0,4,31,4231,
+6,10,29,4231,
+13,18,22,4231,
+7,12,28,4231,
+3,22,22,4231,
+5,13,28,4231,
+1,4,31,4231,
+7,20,23,4231,
+8,17,25,4231,
+4,11,29,4231,
+17,17,20,4260,
+16,19,19,4260,
+3,21,23,4260,
+5,15,27,4260,
+9,13,27,4260,
+15,15,23,4260,
+3,3,31,4260,
+0,14,28,4260,
+16,18,20,4263,
+2,20,24,4263,
+4,8,30,4263,
+9,18,24,4263,
+1,14,28,4263,
+10,16,25,4263,
+2,4,31,4263,
+4,17,26,4263,
+14,16,23,4263,
+0,9,30,4263,
+7,16,26,4263,
+10,21,21,4263,
+9,15,26,4263,
+1,9,30,4263,
+2,14,28,4263,
+10,20,22,4263,
+4,22,22,4263,
+10,10,28,4263,
+12,20,21,4273,
+6,7,30,4273,
+0,12,29,4273,
+6,18,25,4273,
+2,9,30,4273,
+0,16,27,4273,
+3,20,24,4273,
+8,9,29,4273,
+3,4,31,4273,
+7,19,24,4273,
+0,5,31,4273,
+4,21,23,4273,
+0,19,25,4273,
+9,11,28,4273,
+15,19,20,4299,
+16,17,21,4299,
+1,16,27,4299,
+11,17,24,4299,
+1,12,29,4299,
+1,5,31,4299,
+5,11,29,4299,
+1,19,25,4299,
+13,17,23,4299,
+2,12,29,4299,
+12,13,26,4299,
+12,19,22,4299,
+8,14,27,4299,
+6,13,28,4299,
+2,16,27,4299,
+8,21,22,4299,
+5,8,30,4299,
+3,14,28,4299,
+6,15,27,4299,
+2,5,31,4299,
+5,17,26,4299,
+2,19,25,4299,
+10,19,23,4299,
+7,10,29,4299,
+13,14,25,4299,
+3,9,30,4299,
+15,18,21,4315,
+8,12,28,4315,
+4,20,24,4315,
+4,4,31,4315,
+8,20,23,4315,
+11,14,26,4315,
+5,22,22,4315,
+3,12,29,4315,
+3,16,27,4315,
+12,15,25,4315,
+11,12,27,4315,
+5,21,23,4315,
+3,5,31,4315,
+9,17,25,4315,
+3,19,25,4315,
+8,16,26,4315,
+4,14,28,4315,
+14,20,20,4341,
+16,16,22,4341,
+14,15,24,4341,
+4,9,30,4341,
+0,6,31,4341,
+12,18,23,4341,
+14,19,21,4359,
+7,7,30,4359,
+6,11,29,4359,
+7,18,25,4359,
+10,13,27,4359,
+1,6,31,4359,
+15,17,22,4359,
+0,18,26,4359,
+0,10,30,4359,
+10,18,24,4359,
+6,8,30,4359,
+4,12,29,4359,
+8,19,24,4359,
+4,16,27,4359,
+5,20,24,4359,
+6,17,26,4359,
+10,15,26,4359,
+2,6,31,4359,
+1,18,26,4359,
+13,16,24,4359,
+1,10,30,4359,
+7,13,28,4359,
+4,19,25,4359,
+4,5,31,4359,
+11,16,25,4359,
+11,21,21,4362,
+7,15,27,4362,
+9,9,29,4362,
+2,10,30,4362,
+2,18,26,4362,
+14,18,22,4382,
+6,22,22,4382,
+8,10,29,4382,
+5,14,28,4382,
+11,20,22,4382,
+10,11,28,4382,
+3,6,31,4382,
+9,21,22,4382,
+9,14,27,4382,
+6,21,23,4382,
+5,9,30,4382,
+3,10,30,4382,
+0,15,28,4382,
+12,17,24,4390,
+9,12,28,4390,
+18,18,19,4433,
+3,18,26,4433,
+1,15,28,4433,
+9,20,23,4433,
+5,16,27,4433,
+0,13,29,4433,
+13,20,21,4433,
+15,16,23,4433,
+5,12,29,4433,
+0,7,31,4433,
+17,19,19,4444,
+5,5,31,4444,
+11,19,23,4444,
+5,19,25,4444,
+7,11,29,4444,
+1,13,29,4444,
+1,7,31,4444,
+6,20,24,4444,
+0,22,23,4444,
+17,18,20,4452,
+9,16,26,4452,
+2,15,28,4452,
+8,18,25,4452,
+4,6,31,4452,
+7,8,30,4452,
+10,17,25,4452,
+2,13,29,4452,
+14,17,23,4452,
+7,17,26,4452,
+1,22,23,4452,
+13,19,22,4452,
+13,13,26,4452,
+2,7,31,4452,
+4,10,30,4452,
+12,14,26,4452,
+4,18,26,4452,
+6,14,28,4452,
+12,12,27,4452,
+0,21,24,4452,
+7,22,22,4452,
+6,9,30,4452,
+2,22,23,4452,
+16,19,20,4466,
+8,13,28,4466,
+14,14,25,4466,
+8,15,27,4466,
+9,19,24,4466,
+1,21,24,4466,
+3,15,28,4466,
+0,17,27,4466,
+13,15,25,4466,
+3,7,31,4466,
+1,17,27,4466,
+17,17,21,4486,
+7,21,23,4486,
+11,13,27,4486,
+3,13,29,4486,
+6,12,29,4486,
+11,18,24,4486,
+16,18,21,4497,
+0,11,30,4497,
+2,21,24,4497,
+6,16,27,4497,
+11,15,26,4497,
+5,6,31,4497,
+1,11,30,4497,
+9,10,29,4497,
+2,17,27,4497,
+6,19,25,4497,
+3,22,23,4497,
+13,18,23,4497,
+0,0,32,4497,
+15,20,20,4518,
+2,11,30,4518,
+12,16,25,4518,
+10,21,22,4518,
+0,20,25,4518,
+0,1,32,4518,
+4,15,28,4518,
+7,20,24,4518,
+10,14,27,4518,
+5,18,26,4518,
+5,10,30,4518,
+0,8,31,4518,
+11,11,28,4518,
+1,8,31,4518,
+4,13,29,4518,
+1,20,25,4518,
+1,1,32,4518,
+12,21,21,4518,
+4,7,31,4518,
+15,15,24,4518,
+3,21,24,4518,
+8,11,29,4518,
+15,19,21,4530,
+3,17,27,4530,
+12,20,22,4530,
+8,8,30,4530,
+0,2,32,4530,
+10,12,28,4530,
+14,16,24,4530,
+10,20,23,4530,
+2,8,31,4530,
+16,17,22,4539,
+1,2,32,4539,
+8,17,26,4539,
+7,14,28,4539,
+4,22,23,4539,
+2,20,25,4539,
+9,18,25,4539,
+3,11,30,4539,
+7,9,30,4539,
+10,16,26,4539,
+8,22,22,4539,
+2,2,32,4539,
+15,18,22,4558,
+4,21,24,4558,
+6,6,31,4558,
+0,3,32,4558,
+9,13,28,4558,
+8,21,23,4558,
+13,17,24,4558,
+3,8,31,4558,
+5,15,28,4558,
+7,12,29,4558,
+4,17,27,4558,
+7,16,27,4558,
+1,3,32,4558,
+12,19,23,4558,
+3,20,25,4558,
+11,17,25,4558,
+7,19,25,4558,
+5,7,31,4558,
+5,13,29,4558,
+9,15,27,4558,
+6,18,26,4558,
+6,10,30,4558,
+0,14,29,4558,
+10,19,24,4558,
+2,3,32,4558,
+0,19,26,4558,
+4,11,30,4558,
+14,20,21,4581,
+5,22,23,4581,
+1,19,26,4581,
+1,14,29,4581,
+0,4,32,4581,
+0,16,28,4581,
+8,20,24,4581,
+2,14,29,4581,
+1,4,32,4581,
+4,8,31,4581,
+16,16,23,4595,
+13,14,26,4595,
+14,19,22,4595,
+2,19,26,4595,
+10,10,29,4595,
+4,20,25,4595,
+1,16,28,4595,
+12,13,27,4595,
+5,21,24,4595,
+3,3,32,4595,
+0,9,31,4595,
+1,9,31,4595,
+5,17,27,4595,
+9,11,29,4595,
+15,17,23,4612,
+12,18,24,4612,
+0,12,30,4612,
+2,4,32,4612,
+8,14,28,4612,
+2,16,28,4612,
+12,15,26,4612,
+6,15,28,4612,
+1,12,30,4612,
+8,9,30,4612,
+2,9,31,4612,
+11,21,22,4612,
+3,14,29,4612,
+9,17,26,4612,
+6,13,29,4612,
+18,19,19,4637,
+6,7,31,4637,
+11,14,27,4637,
+5,11,30,4637,
+14,15,25,4637,
+3,19,26,4637,
+18,18,20,4649,
+2,12,30,4649,
+11,12,28,4649,
+3,16,28,4649,
+0,5,32,4649,
+7,10,30,4649,
+14,18,23,4649,
+9,22,22,4649,
+8,16,27,4649,
+7,18,26,4649,
+3,4,32,4649,
+10,18,25,4649,
+6,22,23,4649,
+8,12,29,4649,
+13,16,25,4649,
+11,20,23,4649,
+17,19,20,4668,
+1,5,32,4668,
+5,8,31,4668,
+8,19,25,4668,
+5,20,25,4668,
+13,21,21,4668,
+3,9,31,4668,
+9,21,23,4668,
+13,20,22,4668,
+11,16,26,4668,
+2,5,32,4668,
+4,19,26,4668,
+3,12,30,4668,
+6,21,24,4668,
+4,14,29,4668,
+0,18,27,4668,
+10,13,28,4668,
+10,15,27,4668,
+1,18,27,4668,
+17,18,21,4684,
+6,17,27,4684,
+4,4,32,4684,
+4,16,28,4684,
+16,20,20,4692,
+2,18,27,4692,
+6,11,30,4692,
+9,20,24,4692,
+15,16,24,4692,
+16,19,21,4705,
+7,15,28,4705,
+3,5,32,4705,
+11,19,24,4705,
+4,9,31,4705,
+0,23,23,4705,
+12,17,25,4705,
+13,19,23,4705,
+7,7,31,4705,
+1,23,23,4705,
+7,13,29,4705,
+0,22,24,4705,
+4,12,30,4705,
+0,6,32,4705,
+14,17,24,4705,
+0,10,31,4705,
+6,20,25,4705,
+6,8,31,4705,
+9,14,28,4705,
+1,6,32,4705,
+1,22,24,4705,
+17,17,22,4722,
+10,11,29,4722,
+5,19,26,4722,
+5,14,29,4722,
+3,18,27,4722,
+1,10,31,4722,
+2,23,23,4722,
+9,9,30,4722,
+7,22,23,4722,
+2,6,32,4722,
+2,22,24,4722,
+8,10,30,4722,
+16,18,22,4732,
+8,18,26,4732,
+5,16,28,4732,
+2,10,31,4732,
+4,5,32,4732,
+10,17,26,4732,
+9,16,27,4732,
+7,21,24,4732,
+9,12,29,4732,
+15,20,21,4749,
+0,21,25,4749,
+0,15,29,4749,
+1,21,25,4749,
+7,17,27,4749,
+5,9,31,4749,
+3,23,23,4749,
+13,13,27,4749,
+9,19,25,4749,
+1,15,29,4749,
+10,22,22,4749,
+14,14,26,4749,
+3,6,32,4749,
+4,18,27,4749,
+12,21,22,4749,
+12,14,27,4749,
+0,13,30,4749,
+5,12,30,4749,
+3,22,24,4749,
+13,18,24,4749,
+13,15,26,4749,
+2,21,25,4749,
+3,10,31,4749,
+7,11,30,4749,
+11,18,25,4749,
+10,21,23,4749,
+15,19,22,4771,
+2,15,29,4771,
+1,13,30,4771,
+12,12,28,4771,
+8,15,28,4771,
+2,13,30,4771,
+0,7,32,4771,
+6,19,26,4771,
+12,20,23,4771,
+6,14,29,4771,
+0,17,28,4771,
+5,5,32,4771,
+1,7,32,4771,
+4,23,23,4771,
+7,20,25,4771,
+8,13,29,4771,
+16,17,23,4792,
+7,8,31,4792,
+1,17,28,4792,
+11,13,28,4792,
+11,15,27,4792,
+3,15,29,4792,
+15,15,25,4792,
+3,21,25,4792,
+4,22,24,4792,
+0,20,26,4792,
+4,6,32,4792,
+10,20,24,4792,
+12,16,26,4792,
+6,16,28,4792,
+1,20,26,4792,
+8,22,23,4792,
+2,17,28,4792,
+2,7,32,4792,
+4,10,31,4792,
+14,16,25,4792,
+15,18,23,4815,
+6,9,31,4815,
+3,13,30,4815,
+14,21,21,4815,
+5,18,27,4815,
+2,20,26,4815,
+10,14,28,4815,
+14,20,22,4824,
+6,12,30,4824,
+9,18,26,4824,
+9,10,30,4824,
+8,21,24,4824,
+12,19,24,4824,
+4,21,25,4824,
+3,17,28,4824,
+8,17,27,4824,
+4,15,29,4824,
+3,7,32,4824,
+0,11,31,4824,
+1,11,31,4824,
+11,11,29,4824,
+5,23,23,4824,
+13,17,25,4824,
+19,19,19,4858,
+5,6,32,4858,
+10,12,29,4858,
+3,20,26,4858,
+4,13,30,4858,
+18,19,20,4872,
+8,11,30,4872,
+10,16,27,4872,
+5,22,24,4872,
+10,19,25,4872,
+11,17,26,4872,
+7,14,29,4872,
+2,11,31,4872,
+5,10,31,4872,
+7,19,26,4872,
+14,19,23,4872,
+16,16,24,4872,
+0,8,32,4872,
+4,7,32,4872,
+7,16,28,4872,
+6,18,27,4872,
+8,8,31,4872,
+4,17,28,4872,
+18,18,21,4894,
+11,22,22,4894,
+0,0,33,4894,
+17,20,20,4894,
+8,20,25,4894,
+1,8,32,4894,
+9,15,28,4894,
+15,17,24,4894,
+0,1,33,4894,
+0,19,27,4894,
+5,21,25,4894,
+11,21,23,4894,
+9,13,29,4894,
+3,11,31,4894,
+5,15,29,4894,
+7,9,31,4894,
+1,1,33,4894,
+1,19,27,4894,
+17,19,21,4907,
+4,20,26,4907,
+2,8,32,4907,
+7,12,30,4907,
+12,18,25,4907,
+0,2,33,4907,
+1,2,33,4907,
+13,21,22,4907,
+5,13,30,4907,
+2,19,27,4907,
+9,22,23,4907,
+6,23,23,4907,
+13,14,27,4907,
+6,6,32,4907,
+0,14,30,4907,
+14,18,24,4910,
+6,22,24,4910,
+0,16,29,4910,
+6,10,31,4910,
+12,13,28,4910,
+1,14,30,4910,
+3,8,32,4910,
+2,2,33,4910,
+11,20,24,4910,
+16,20,21,4932,
+14,15,26,4932,
+17,18,22,4932,
+4,11,31,4932,
+9,21,24,4932,
+1,16,29,4932,
+5,7,32,4932,
+0,3,33,4932,
+5,17,28,4932,
+13,20,23,4932,
+12,15,27,4932,
+1,3,33,4932,
+3,19,27,4932,
+9,17,27,4932,
+2,14,30,4932,
+10,10,30,4932,
+10,18,26,4932,
+2,16,29,4932,
+11,14,28,4932,
+8,14,29,4932,
+13,16,26,4932,
+5,20,26,4932,
+8,19,26,4932,
+16,19,22,4952,
+2,3,33,4952,
+6,21,25,4952,
+7,18,27,4952,
+9,11,30,4952,
+6,15,29,4952,
+4,8,32,4952,
+8,16,28,4952,
+6,13,30,4952,
+3,14,30,4952,
+0,9,32,4952,
+0,23,24,4952,
+0,4,33,4952,
+0,12,31,4952,
+1,9,32,4952,
+15,16,25,4957,
+1,12,31,4957,
+13,19,24,4957,
+11,12,29,4957,
+8,9,31,4957,
+3,16,29,4957,
+9,20,25,4957,
+11,16,27,4957,
+1,4,33,4957,
+4,19,27,4957,
+1,23,24,4957,
+15,21,21,4975,
+5,11,31,4975,
+17,17,23,4975,
+3,3,33,4975,
+7,23,23,4975,
+11,19,25,4975,
+8,12,30,4975,
+0,18,28,4975,
+6,17,28,4975,
+15,20,22,4992,
+2,12,31,4992,
+0,22,25,4992,
+7,22,24,4992,
+2,23,24,4992,
+12,17,26,4992,
+2,4,33,4992,
+16,18,23,4992,
+10,15,28,4992,
+6,7,32,4992,
+1,18,28,4992,
+2,9,32,4992,
+1,22,25,4992,
+14,17,25,4992,
+10,13,29,4992,
+7,10,31,4992,
+6,20,26,4992,
+4,14,30,4992,
+2,18,28,4992,
+12,22,22,4992,
+5,8,32,4992,
+2,22,25,4992,
+4,16,29,4992,
+10,22,23,4992,
+3,4,33,4992,
+3,23,24,4992,
+12,21,23,5003,
+3,12,31,5003,
+3,9,32,5003,
+0,5,33,5003,
+7,21,25,5003,
+7,15,29,5003,
+15,19,23,5026,
+5,19,27,5026,
+1,5,33,5026,
+3,18,28,5026,
+10,21,24,5026,
+8,18,27,5026,
+0,21,26,5026,
+7,13,30,5026,
+2,5,33,5026,
+10,17,27,5026,
+1,21,26,5026,
+6,11,31,5026,
+9,19,26,5026,
+3,22,25,5026,
+9,14,29,5026,
+13,18,25,5026,
+12,20,24,5030,
+4,12,31,5030,
+5,14,30,5030,
+4,23,24,5030,
+10,11,30,5030,
+9,16,28,5030,
+16,17,24,5058,
+2,21,26,5058,
+14,14,27,5058,
+4,4,33,5058,
+4,9,32,5058,
+11,18,26,5058,
+14,21,22,5058,
+19,19,20,5084,
+8,23,23,5084,
+7,17,28,5084,
+13,13,28,5084,
+7,7,32,5084,
+5,16,29,5084,
+9,9,31,5084,
+3,5,33,5084,
+13,15,27,5084,
+0,10,32,5084,
+12,14,28,5084,
+6,8,32,5084,
+8,22,24,5084,
+18,20,20,5090,
+4,18,28,5090,
+0,6,33,5090,
+10,20,25,5090,
+4,22,25,5090,
+7,20,26,5090,
+0,15,30,5090,
+9,12,30,5090,
+15,18,24,5090,
+1,10,32,5090,
+8,10,31,5090,
+14,20,23,5090,
+1,15,30,5090,
+15,15,26,5090,
+6,19,27,5090,
+1,6,33,5090,
+3,21,26,5090,
+18,19,21,5108,
+2,10,32,5108,
+14,16,26,5108,
+12,16,27,5108,
+12,12,29,5108,
+0,20,27,5108,
+2,6,33,5108,
+2,15,30,5108,
+11,15,28,5108,
+1,20,27,5108,
+0,17,29,5108,
+5,23,24,5108,
+5,12,31,5108,
+4,5,33,5108,
+12,19,25,5108,
+8,15,29,5108,
+5,9,32,5108,
+17,20,21,5127,
+8,21,25,5127,
+0,13,31,5127,
+11,13,29,5127,
+1,17,29,5127,
+1,13,31,5127,
+7,11,31,5127,
+18,18,22,5130,
+6,14,30,5130,
+14,19,24,5130,
+3,10,32,5130,
+2,20,27,5130,
+5,18,28,5130,
+6,16,29,5130,
+8,13,30,5130,
+4,21,26,5130,
+3,6,33,5130,
+9,18,27,5130,
+3,15,30,5130,
+2,13,31,5130,
+13,17,26,5130,
+5,22,25,5130,
+17,19,22,5148,
+11,22,23,5148,
+2,17,29,5148,
+8,17,28,5148,
+7,8,32,5148,
+10,14,29,5148,
+10,19,26,5148,
+16,16,25,5148,
+13,22,22,5148,
+16,21,21,5175,
+0,7,33,5175,
+3,20,27,5175,
+11,21,24,5175,
+11,17,27,5175,
+9,23,23,5175,
+5,5,33,5175,
+15,17,25,5175,
+13,21,23,5175,
+3,13,31,5175,
+3,17,29,5175,
+1,7,33,5175,
+7,19,27,5175,
+10,16,28,5175,
+8,20,26,5175,
+4,10,32,5175,
+16,20,22,5178,
+9,22,24,5178,
+6,12,31,5178,
+6,23,24,5178,
+4,15,30,5178,
+6,9,32,5178,
+4,6,33,5178,
+11,11,30,5178,
+5,21,26,5178,
+9,10,31,5178,
+17,18,23,5201,
+2,7,33,5201,
+6,18,28,5201,
+10,12,30,5201,
+12,18,26,5201,
+7,14,30,5201,
+6,22,25,5201,
+0,19,28,5201,
+0,11,32,5201,
+13,20,24,5201,
+14,18,25,5201,
+4,20,27,5201,
+7,16,29,5201,
+1,11,32,5201,
+16,19,23,5219,
+8,11,31,5219,
+11,20,25,5219,
+1,19,28,5219,
+4,13,31,5219,
+4,17,29,5219,
+9,21,25,5219,
+9,15,29,5219,
+3,7,33,5219,
+2,19,28,5219,
+13,14,28,5219,
+5,10,32,5219,
+2,11,32,5219,
+5,6,33,5219,
+5,15,30,5219,
+15,21,22,5237,
+14,15,27,5237,
+9,13,30,5237,
+0,24,24,5237,
+8,8,32,5237,
+0,8,33,5237,
+6,21,26,5237,
+12,15,28,5237,
+1,24,24,5237,
+10,18,27,5237,
+17,17,24,5259,
+0,23,25,5259,
+8,19,27,5259,
+3,19,28,5259,
+7,12,31,5259,
+15,20,23,5259,
+12,13,29,5259,
+13,16,27,5259,
+3,11,32,5259,
+4,7,33,5259,
+1,8,33,5259,
+9,17,28,5259,
+7,23,24,5259,
+7,9,32,5259,
+5,20,27,5259,
+1,23,25,5259,
+13,19,25,5259,
+5,17,29,5259,
+5,13,31,5259,
+0,0,34,5259,
+2,24,24,5259,
+16,18,24,5264,
+0,16,30,5264,
+7,18,28,5264,
+15,16,26,5264,
+9,20,26,5264,
+12,22,23,5264,
+0,1,34,5264,
+2,8,33,5264,
+0,14,31,5264,
+1,16,30,5264,
+2,23,25,5264,
+11,19,26,5264,
+11,14,29,5264,
+7,22,25,5264,
+1,1,34,5264,
+10,23,23,5264,
+1,14,31,5264,
+8,14,30,5264,
+2,16,30,5264,
+0,22,26,5264,
+6,10,32,5264,
+10,22,24,5264,
+0,2,34,5264,
+4,11,32,5264,
+1,22,26,5264,
+8,16,29,5264,
+4,19,28,5264,
+2,14,31,5264,
+6,15,30,5264,
+19,20,20,5312,
+14,17,26,5312,
+12,21,24,5312,
+1,2,34,5312,
+6,6,33,5312,
+11,16,28,5312,
+10,10,31,5312,
+3,24,24,5312,
+3,8,33,5312,
+12,17,27,5312,
+15,19,24,5312,
+9,11,31,5312,
+19,19,21,5323,
+3,23,25,5323,
+5,7,33,5323,
+14,22,22,5323,
+2,2,34,5323,
+2,22,26,5323,
+3,16,30,5323,
+6,20,27,5323,
+0,3,34,5323,
+11,12,30,5323,
+0,18,29,5323,
+18,20,21,5336,
+7,21,26,5336,
+14,21,23,5336,
+1,3,34,5336,
+10,21,25,5336,
+6,13,31,5336,
+1,18,29,5336,
+3,14,31,5336,
+6,17,29,5336,
+10,15,29,5336,
+0,12,32,5336,
+4,24,24,5336,
+2,3,34,5336,
+8,9,32,5336,
+13,18,26,5336,
+2,18,29,5336,
+18,19,22,5353,
+8,12,31,5353,
+8,23,24,5353,
+1,12,32,5353,
+3,22,26,5353,
+10,13,30,5353,
+12,20,25,5353,
+4,8,33,5353,
+5,11,32,5353,
+0,9,33,5353,
+0,21,27,5353,
+16,17,25,5353,
+4,23,25,5353,
+5,19,28,5353,
+1,21,27,5353,
+9,19,27,5353,
+17,21,21,5370,
+1,9,33,5370,
+14,20,24,5370,
+8,18,28,5370,
+2,12,32,5370,
+0,4,34,5370,
+4,16,30,5370,
+4,14,31,5370,
+8,22,25,5370,
+1,4,34,5370,
+7,10,32,5370,
+17,20,22,5386,
+10,17,28,5386,
+3,18,29,5386,
+15,18,25,5386,
+2,21,27,5386,
+7,15,30,5386,
+6,7,33,5386,
+2,9,33,5386,
+11,18,27,5386,
+3,3,34,5386,
+10,20,26,5386,
+2,4,34,5386,
+4,22,26,5386,
+14,14,28,5386,
+18,18,23,5404,
+9,14,30,5404,
+3,12,32,5404,
+5,24,24,5404,
+7,20,27,5404,
+13,15,28,5404,
+9,16,29,5404,
+5,8,33,5404,
+13,13,29,5404,
+17,19,23,5420,
+15,15,27,5420,
+7,13,31,5420,
+11,23,23,5420,
+5,23,25,5420,
+7,17,29,5420,
+3,21,27,5420,
+3,9,33,5420,
+3,4,34,5420,
+16,21,22,5428,
+5,16,30,5428,
+8,21,26,5428,
+6,19,28,5428,
+12,14,29,5428,
+6,11,32,5428,
+12,19,26,5428,
+4,18,29,5428,
+14,16,27,5428,
+11,22,24,5428,
+0,5,34,5428,
+1,5,34,5428,
+13,22,23,5428,
+5,14,31,5428,
+14,19,25,5428,
+10,11,31,5428,
+12,16,28,5428,
+4,12,32,5428,
+0,20,28,5428,
+16,20,23,5448,
+1,20,28,5448,
+5,22,26,5448,
+2,5,34,5448,
+13,21,24,5448,
+0,15,31,5448,
+9,9,32,5448,
+9,12,31,5448,
+4,9,33,5448,
+4,21,27,5448,
+9,23,24,5448,
+7,7,33,5448,
+11,15,29,5448,
+11,21,25,5448,
+1,15,31,5448,
+13,17,27,5448,
+2,20,28,5448,
+6,24,24,5448,
+16,16,26,5448,
+8,10,32,5448,
+4,4,34,5448,
+12,12,30,5448,
+17,18,24,5464,
+6,8,33,5464,
+0,10,33,5464,
+0,17,30,5464,
+8,15,30,5464,
+9,18,28,5464,
+1,10,33,5464,
+11,13,30,5464,
+3,5,34,5464,
+2,15,31,5464,
+5,18,29,5464,
+9,22,25,5464,
+15,17,26,5464,
+10,19,27,5464,
+1,17,30,5464,
+6,23,25,5464,
+6,16,30,5464,
+0,6,34,5464,
+1,6,34,5464,
+16,19,24,5479,
+2,17,30,5479,
+5,12,32,5479,
+2,10,33,5479,
+6,14,31,5479,
+3,20,28,5479,
+0,13,32,5479,
+15,22,22,5479,
+8,20,27,5479,
+7,11,32,5479,
+8,13,31,5479,
+7,19,28,5479,
+1,13,32,5479,
+8,17,29,5479,
+11,17,28,5479,
+13,20,25,5479,
+5,21,27,5479,
+15,21,23,5489,
+5,9,33,5489,
+3,15,31,5489,
+6,22,26,5489,
+2,6,34,5489,
+14,18,26,5489,
+10,14,30,5489,
+2,13,32,5489,
+12,18,27,5489,
+11,20,26,5489,
+10,16,29,5489,
+4,5,34,5489,
+3,10,33,5489,
+3,17,30,5489,
+9,21,26,5489,
+20,20,20,5546,
+4,20,28,5546,
+7,24,24,5546,
+3,6,34,5546,
+0,24,25,5546,
+6,18,29,5546,
+15,20,24,5546,
+12,23,23,5546,
+4,15,31,5546,
+1,24,25,5546,
+19,20,21,5565,
+0,19,29,5565,
+7,8,33,5565,
+3,13,32,5565,
+11,11,31,5565,
+17,17,25,5565,
+7,23,25,5565,
+1,19,29,5565,
+6,12,32,5565,
+12,22,24,5565,
+14,15,28,5565,
+7,16,30,5565,
+10,23,24,5565,
+16,18,25,5565,
+10,12,31,5565,
+2,24,25,5565,
+4,10,33,5565,
+9,10,32,5565,
+0,23,26,5565,
+4,17,30,5565,
+0,7,34,5565,
+5,5,34,5565,
+7,14,31,5565,
+13,14,29,5565,
+13,19,26,5565,
+19,19,22,5581,
+6,9,33,5581,
+2,19,29,5581,
+6,21,27,5581,
+18,21,21,5581,
+1,7,34,5581,
+9,15,30,5581,
+1,23,26,5581,
+18,20,22,5593,
+10,18,28,5593,
+4,6,34,5593,
+2,23,26,5593,
+10,22,25,5593,
+7,22,26,5593,
+13,16,28,5593,
+8,11,32,5593,
+5,20,28,5593,
+14,22,23,5593,
+2,7,34,5593,
+8,19,28,5593,
+4,13,32,5593,
+3,24,25,5593,
+12,21,25,5593,
+15,16,27,5593,
+12,15,29,5593,
+0,11,33,5593,
+9,20,27,5593,
+1,11,33,5593,
+3,19,29,5593,
+15,19,25,5593,
+9,13,31,5593,
+5,15,31,5593,
+9,17,29,5593,
+11,19,27,5593,
+0,22,27,5593,
+12,13,30,5593,
+14,21,24,5600,
+5,17,30,5600,
+2,11,33,5600,
+18,19,23,5628,
+1,22,27,5628,
+7,18,29,5628,
+3,7,34,5628,
+17,21,22,5628,
+14,17,27,5628,
+5,10,33,5628,
+3,23,26,5628,
+8,24,24,5628,
+7,12,32,5628,
+8,8,33,5628,
+5,6,34,5628,
+2,22,27,5628,
+10,21,26,5628,
+12,17,28,5628,
+4,24,25,5628,
+0,16,31,5628,
+11,14,30,5628,
+17,20,23,5656,
+1,16,31,5656,
+4,19,29,5656,
+8,23,25,5656,
+5,13,32,5656,
+11,16,29,5656,
+7,21,27,5656,
+3,11,33,5656,
+7,9,33,5656,
+0,14,32,5656,
+12,20,26,5656,
+6,20,28,5656,
+8,16,30,5656,
+0,8,34,5656,
+4,7,34,5656,
+1,14,32,5656,
+14,20,25,5656,
+2,16,31,5656,
+8,14,31,5656,
+16,17,26,5656,
+1,8,34,5656,
+4,23,26,5656,
+13,18,27,5656,
+3,22,27,5656,
+6,15,31,5656,
+18,18,24,5685,
+0,18,30,5685,
+2,14,32,5685,
+10,10,32,5685,
+8,22,26,5685,
+2,8,34,5685,
+16,22,22,5685,
+0,21,28,5685,
+15,18,26,5685,
+6,10,33,5685,
+10,15,30,5685,
+1,18,30,5685,
+0,0,35,5685,
+6,17,30,5685,
+9,19,28,5685,
+1,21,28,5685,
+0,1,35,5685,
+16,21,23,5697,
+9,11,32,5697,
+3,16,31,5697,
+5,24,25,5697,
+4,11,33,5697,
+11,12,31,5697,
+11,23,24,5697,
+17,19,24,5697,
+1,1,35,5697,
+13,23,23,5697,
+5,19,29,5697,
+6,6,34,5697,
+2,18,30,5697,
+0,2,35,5697,
+6,13,32,5697,
+3,14,32,5697,
+11,18,28,5697,
+13,22,24,5697,
+10,20,27,5697,
+4,22,27,5697,
+3,8,34,5697,
+2,21,28,5697,
+8,18,29,5697,
+5,7,34,5697,
+5,23,26,5697,
+1,2,35,5697,
+10,17,29,5697,
+10,13,31,5697,
+11,22,25,5697,
+16,20,24,5729,
+8,12,32,5729,
+4,16,31,5729,
+9,24,24,5729,
+2,2,35,5729,
+0,12,33,5729,
+14,19,26,5729,
+3,18,30,5729,
+7,20,28,5729,
+14,14,29,5729,
+8,9,33,5729,
+0,3,35,5729,
+15,15,28,5729,
+3,21,28,5729,
+1,12,33,5729,
+12,19,27,5729,
+8,21,27,5729,
+1,3,35,5729,
+9,23,25,5729,
+5,11,33,5729,
+7,15,31,5729,
+13,21,25,5729,
+13,15,29,5729,
+4,8,34,5729,
+4,14,32,5729,
+14,16,28,5729,
+6,24,25,5729,
+9,16,30,5729,
+2,12,33,5729,
+0,9,34,5729,
+11,21,26,5729,
+9,14,31,5729,
+13,13,30,5729,
+15,22,23,5759,
+2,3,35,5759,
+7,17,30,5759,
+1,9,34,5759,
+6,19,29,5759,
+5,22,27,5759,
+7,10,33,5759,
+17,18,25,5759,
+12,14,30,5759,
+4,18,30,5759,
+16,16,27,5759,
+12,16,29,5759,
+0,4,35,5759,
+6,7,34,5759,
+4,21,28,5759,
+6,23,26,5759,
+2,9,34,5759,
+20,20,21,5802,
+0,20,29,5802,
+9,22,26,5802,
+13,17,28,5802,
+16,19,25,5802,
+5,16,31,5802,
+1,4,35,5802,
+1,20,29,5802,
+7,13,32,5802,
+15,21,24,5802,
+3,12,33,5802,
+19,21,21,5813,
+15,17,27,5813,
+3,3,35,5813,
+13,20,26,5813,
+10,19,28,5813,
+5,8,34,5813,
+2,20,29,5813,
+10,11,32,5813,
+19,20,22,5819,
+5,14,32,5819,
+2,4,35,5819,
+9,18,29,5819,
+11,15,30,5819,
+3,9,34,5819,
+6,11,33,5819,
+8,20,28,5819,
+18,21,22,5837,
+12,23,24,5837,
+5,18,30,5837,
+6,22,27,5837,
+0,15,32,5837,
+9,12,32,5837,
+14,18,27,5837,
+12,12,31,5837,
+4,12,33,5837,
+0,25,25,5837,
+15,20,25,5837,
+3,4,35,5837,
+11,20,27,5837,
+7,24,25,5837,
+0,17,31,5837,
+1,15,32,5837,
+0,5,35,5837,
+5,21,28,5837,
+3,20,29,5837,
+8,15,31,5837,
+9,9,33,5837,
+11,17,29,5837,
+1,5,35,5837,
+1,25,25,5837,
+7,19,29,5837,
+11,13,31,5837,
+1,17,31,5837,
+19,19,23,5847,
+9,21,27,5847,
+12,18,28,5847,
+10,24,24,5847,
+0,24,26,5847,
+4,9,34,5847,
+18,20,23,5862,
+8,10,33,5862,
+2,15,32,5862,
+1,24,26,5862,
+8,17,30,5862,
+6,16,31,5862,
+12,22,25,5862,
+10,23,25,5862,
+14,23,23,5862,
+7,23,26,5862,
+2,17,31,5862,
+2,5,35,5862,
+17,17,26,5862,
+2,25,25,5862,
+7,7,34,5862,
+6,8,34,5862,
+6,14,32,5862,
+16,18,26,5862,
+10,16,30,5862,
+14,22,24,5862,
+2,24,26,5862,
+0,10,34,5862,
+4,20,29,5862,
+1,10,34,5862,
+17,22,22,5876,
+4,4,35,5876,
+10,14,31,5876,
+8,13,32,5876,
+0,13,33,5876,
+3,15,32,5876,
+5,12,33,5876,
+0,23,27,5876,
+13,19,27,5876,
+7,11,33,5876,
+3,17,31,5876,
+3,25,25,5876,
+17,21,23,5895,
+1,13,33,5895,
+1,23,27,5895,
+3,5,35,5895,
+6,18,30,5895,
+10,22,26,5895,
+2,10,34,5895,
+18,19,24,5910,
+0,6,35,5910,
+6,21,28,5910,
+0,19,30,5910,
+3,24,26,5910,
+12,21,26,5910,
+7,22,27,5910,
+2,13,33,5910,
+1,19,30,5910,
+2,23,27,5910,
+1,6,35,5910,
+5,9,34,5910,
+14,15,29,5910,
+14,21,25,5910,
+15,19,26,5910,
+15,16,28,5910,
+2,19,30,5910,
+9,20,28,5910,
+2,6,35,5910,
+4,15,32,5910,
+3,10,34,5910,
+13,14,30,5910,
+8,24,25,5910,
+17,20,24,5926,
+10,18,29,5926,
+4,17,31,5926,
+4,25,25,5926,
+4,5,35,5926,
+11,19,28,5926,
+11,11,32,5926,
+5,20,29,5926,
+7,16,31,5926,
+13,16,29,5926,
+8,19,29,5926,
+9,15,31,5926,
+3,13,33,5926,
+3,23,27,5926,
+0,22,28,5926,
+4,24,26,5926,
+10,12,32,5926,
+6,12,33,5926,
+8,23,26,5926,
+14,17,28,5926,
+12,15,30,5926,
+16,22,23,5950,
+1,22,28,5950,
+7,8,34,5950,
+7,14,32,5950,
+3,6,35,5950,
+3,19,30,5950,
+10,21,27,5950,
+9,10,33,5950,
+9,17,30,5950,
+14,20,26,5950,
+4,10,34,5950,
+2,22,28,5950,
+6,9,34,5950,
+18,18,25,5978,
+16,21,24,5978,
+11,24,24,5978,
+12,20,27,5978,
+7,18,30,5978,
+13,23,24,5978,
+16,17,27,5978,
+7,21,28,5978,
+5,15,32,5978,
+0,7,35,5978,
+12,17,29,5978,
+8,11,33,5978,
+4,23,27,5978,
+12,13,31,5978,
+4,13,33,5978,
+9,13,32,5978,
+17,19,25,5994,
+1,7,35,5994,
+11,23,25,5994,
+5,25,25,5994,
+5,5,35,5994,
+5,17,31,5994,
+3,22,28,5994,
+8,22,27,5994,
+11,16,30,5994,
+13,18,28,5994,
+0,11,34,5994,
+5,24,26,5994,
+4,6,35,5994,
+6,20,29,5994,
+4,19,30,5994,
+11,14,31,5994,
+15,18,27,5994,
+1,11,34,5994,
+2,7,35,5994,
+13,22,25,5994,
+0,16,32,5994,
+16,20,25,6011,
+5,10,34,6011,
+1,16,32,6011,
+11,22,26,6011,
+8,16,31,6011,
+2,11,34,6011,
+0,21,29,6011,
+20,21,21,6051,
+7,12,33,6051,
+9,24,25,6051,
+1,21,29,6051,
+5,13,33,6051,
+3,7,35,6051,
+9,19,29,6051,
+5,23,27,6051,
+15,23,23,6051,
+2,16,32,6051,
+8,8,34,6051,
+10,20,28,6051,
+4,22,28,6051,
+20,20,22,6057,
+8,14,32,6057,
+15,22,24,6057,
+6,15,32,6057,
+0,14,33,6057,
+0,18,31,6057,
+2,21,29,6057,
+5,19,30,6057,
+13,21,26,6057,
+6,25,25,6057,
+3,11,34,6057,
+19,21,22,6072,
+6,17,31,6072,
+14,19,27,6072,
+1,14,33,6072,
+5,6,35,6072,
+10,15,31,6072,
+1,18,31,6072,
+7,9,34,6072,
+9,23,26,6072,
+11,18,29,6072,
+6,24,26,6072,
+8,18,30,6072,
+10,10,33,6072,
+12,19,28,6072,
+3,16,32,6072,
+10,17,30,6072,
+0,8,35,6072,
+17,18,26,6072,
+2,14,33,6072,
+11,12,32,6072,
+8,21,28,6072,
+2,18,31,6072,
+19,20,23,6101,
+1,8,35,6101,
+4,7,35,6101,
+7,20,29,6101,
+11,21,27,6101,
+15,21,25,6101,
+9,11,33,6101,
+3,21,29,6101,
+15,15,29,6101,
+18,22,22,6103,
+6,10,34,6103,
+14,14,30,6103,
+10,13,32,6103,
+2,8,35,6103,
+16,19,26,6103,
+5,22,28,6103,
+14,16,29,6103,
+4,11,34,6103,
+13,15,30,6103,
+18,21,23,6120,
+6,13,33,6120,
+3,18,31,6120,
+6,23,27,6120,
+3,14,33,6120,
+9,22,27,6120,
+12,24,24,6120,
+4,16,32,6120,
+0,0,36,6120,
+16,16,28,6120,
+6,19,30,6120,
+0,1,36,6120,
+6,6,35,6120,
+8,12,33,6120,
+19,19,24,6143,
+1,1,36,6143,
+9,16,31,6143,
+13,20,27,6143,
+3,8,35,6143,
+4,21,29,6143,
+12,23,25,6143,
+15,17,28,6143,
+7,15,32,6143,
+7,25,25,6143,
+13,17,29,6143,
+7,17,31,6143,
+5,7,35,6143,
+13,13,31,6143,
+12,16,30,6143,
+18,20,24,6147,
+0,12,34,6147,
+0,20,30,6147,
+0,2,36,6147,
+14,23,24,6147,
+15,20,26,6147,
+1,2,36,6147,
+10,24,25,6147,
+9,14,32,6147,
+8,9,34,6147,
+7,24,26,6147,
+12,14,31,6147,
+1,12,34,6147,
+0,25,26,6147,
+4,18,31,6147,
+1,20,30,6147,
+4,14,33,6147,
+5,11,34,6147,
+17,22,23,6162,
+10,19,29,6162,
+1,25,26,6162,
+2,12,34,6162,
+2,20,30,6162,
+14,18,28,6162,
+2,2,36,6162,
+6,22,28,6162,
+12,22,26,6162,
+0,24,27,6162,
+11,20,28,6162,
+14,22,25,6162,
+2,25,26,6162,
+10,23,26,6162,
+5,16,32,6162,
+8,20,29,6162,
+0,3,36,6162,
+7,10,34,6162,
+4,8,35,6162,
+9,18,30,6162,
+17,21,24,6186,
+1,3,36,6186,
+0,9,35,6186,
+9,21,28,6186,
+1,24,27,6186,
+5,21,29,6186,
+7,23,27,6186,
+1,9,35,6186,
+17,17,27,6186,
+7,13,33,6186,
+11,15,31,6186,
+16,18,27,6186,
+3,20,30,6186,
+2,3,36,6186,
+2,24,27,6186,
+3,12,34,6186,
+12,18,29,6186,
+7,19,30,6186,
+18,19,25,6203,
+11,17,30,6203,
+2,9,35,6203,
+10,11,33,6203,
+6,7,35,6203,
+3,25,26,6203,
+5,18,31,6203,
+5,14,33,6203,
+12,12,32,6203,
+0,4,36,6203,
+6,11,34,6203,
+14,21,26,6203,
+0,23,28,6203,
+1,4,36,6203,
+8,15,32,6203,
+0,17,32,6203,
+10,22,27,6203,
+3,3,36,6203,
+1,23,28,6203,
+8,25,25,6203,
+1,17,32,6203,
+3,24,27,6203,
+9,12,33,6203,
+13,19,28,6203,
+8,17,31,6203,
+11,13,32,6203,
+0,15,33,6203,
+12,21,27,6203,
+16,23,23,6236,
+5,8,35,6236,
+17,20,25,6236,
+3,9,35,6236,
+15,19,27,6236,
+1,15,33,6236,
+6,16,32,6236,
+16,22,24,6239,
+4,12,34,6239,
+4,20,30,6239,
+8,24,26,6239,
+2,4,36,6239,
+2,23,28,6239,
+2,17,32,6239,
+7,22,28,6239,
+4,25,26,6239,
+10,16,31,6239,
+6,21,29,6239,
+9,9,34,6239,
+2,15,33,6239,
+8,10,34,6239,
+10,14,32,6239,
+6,14,33,6239,
+6,18,31,6239,
+13,24,24,6247,
+14,15,30,6247,
+0,5,36,6247,
+4,24,27,6247,
+3,4,36,6247,
+11,24,25,6247,
+3,17,32,6247,
+16,21,25,6274,
+3,23,28,6274,
+4,9,35,6274,
+1,5,36,6274,
+9,20,29,6274,
+0,19,31,6274,
+15,16,29,6274,
+8,13,33,6274,
+8,23,27,6274,
+1,19,31,6274,
+3,15,33,6274,
+7,7,35,6274,
+11,19,29,6274,
+21,21,21,6301,
+13,23,25,6301,
+10,18,30,6301,
+18,18,26,6301,
+5,12,34,6301,
+2,5,36,6301,
+8,19,30,6301,
+14,20,27,6301,
+0,10,35,6301,
+6,8,35,6301,
+20,21,22,6316,
+0,13,34,6316,
+13,16,30,6316,
+5,20,30,6316,
+10,21,28,6316,
+0,22,29,6316,
+14,17,29,6316,
+1,10,35,6316,
+7,11,34,6316,
+1,22,29,6316,
+11,23,26,6316,
+17,19,26,6316,
+5,25,26,6316,
+13,14,31,6316,
+1,13,34,6316,
+2,19,31,6316,
+12,20,28,6316,
+4,4,36,6316,
+20,20,23,6335,
+19,22,22,6335,
+7,16,32,6335,
+13,22,26,6335,
+2,13,34,6335,
+2,22,29,6335,
+16,17,28,6335,
+4,17,32,6335,
+2,10,35,6335,
+4,23,28,6335,
+5,24,27,6335,
+4,15,33,6335,
+3,5,36,6335,
+15,23,24,6335,
+12,15,31,6335,
+9,15,32,6335,
+19,21,23,6352,
+5,9,35,6352,
+11,11,33,6352,
+7,21,29,6352,
+9,25,25,6352,
+3,19,31,6352,
+9,17,31,6352,
+0,6,36,6352,
+16,20,26,6352,
+8,22,28,6352,
+9,24,26,6352,
+12,17,30,6352,
+15,18,28,6352,
+1,6,36,6352,
+10,12,33,6352,
+15,22,25,6352,
+3,22,29,6352,
+11,22,27,6352,
+13,18,29,6352,
+3,13,34,6352,
+7,18,31,6352,
+3,10,35,6352,
+7,14,33,6352,
+6,20,30,6352,
+2,6,36,6352,
+6,12,34,6352,
+9,10,34,6352,
+19,20,24,6381,
+12,13,32,6381,
+18,22,23,6381,
+6,25,26,6381,
+4,5,36,6381,
+5,17,32,6381,
+11,16,31,6381,
+5,23,28,6381,
+4,19,31,6381,
+7,8,35,6381,
+9,23,27,6381,
+13,21,27,6381,
+5,15,33,6381,
+9,13,33,6381,
+10,20,29,6381,
+4,10,35,6381,
+6,24,27,6381,
+11,14,32,6381,
+4,13,34,6381,
+4,22,29,6381,
+8,11,34,6381,
+3,6,36,6381,
+14,19,28,6381,
+0,21,30,6381,
+18,21,24,6406,
+17,18,27,6406,
+15,21,26,6406,
+9,19,30,6406,
+1,21,30,6406,
+6,9,35,6406,
+8,16,32,6406,
+11,18,30,6406,
+2,21,30,6406,
+0,16,33,6406,
+12,24,25,6406,
+0,7,36,6406,
+0,11,35,6406,
+12,19,29,6406,
+16,19,27,6414,
+1,16,33,6414,
+5,5,36,6414,
+8,21,29,6414,
+11,21,28,6414,
+1,7,36,6414,
+1,11,35,6414,
+5,19,31,6414,
+19,19,25,6444,
+17,23,23,6444,
+4,6,36,6444,
+0,18,32,6444,
+14,24,24,6444,
+6,23,28,6444,
+17,22,24,6456,
+7,12,34,6456,
+12,23,26,6456,
+2,7,36,6456,
+1,18,32,6456,
+10,15,32,6456,
+6,17,32,6456,
+2,16,33,6456,
+7,20,30,6456,
+9,22,28,6456,
+18,20,25,6456,
+8,18,31,6456,
+8,14,33,6456,
+14,23,25,6456,
+5,22,29,6456,
+5,10,35,6456,
+15,15,30,6456,
+6,15,33,6456,
+10,25,25,6456,
+2,11,35,6456,
+10,17,31,6456,
+5,13,34,6456,
+7,25,26,6456,
+3,21,30,6456,
+2,18,32,6456,
+10,24,26,6456,
+0,14,34,6456,
+14,16,30,6456,
+0,26,26,6456,
+1,14,34,6456,
+8,8,35,6456,
+14,14,31,6456,
+16,16,29,6456,
+1,26,26,6456,
+13,20,28,6456,
+11,12,33,6456,
+7,24,27,6456,
+15,20,27,6463,
+3,7,36,6463,
+3,16,33,6463,
+0,25,27,6463,
+15,17,29,6463,
+1,25,27,6463,
+3,11,35,6463,
+7,9,35,6463,
+17,21,25,6487,
+13,15,31,6487,
+2,26,26,6487,
+10,10,34,6487,
+2,14,34,6487,
+14,22,26,6487,
+4,21,30,6487,
+3,18,32,6487,
+12,22,27,6487,
+5,6,36,6487,
+9,11,34,6487,
+10,23,27,6487,
+10,13,33,6487,
+2,25,27,6487,
+6,19,31,6487,
+13,17,30,6487,
+0,8,36,6487,
+0,24,28,6487,
+4,16,33,6487,
+0,20,31,6487,
+4,7,36,6487,
+9,16,32,6487,
+1,24,28,6487,
+6,10,35,6487,
+14,18,29,6487,
+1,8,36,6487,
+12,16,31,6487,
+6,13,34,6487,
+16,23,24,6523,
+10,19,30,6523,
+18,19,26,6523,
+3,14,34,6523,
+3,26,26,6523,
+6,22,29,6523,
+7,23,28,6523,
+17,17,28,6523,
+11,20,29,6523,
+4,11,35,6523,
+13,13,32,6523,
+1,20,31,6523,
+7,17,32,6523,
+9,21,29,6523,
+7,15,33,6523,
+3,25,27,6523,
+4,18,32,6523,
+16,18,28,6523,
+2,24,28,6523,
+8,20,30,6523,
+8,12,34,6523,
+2,8,36,6523,
+12,14,32,6523,
+8,25,26,6523,
+16,22,25,6545,
+2,20,31,6545,
+17,20,26,6545,
+5,21,30,6545,
+14,21,27,6545,
+21,21,22,6575,
+9,18,31,6575,
+9,14,33,6575,
+4,14,34,6575,
+12,18,30,6575,
+4,26,26,6575,
+20,22,22,6584,
+10,22,28,6584,
+6,6,36,6584,
+12,21,28,6584,
+0,0,37,6584,
+0,12,35,6584,
+8,24,27,6584,
+3,24,28,6584,
+3,8,36,6584,
+15,19,28,6584,
+13,24,25,6584,
+5,7,36,6584,
+20,21,23,6603,
+0,23,29,6603,
+5,16,33,6603,
+3,20,31,6603,
+0,1,37,6603,
+11,15,32,6603,
+4,25,27,6603,
+8,9,35,6603,
+1,12,35,6603,
+1,1,37,6603,
+1,23,29,6603,
+13,19,29,6603,
+11,17,31,6603,
+7,19,31,6603,
+5,11,35,6603,
+11,25,25,6603,
+11,24,26,6603,
+0,2,37,6603,
+5,18,32,6603,
+2,12,35,6603,
+16,21,26,6603,
+2,23,29,6603,
+1,2,37,6603,
+13,23,26,6603,
+7,10,35,6603,
+7,22,29,6603,
+19,22,23,6624,
+7,13,34,6624,
+4,8,36,6624,
+20,20,24,6633,
+4,24,28,6633,
+18,18,27,6633,
+10,11,34,6633,
+2,2,37,6633,
+5,26,26,6633,
+4,20,31,6633,
+15,24,24,6633,
+5,14,34,6633,
+12,12,33,6633,
+8,17,32,6633,
+6,21,30,6633,
+8,23,28,6633,
+0,9,36,6633,
+1,9,36,6633,
+0,17,33,6633,
+8,15,33,6633,
+19,21,24,6648,
+0,3,37,6648,
+3,12,35,6648,
+15,23,25,6648,
+5,25,27,6648,
+11,13,33,6648,
+17,19,27,6648,
+3,23,29,6648,
+11,23,27,6648,
+1,17,33,6648,
+1,3,37,6648,
+10,16,32,6648,
+14,20,28,6648,
+6,16,33,6648,
+2,9,36,6648,
+6,7,36,6648,
+9,12,34,6648,
+0,15,34,6648,
+9,20,30,6648,
+15,16,30,6648,
+2,17,33,6648,
+10,21,29,6648,
+18,23,23,6673,
+13,22,27,6673,
+9,25,26,6673,
+6,11,35,6673,
+2,3,37,6673,
+1,15,34,6673,
+11,19,30,6673,
+14,15,31,6673,
+18,22,24,6682,
+6,18,32,6682,
+0,22,30,6682,
+0,19,32,6682,
+1,22,30,6682,
+0,4,37,6682,
+2,15,34,6682,
+10,18,31,6682,
+4,12,35,6682,
+12,20,29,6682,
+16,20,27,6682,
+5,8,36,6682,
+10,14,33,6682,
+5,24,28,6682,
+14,17,30,6682,
+15,22,26,6682,
+1,4,37,6682,
+8,19,31,6682,
+3,9,36,6682,
+4,23,29,6682,
+19,20,25,6692,
+1,19,32,6692,
+5,20,31,6692,
+16,17,29,6692,
+13,16,31,6692,
+9,24,27,6692,
+3,17,33,6692,
+9,9,35,6692,
+3,3,37,6692,
+2,22,30,6692,
+6,14,34,6692,
+6,26,26,6692,
+8,10,35,6692,
+11,22,28,6692,
+2,4,37,6692,
+13,14,32,6692,
+2,19,32,6692,
+8,22,29,6692,
+8,13,34,6692,
+3,15,34,6692,
+7,21,30,6692,
+18,21,25,6713,
+6,25,27,6713,
+15,18,29,6713,
+12,15,32,6713,
+3,22,30,6713,
+13,18,30,6713,
+4,9,36,6713,
+9,23,28,6713,
+7,7,36,6713,
+13,21,28,6713,
+0,5,37,6713,
+4,17,33,6713,
+7,16,33,6713,
+0,13,35,6713,
+5,12,35,6713,
+9,17,32,6713,
+12,25,25,6713,
+3,19,32,6713,
+12,17,31,6713,
+17,23,24,6734,
+3,4,37,6734,
+7,11,35,6734,
+15,21,27,6734,
+9,15,33,6734,
+1,5,37,6734,
+5,23,29,6734,
+1,13,35,6734,
+0,10,36,6734,
+6,8,36,6734,
+12,24,26,6734,
+6,24,28,6734,
+4,15,34,6734,
+1,10,36,6734,
+14,24,25,6734,
+17,18,28,6734,
+7,18,32,6734,
+6,20,31,6734,
+19,19,26,6757,
+2,5,37,6757,
+11,11,34,6757,
+2,13,35,6757,
+14,19,29,6757,
+17,22,25,6757,
+10,20,30,6757,
+2,10,36,6757,
+4,22,30,6757,
+18,20,26,6768,
+10,12,34,6768,
+7,14,34,6768,
+16,19,28,6768,
+7,26,26,6768,
+4,4,37,6768,
+11,16,32,6768,
+10,25,26,6768,
+4,19,32,6768,
+14,23,26,6768,
+12,13,33,6768,
+5,9,36,6768,
+0,21,31,6768,
+12,23,27,6768,
+7,25,27,6768,
+5,17,33,6768,
+11,21,29,6768,
+1,21,31,6768,
+3,5,37,6768,
+9,19,31,6768,
+3,13,35,6768,
+6,12,35,6768,
+0,6,37,6768,
+10,24,27,6768,
+0,26,27,6768,
+12,19,30,6768,
+3,10,36,6768,
+8,21,30,6768,
+9,22,29,6768,
+1,6,37,6768,
+9,10,35,6768,
+11,18,31,6768,
+11,14,33,6768,
+6,23,29,6768,
+5,15,34,6768,
+2,21,31,6768,
+1,26,27,6768,
+17,21,26,6805,
+9,13,34,6805,
+16,24,24,6814,
+2,6,37,6814,
+21,22,22,6832,
+14,22,27,6832,
+15,20,28,6832,
+5,22,30,6832,
+0,25,28,6832,
+7,8,36,6832,
+2,26,27,6832,
+8,16,33,6832,
+7,24,28,6832,
+16,23,25,6832,
+4,5,37,6832,
+7,20,31,6832,
+5,19,32,6832,
+13,20,29,6832,
+4,13,35,6832,
+8,11,35,6832,
+1,25,28,6832,
+3,21,31,6832,
+15,15,31,6832,
+21,21,23,6849,
+16,16,30,6849,
+0,16,34,6849,
+4,10,36,6849,
+12,22,28,6849,
+8,18,32,6849,
+20,22,23,6866,
+2,25,28,6866,
+6,9,36,6866,
+10,17,32,6866,
+0,18,33,6866,
+10,23,28,6866,
+14,16,31,6866,
+1,16,34,6866,
+6,17,33,6866,
+10,15,33,6866,
+3,26,27,6866,
+3,6,37,6866,
+1,18,33,6866,
+15,17,30,6866,
+18,19,27,6866,
+2,16,34,6866,
+14,14,32,6866,
+8,26,26,6866,
+16,22,26,6866,
+8,14,34,6866,
+20,21,24,6891,
+0,11,36,6891,
+2,18,33,6891,
+6,15,34,6891,
+0,24,29,6891,
+7,12,35,6891,
+4,21,31,6891,
+0,7,37,6891,
+8,25,27,6891,
+17,20,27,6891,
+1,11,36,6891,
+3,25,28,6891,
+13,15,32,6891,
+1,24,29,6891,
+7,23,29,6891,
+17,17,29,6891,
+5,13,35,6891,
+13,17,31,6891,
+1,7,37,6891,
+13,25,25,6891,
+19,23,23,6909,
+5,5,37,6909,
+6,22,30,6909,
+14,18,30,6909,
+16,18,29,6909,
+5,10,36,6909,
+6,19,32,6909,
+4,26,27,6909,
+2,11,36,6909,
+14,21,28,6909,
+11,12,34,6909,
+2,24,29,6909,
+11,20,30,6909,
+3,16,34,6909,
+4,6,37,6909,
+13,24,26,6909,
+19,22,24,6915,
+0,14,35,6915,
+2,7,37,6915,
+1,14,35,6915,
+10,19,31,6915,
+3,18,33,6915,
+9,21,30,6915,
+11,25,26,6915,
+0,20,32,6915,
+12,16,32,6915,
+8,8,36,6915,
+8,24,28,6915,
+8,20,31,6915,
+1,20,32,6915,
+4,25,28,6915,
+10,13,34,6915,
+10,10,35,6915,
+20,20,25,6938,
+2,14,35,6938,
+10,22,29,6938,
+9,16,33,6938,
+11,24,27,6938,
+7,9,36,6938,
+3,24,29,6938,
+16,21,27,6938,
+12,21,29,6938,
+15,24,25,6938,
+3,11,36,6938,
+7,17,33,6938,
+13,13,33,6938,
+3,7,37,6938,
+15,19,29,6938,
+19,21,25,6949,
+13,23,27,6949,
+5,21,31,6949,
+9,11,35,6949,
+4,16,34,6949,
+2,20,32,6949,
+9,18,32,6949,
+0,23,30,6949,
+12,14,33,6949,
+12,18,31,6949,
+4,18,33,6949,
+18,23,24,6971,
+3,14,35,6971,
+6,13,35,6971,
+15,23,26,6971,
+5,26,27,6971,
+13,19,30,6971,
+7,15,34,6971,
+5,6,37,6971,
+1,23,30,6971,
+6,10,36,6971,
+18,18,28,6971,
+3,20,32,6971,
+18,22,25,6986,
+8,12,35,6986,
+2,23,30,6986,
+4,11,36,6986,
+9,26,26,6986,
+9,14,34,6986,
+4,24,29,6986,
+7,22,30,6986,
+0,8,37,6986,
+7,19,32,6986,
+11,23,28,6986,
+11,17,32,6986,
+1,8,37,6986,
+8,23,29,6986,
+5,25,28,6986,
+4,7,37,6986,
+17,19,28,6986,
+11,15,33,6986,
+9,25,27,6986,
+14,20,29,6986,
+2,8,37,6986,
+5,16,34,6986,
+13,22,28,6986,
+19,20,26,7019,
+4,14,35,7019,
+3,23,30,7019,
+5,18,33,7019,
+6,21,31,7019,
+15,22,27,7019,
+4,20,32,7019,
+0,12,36,7019,
+16,20,28,7019,
+6,26,27,7019,
+18,21,26,7036,
+10,21,30,7036,
+17,24,24,7036,
+1,12,36,7036,
+8,9,36,7036,
+9,24,28,7036,
+6,6,37,7036,
+8,17,33,7036,
+5,24,29,7036,
+3,8,37,7036,
+9,20,31,7036,
+5,11,36,7036,
+15,16,31,7036,
+11,19,31,7036,
+17,23,25,7050,
+7,13,35,7050,
+5,7,37,7050,
+12,20,30,7050,
+12,12,34,7050,
+0,0,38,7050,
+2,12,36,7050,
+8,15,34,7050,
+4,23,30,7050,
+0,17,34,7050,
+7,10,36,7050,
+12,25,26,7050,
+6,25,28,7050,
+16,17,30,7050,
+0,1,38,7050,
+0,22,31,7050,
+10,16,33,7050,
+14,15,32,7050,
+1,22,31,7050,
+1,17,34,7050,
+1,1,38,7050,
+11,13,34,7050,
+11,22,29,7050,
+14,25,25,7050,
+5,14,35,7050,
+10,11,35,7050,
+14,17,31,7050,
+0,2,38,7050,
+10,18,32,7050,
+14,24,26,7054,
+6,16,34,7054,
+8,22,30,7054,
+3,12,36,7054,
+2,22,31,7054,
+1,2,38,7054,
+12,24,27,7054,
+17,22,26,7088,
+8,19,32,7088,
+5,20,32,7088,
+13,16,32,7088,
+2,17,34,7088,
+15,18,30,7088,
+4,8,37,7088,
+6,18,33,7088,
+0,15,35,7088,
+15,21,28,7088,
+0,9,37,7088,
+9,12,35,7088,
+0,19,33,7088,
+19,19,27,7097,
+9,23,29,7097,
+13,21,29,7097,
+7,21,31,7097,
+1,9,37,7097,
+1,19,33,7097,
+1,15,35,7097,
+22,22,22,7115,
+2,2,38,7115,
+10,14,34,7115,
+10,26,26,7115,
+6,24,29,7115,
+18,20,27,7115,
+6,11,36,7115,
+0,3,38,7115,
+2,19,33,7115,
+10,25,27,7115,
+2,9,37,7115,
+14,23,27,7115,
+13,18,31,7115,
+13,14,33,7115,
+3,17,34,7115,
+6,7,37,7115,
+17,18,29,7115,
+2,15,35,7115,
+1,3,38,7115,
+3,22,31,7115,
+7,26,27,7115,
+21,22,23,7131,
+5,23,30,7131,
+4,12,36,7131,
+2,3,38,7131,
+14,19,30,7131,
+12,17,32,7131,
+6,14,35,7131,
+12,23,28,7131,
+16,24,25,7131,
+16,19,29,7131,
+12,15,33,7131,
+8,13,35,7131,
+20,23,23,7160,
+21,21,24,7160,
+5,8,37,7160,
+7,25,28,7160,
+0,27,27,7160,
+9,9,36,7160,
+3,15,35,7160,
+3,9,37,7160,
+3,19,33,7160,
+1,27,27,7160,
+9,17,33,7160,
+17,21,27,7160,
+0,4,38,7160,
+20,22,24,7166,
+10,24,28,7166,
+0,26,28,7166,
+6,20,32,7166,
+8,10,36,7166,
+1,26,28,7166,
+4,22,31,7166,
+1,4,38,7166,
+10,20,31,7166,
+16,23,26,7166,
+4,17,34,7166,
+7,16,34,7166,
+7,18,33,7166,
+2,27,27,7166,
+3,3,38,7166,
+9,15,34,7166,
+11,21,30,7166,
+2,26,28,7166,
+2,4,38,7166,
+14,22,28,7166,
+0,13,36,7166,
+0,21,32,7166,
+6,23,30,7166,
+9,22,30,7166,
+5,12,36,7166,
+0,25,29,7166,
+12,19,31,7166,
+4,15,35,7166,
+8,21,31,7166,
+4,19,33,7166,
+11,16,33,7166,
+15,20,29,7166,
+7,24,29,7166,
+7,11,36,7166,
+1,21,32,7166,
+9,19,32,7166,
+20,21,25,7207,
+1,13,36,7207,
+19,23,24,7207,
+4,9,37,7207,
+3,27,27,7207,
+11,11,35,7207,
+7,7,37,7207,
+1,25,29,7207,
+12,22,29,7207,
+2,13,36,7207,
+6,8,37,7207,
+3,26,28,7207,
+3,4,38,7207,
+18,19,28,7207,
+0,5,38,7207,
+16,22,27,7207,
+0,10,37,7207,
+2,21,32,7207,
+11,18,32,7207,
+12,13,34,7207,
+13,20,30,7207,
+8,26,27,7207,
+10,12,35,7207,
+5,22,31,7207,
+2,25,29,7207,
+7,14,35,7207,
+19,22,25,7237,
+1,5,38,7237,
+10,23,29,7237,
+1,10,37,7237,
+13,25,26,7237,
+5,17,34,7237,
+2,10,37,7237,
+8,25,28,7237,
+7,20,32,7237,
+17,20,28,7237,
+2,5,38,7237,
+11,14,34,7237,
+16,16,31,7237,
+11,26,26,7237,
+3,13,36,7237,
+3,21,32,7237,
+4,27,27,7237,
+13,24,27,7237,
+15,15,32,7237,
+5,9,37,7237,
+11,25,27,7237,
+9,13,35,7237,
+3,25,29,7237,
+15,17,31,7237,
+15,25,25,7240,
+5,15,35,7240,
+5,19,33,7240,
+4,26,28,7240,
+6,12,36,7240,
+8,16,34,7240,
+0,24,30,7240,
+4,4,38,7240,
+20,20,26,7264,
+14,16,32,7264,
+18,24,24,7264,
+1,24,30,7264,
+8,18,33,7264,
+9,10,36,7264,
+15,24,26,7264,
+17,17,30,7264,
+10,17,33,7264,
+3,5,38,7264,
+19,21,26,7280,
+7,23,30,7280,
+18,23,25,7280,
+3,10,37,7280,
+14,21,29,7280,
+16,18,30,7280,
+0,18,34,7280,
+2,24,30,7280,
+0,6,38,7280,
+14,18,31,7280,
+0,16,35,7280,
+6,17,34,7280,
+11,24,28,7280,
+4,21,32,7280,
+4,13,36,7280,
+1,18,34,7280,
+6,22,31,7280,
+14,14,33,7280,
+8,24,29,7280,
+8,11,36,7280,
+1,6,38,7280,
+10,15,34,7280,
+16,21,28,7280,
+1,16,35,7280,
+4,25,29,7280,
+11,20,31,7280,
+13,23,28,7280,
+7,8,37,7280,
+13,17,32,7280,
+13,15,33,7280,
+9,21,31,7280,
+5,27,27,7280,
+15,23,27,7288,
+2,18,34,7288,
+10,22,30,7288,
+2,6,38,7288,
+18,22,26,7303,
+3,24,30,7303,
+4,5,38,7303,
+5,26,28,7303,
+4,10,37,7303,
+2,16,35,7303,
+10,19,32,7303,
+12,21,30,7303,
+8,14,35,7303,
+15,19,30,7303,
+9,26,27,7303,
+6,9,37,7303,
+6,15,35,7303,
+6,19,33,7303,
+8,20,32,7303,
+18,18,29,7309,
+7,12,36,7309,
+3,18,34,7309,
+0,20,33,7309,
+12,16,33,7309,
+3,6,38,7309,
+11,12,35,7309,
+3,16,35,7309,
+5,21,32,7309,
+0,23,31,7309,
+0,11,37,7309,
+19,20,27,7349,
+17,24,25,7349,
+1,20,33,7349,
+5,13,36,7349,
+9,25,28,7349,
+17,19,29,7349,
+11,23,29,7349,
+1,23,31,7349,
+13,19,31,7349,
+5,25,29,7349,
+1,11,37,7349,
+12,18,32,7349,
+4,24,30,7349,
+0,14,36,7349,
+15,22,28,7349,
+1,14,36,7349,
+9,16,34,7349,
+0,7,38,7349,
+8,23,30,7349,
+2,20,33,7349,
+17,23,26,7379,
+18,21,27,7379,
+7,17,34,7379,
+5,10,37,7379,
+13,13,34,7379,
+2,11,37,7379,
+5,5,38,7379,
+10,13,35,7379,
+9,18,33,7379,
+2,23,31,7379,
+1,7,38,7379,
+7,22,31,7379,
+13,22,29,7379,
+6,27,27,7379,
+14,20,30,7379,
+12,26,26,7379,
+4,18,34,7379,
+12,14,34,7379,
+4,6,38,7379,
+6,26,28,7379,
+2,14,36,7379,
+10,10,36,7379,
+8,8,37,7379,
+2,7,38,7379,
+14,25,26,7379,
+16,20,29,7379,
+22,22,23,7406,
+4,16,35,7406,
+9,24,29,7406,
+12,25,27,7406,
+9,11,36,7406,
+3,20,33,7406,
+7,19,33,7406,
+3,23,31,7406,
+7,9,37,7406,
+21,23,23,7422,
+3,11,37,7422,
+11,17,33,7422,
+7,15,35,7422,
+5,24,30,7422,
+21,22,24,7443,
+14,24,27,7443,
+6,13,36,7443,
+6,21,32,7443,
+3,14,36,7443,
+3,7,38,7443,
+9,14,35,7443,
+17,22,27,7443,
+10,21,31,7443,
+6,25,29,7443,
+11,15,34,7443,
+8,12,36,7443,
+12,24,28,7443,
+9,20,32,7443,
+5,18,34,7443,
+5,6,38,7443,
+15,16,32,7443,
+6,10,37,7443,
+4,20,33,7443,
+10,26,27,7443,
+20,23,24,7470,
+11,22,30,7470,
+12,20,31,7470,
+5,16,35,7470,
+16,25,25,7470,
+16,17,31,7470,
+19,19,28,7470,
+4,11,37,7470,
+4,23,31,7470,
+11,19,32,7470,
+21,21,25,7479,
+7,27,27,7479,
+15,21,29,7479,
+0,8,38,7479,
+0,22,32,7479,
+4,14,36,7479,
+18,20,28,7479,
+16,24,26,7479,
+1,22,32,7479,
+20,22,25,7486,
+14,23,28,7486,
+8,17,34,7486,
+1,8,38,7486,
+8,22,31,7486,
+14,17,32,7486,
+7,26,28,7486,
+4,7,38,7486,
+10,25,28,7486,
+14,15,33,7486,
+13,21,30,7486,
+15,18,31,7486,
+9,23,30,7486,
+6,24,30,7486,
+2,22,32,7486,
+2,8,38,7486,
+10,16,34,7486,
+0,12,37,7486,
+19,24,24,7509,
+0,27,28,7509,
+17,18,30,7509,
+10,18,33,7509,
+12,12,35,7509,
+12,23,29,7509,
+13,16,33,7509,
+0,17,35,7509,
+17,21,28,7509,
+5,20,33,7509,
+1,27,28,7509,
+8,15,35,7509,
+1,12,37,7509,
+8,19,33,7509,
+7,21,32,7509,
+16,23,27,7509,
+7,13,36,7509,
+8,9,37,7509,
+7,25,29,7509,
+5,11,37,7509,
+11,13,35,7509,
+5,23,31,7509,
+19,23,25,7521,
+1,17,35,7521,
+6,18,34,7521,
+6,6,38,7521,
+6,16,35,7521,
+5,14,36,7521,
+2,12,37,7521,
+2,27,28,7521,
+3,22,32,7521,
+3,8,38,7521,
+20,21,26,7533,
+10,24,29,7533,
+0,19,34,7533,
+0,26,29,7533,
+16,19,30,7533,
+10,11,36,7533,
+13,18,32,7533,
+7,10,37,7533,
+2,17,35,7533,
+14,19,31,7533,
+1,19,34,7533,
+5,7,38,7533,
+1,26,29,7533,
+19,22,26,7553,
+9,12,36,7553,
+14,22,29,7553,
+2,19,34,7553,
+0,0,39,7553,
+13,26,26,7553,
+13,14,34,7553,
+0,15,36,7553,
+10,14,35,7553,
+2,26,29,7553,
+1,15,36,7553,
+12,17,33,7553,
+0,1,39,7553,
+8,27,27,7553,
+3,27,28,7553,
+3,12,37,7553,
+1,1,39,7553,
+3,17,35,7553,
+13,25,27,7553,
+11,21,31,7553,
+8,26,28,7553,
+10,20,32,7553,
+16,22,28,7553,
+4,22,32,7553,
+4,8,38,7553,
+7,24,30,7553,
+12,15,34,7553,
+6,20,33,7553,
+0,2,39,7553,
+2,15,36,7553,
+18,24,25,7582,
+0,9,38,7582,
+0,25,30,7582,
+15,20,30,7582,
+11,26,27,7582,
+1,9,38,7582,
+9,17,34,7582,
+1,2,39,7582,
+18,19,29,7582,
+6,23,31,7582,
+1,25,30,7582,
+6,11,37,7582,
+15,25,26,7582,
+9,22,31,7582,
+3,19,34,7582,
+3,26,29,7582,
+12,22,30,7582,
+6,14,36,7582,
+20,20,27,7609,
+7,18,34,7609,
+18,23,26,7609,
+2,25,30,7609,
+2,9,38,7609,
+2,2,39,7609,
+8,21,32,7609,
+12,19,32,7609,
+10,23,30,7609,
+6,7,38,7609,
+4,12,37,7609,
+4,27,28,7609,
+8,13,36,7609,
+13,24,28,7609,
+17,20,29,7609,
+15,24,27,7609,
+3,15,36,7609,
+11,25,28,7609,
+0,3,39,7609,
+0,21,33,7609,
+4,17,35,7609,
+7,16,35,7609,
+8,25,29,7609,
+13,20,31,7609,
+1,21,33,7609,
+19,21,27,7627,
+9,15,35,7627,
+1,3,39,7627,
+9,9,37,7627,
+9,19,33,7627,
+4,26,29,7627,
+11,16,34,7627,
+5,22,32,7627,
+8,10,37,7627,
+5,8,38,7627,
+4,19,34,7627,
+11,18,33,7627,
+2,3,39,7627,
+3,9,38,7627,
+2,21,33,7627,
+3,25,30,7627,
+16,16,32,7627,
+0,4,39,7627,
+18,22,27,7661,
+4,15,36,7661,
+14,21,30,7661,
+0,24,31,7661,
+11,24,29,7661,
+11,11,36,7661,
+15,23,28,7661,
+5,12,37,7661,
+15,17,32,7661,
+7,20,33,7661,
+1,4,39,7661,
+5,27,28,7661,
+0,13,37,7661,
+12,13,35,7661,
+1,24,31,7661,
+16,21,29,7661,
+1,13,37,7661,
+13,23,29,7661,
+5,17,35,7661,
+17,25,25,7675,
+9,27,27,7675,
+3,21,33,7675,
+17,17,31,7675,
+15,15,33,7675,
+7,11,37,7675,
+7,23,31,7675,
+3,3,39,7675,
+10,12,36,7675,
+8,24,30,7675,
+4,9,38,7675,
+17,24,26,7684,
+14,16,33,7684,
+2,4,39,7684,
+9,26,28,7684,
+7,14,36,7684,
+16,18,31,7684,
+4,25,30,7684,
+2,24,31,7684,
+5,19,34,7684,
+2,13,37,7684,
+7,7,38,7684,
+5,26,29,7684,
+11,14,35,7684,
+22,23,23,7715,
+6,8,38,7715,
+8,18,34,7715,
+22,22,24,7724,
+14,18,32,7724,
+6,22,32,7724,
+0,10,38,7724,
+19,20,28,7724,
+1,10,38,7724,
+8,16,35,7724,
+11,20,32,7724,
+10,22,31,7724,
+10,17,34,7724,
+9,21,32,7724,
+12,21,31,7724,
+9,13,36,7724,
+3,4,39,7724,
+3,24,31,7724,
+0,5,39,7724,
+21,23,24,7740,
+5,15,36,7740,
+4,21,33,7740,
+15,19,31,7740,
+1,5,39,7740,
+9,25,29,7740,
+3,13,37,7740,
+13,17,33,7740,
+17,23,27,7740,
+14,26,26,7740,
+18,18,30,7740,
+14,14,34,7740,
+2,10,38,7740,
+0,18,35,7740,
+6,27,28,7740,
+12,26,27,7740,
+18,21,28,7740,
+6,12,37,7740,
+10,15,35,7740,
+1,18,35,7740,
+15,22,29,7740,
+14,25,27,7740,
+5,25,30,7740,
+11,23,30,7740,
+21,22,25,7762,
+2,5,39,7762,
+9,10,37,7762,
+10,19,33,7762,
+13,15,34,7762,
+17,19,30,7762,
+5,9,38,7762,
+6,17,35,7762,
+0,16,36,7762,
+20,24,24,7773,
+4,4,39,7773,
+12,25,28,7773,
+13,22,30,7773,
+3,10,38,7773,
+2,18,35,7773,
+6,19,34,7773,
+4,24,31,7773,
+0,23,32,7773,
+1,16,36,7773,
+8,20,33,7773,
+6,26,29,7773,
+8,11,37,7773,
+20,23,25,7786,
+1,23,32,7786,
+4,13,37,7786,
+8,23,31,7786,
+13,19,32,7786,
+3,5,39,7786,
+5,21,33,7786,
+8,14,36,7786,
+14,24,28,7786,
+2,16,36,7786,
+0,20,34,7786,
+12,16,34,7786,
+16,20,30,7786,
+14,20,31,7786,
+9,24,30,7786,
+16,25,26,7786,
+0,6,39,7786,
+7,8,38,7786,
+12,18,33,7786,
+2,23,32,7786,
+7,22,32,7786,
+6,15,36,7786,
+1,20,34,7786,
+17,22,28,7786,
+10,27,27,7786,
+1,6,39,7786,
+21,21,26,7802,
+3,18,35,7802,
+4,10,38,7802,
+10,26,28,7802,
+2,20,34,7802,
+20,22,26,7814,
+6,9,38,7814,
+11,12,36,7814,
+6,25,30,7814,
+3,16,36,7814,
+9,18,34,7814,
+12,24,29,7814,
+16,24,27,7814,
+2,6,39,7814,
+5,24,31,7814,
+19,24,25,7832,
+9,16,35,7832,
+3,23,32,7832,
+7,12,37,7832,
+7,27,28,7832,
+4,5,39,7832,
+5,13,37,7832,
+7,17,35,7832,
+13,13,35,7832,
+19,19,29,7832,
+10,21,32,7832,
+18,20,29,7832,
+4,18,35,7832,
+0,11,38,7832,
+12,14,35,7832,
+0,14,37,7832,
+10,13,36,7832,
+3,20,34,7832,
+11,17,34,7832,
+11,22,31,7832,
+1,11,38,7832,
+7,19,34,7832,
+7,26,29,7832,
+3,6,39,7832,
+19,23,26,7855,
+15,21,30,7855,
+6,21,33,7855,
+1,14,37,7855,
+14,23,29,7855,
+10,25,29,7855,
+4,16,36,7855,
+0,28,28,7855,
+12,20,32,7855,
+4,23,32,7855,
+2,14,37,7855,
+2,11,38,7855,
+5,10,38,7855,
+16,17,32,7855,
+1,28,28,7855,
+10,10,37,7855,
+16,23,28,7855,
+15,16,33,7855,
+20,21,27,7888,
+9,20,33,7888,
+0,27,29,7888,
+0,7,39,7888,
+7,15,36,7888,
+1,7,39,7888,
+13,21,31,7888,
+11,19,33,7888,
+17,21,29,7888,
+5,5,39,7888,
+9,23,31,7888,
+11,15,35,7888,
+9,11,37,7888,
+1,27,29,7888,
+2,28,28,7888,
+8,22,32,7888,
+8,8,38,7888,
+4,20,34,7888,
+12,23,30,7888,
+6,24,31,7888,
+15,18,32,7888,
+0,22,33,7888,
+4,6,39,7888,
+9,14,36,7888,
+6,13,37,7888,
+7,9,38,7888,
+17,18,31,7888,
+18,25,25,7902,
+2,7,39,7902,
+14,17,33,7902,
+5,18,35,7902,
+13,26,27,7902,
+3,14,37,7902,
+3,11,38,7902,
+19,22,27,7902,
+2,27,29,7902,
+1,22,33,7902,
+7,25,30,7902,
+0,26,30,7902,
+18,24,26,7914,
+10,24,30,7914,
+8,12,37,7914,
+2,22,33,7914,
+15,26,26,7914,
+1,26,30,7914,
+3,28,28,7914,
+5,16,36,7914,
+8,27,28,7914,
+14,15,34,7914,
+16,19,31,7914,
+5,23,32,7914,
+13,25,28,7914,
+8,17,35,7914,
+3,27,29,7914,
+7,21,33,7914,
+3,7,39,7914,
+15,25,27,7914,
+11,27,27,7914,
+6,10,38,7914,
+14,22,30,7914,
+10,18,34,7914,
+2,26,30,7914,
+8,26,29,7914,
+11,26,28,7914,
+16,22,29,7924,
+13,16,34,7924,
+5,20,34,7924,
+4,11,38,7924,
+10,16,35,7924,
+4,14,37,7924,
+8,19,34,7924,
+14,19,32,7924,
+18,23,27,7959,
+3,22,33,7959,
+5,6,39,7959,
+13,18,33,7959,
+20,20,28,7966,
+12,12,36,7966,
+4,28,28,7966,
+15,24,28,7966,
+6,18,35,7966,
+18,19,30,7966,
+0,8,39,7966,
+0,17,36,7966,
+8,15,36,7966,
+3,26,30,7966,
+1,17,36,7966,
+11,13,36,7966,
+0,25,31,7966,
+13,24,29,7966,
+19,21,28,7980,
+1,8,39,7980,
+4,27,29,7980,
+11,21,32,7980,
+4,7,39,7980,
+15,20,31,7980,
+0,19,35,7980,
+7,24,31,7980,
+23,23,23,8009,
+11,25,29,8009,
+7,13,37,8009,
+1,19,35,8009,
+1,25,31,8009,
+0,12,38,8009,
+6,16,36,8009,
+12,22,31,8009,
+17,20,30,8009,
+4,22,33,8009,
+8,25,30,8009,
+6,23,32,8009,
+1,12,38,8009,
+22,23,24,8022,
+8,9,38,8022,
+9,22,32,8022,
+2,8,39,8022,
+12,17,34,8022,
+2,17,36,8022,
+10,20,33,8022,
+17,25,26,8022,
+10,23,31,8022,
+5,11,38,8022,
+13,14,35,8022,
+2,25,31,8022,
+5,14,37,8022,
+10,11,37,8022,
+2,19,35,8022,
+2,12,38,8022,
+10,14,36,8022,
+6,20,34,8022,
+18,22,28,8022,
+4,26,30,8022,
+7,10,38,8022,
+21,24,24,8052,
+6,6,39,8052,
+22,22,25,8052,
+5,28,28,8052,
+13,20,32,8052,
+8,21,33,8052,
+0,15,37,8052,
+9,27,28,8052,
+9,12,37,8052,
+12,15,35,8052,
+17,24,27,8052,
+12,19,33,8052,
+3,8,39,8052,
+3,17,36,8052,
+15,23,29,8052,
+3,19,35,8052,
+5,7,39,8052,
+3,25,31,8052,
+9,17,35,8052,
+21,23,25,8064,
+5,27,29,8064,
+1,15,37,8064,
+16,21,30,8064,
+3,12,38,8064,
+11,24,30,8064,
+0,21,34,8064,
+5,22,33,8064,
+2,15,37,8064,
+14,21,31,8064,
+13,23,30,8064,
+9,19,34,8064,
+9,26,29,8064,
+7,18,35,8064,
+1,21,34,8064,
+0,24,32,8064,
+0,0,40,8064,
+5,26,30,8064,
+11,18,34,8064,
+7,16,36,8064,
+2,21,34,8064,
+6,14,37,8064,
+0,1,40,8064,
+4,17,36,8064,
+21,22,26,8107,
+20,24,25,8107,
+4,8,39,8107,
+16,16,33,8107,
+6,11,38,8107,
+1,24,32,8107,
+14,26,27,8107,
+8,24,31,8107,
+11,16,35,8107,
+1,1,40,8107,
+19,20,29,8107,
+0,9,39,8107,
+8,13,37,8107,
+7,23,32,8107,
+4,25,31,8107,
+17,23,28,8107,
+4,19,35,8107,
+17,17,32,8107,
+12,27,27,8107,
+9,15,36,8107,
+15,17,33,8107,
+1,9,39,8107,
+3,15,37,8107,
+0,2,40,8107,
+12,26,28,8107,
+4,12,38,8107,
+2,24,32,8107,
+6,28,28,8107,
+16,18,32,8107,
+14,25,28,8107,
+1,2,40,8107,
+7,20,34,8107,
+20,23,26,8129,
+2,9,39,8129,
+6,7,39,8129,
+15,15,34,8129,
+3,21,34,8129,
+6,27,29,8129,
+18,21,29,8129,
+9,9,38,8129,
+9,25,30,8129,
+2,2,40,8129,
+14,16,34,8129,
+10,22,32,8129,
+8,10,38,8129,
+16,26,26,8129,
+0,3,40,8129,
+6,22,33,8129,
+18,18,31,8129,
+3,24,32,8129,
+14,18,33,8129,
+12,21,32,8129,
+15,22,30,8129,
+12,13,36,8129,
+15,19,32,8129,
+11,20,33,8129,
+5,8,39,8129,
+4,15,37,8129,
+1,3,40,8129,
+5,17,36,8129,
+12,25,29,8129,
+16,25,27,8137,
+5,25,31,8137,
+5,19,35,8137,
+11,23,31,8137,
+11,11,37,8137,
+21,21,27,8163,
+9,21,33,8163,
+19,25,25,8163,
+3,9,39,8163,
+17,19,31,8163,
+6,26,30,8163,
+10,27,28,8163,
+11,14,36,8163,
+19,24,26,8177,
+20,22,27,8177,
+5,12,38,8177,
+0,13,38,8177,
+2,3,40,8177,
+8,18,35,8177,
+4,21,34,8177,
+10,12,37,8177,
+14,24,29,8177,
+13,17,34,8177,
+7,11,38,8177,
+10,17,35,8177,
+7,14,37,8177,
+13,22,31,8177,
+1,13,38,8177,
+17,22,29,8177,
+8,16,36,8177,
+16,24,28,8177,
+4,24,32,8177,
+0,4,40,8177,
+2,13,38,8177,
+7,28,28,8177,
+10,19,34,8177,
+8,23,32,8177,
+10,26,29,8177,
+1,4,40,8177,
+14,14,35,8177,
+16,20,31,8177,
+0,23,33,8177,
+3,3,40,8177,
+9,24,31,8177,
+4,9,39,8177,
+19,23,27,8205,
+13,19,33,8205,
+9,13,37,8205,
+5,15,37,8205,
+1,23,33,8205,
+7,27,29,8205,
+13,15,35,8205,
+7,7,39,8205,
+14,20,32,8205,
+8,20,34,8205,
+12,24,30,8205,
+2,4,40,8205,
+0,18,36,8205,
+10,15,36,8205,
+1,18,36,8205,
+0,10,39,8205,
+6,17,36,8205,
+6,8,39,8205,
+6,19,35,8205,
+7,22,33,8205,
+2,23,33,8205,
+5,21,34,8205,
+3,13,38,8205,
+1,10,39,8205,
+19,19,30,8205,
+6,25,31,8205,
+12,18,34,8205,
+2,18,36,8205,
+6,12,38,8205,
+18,20,30,8210,
+5,24,32,8210,
+0,20,35,8210,
+10,25,30,8210,
+18,25,26,8243,
+0,28,29,8243,
+3,4,40,8243,
+12,16,35,8243,
+2,10,39,8243,
+14,23,30,8243,
+7,26,30,8243,
+0,5,40,8243,
+20,21,28,8243,
+0,16,37,8243,
+9,10,38,8243,
+1,20,35,8243,
+1,5,40,8243,
+1,28,29,8243,
+1,16,37,8243,
+16,23,29,8243,
+5,9,39,8243,
+3,23,33,8243,
+15,21,31,8243,
+13,27,27,8243,
+13,26,28,8243,
+8,14,37,8243,
+0,27,30,8243,
+8,11,38,8243,
+3,18,36,8243,
+2,28,29,8243,
+2,5,40,8243,
+11,22,32,8243,
+4,13,38,8243,
+2,16,37,8243,
+19,22,28,8266,
+18,24,27,8266,
+2,20,35,8266,
+6,15,37,8266,
+3,10,39,8266,
+9,18,35,8266,
+1,27,30,8266,
+15,26,27,8266,
+10,21,33,8266,
+17,21,30,8266,
+4,4,40,8266,
+8,28,28,8266,
+2,27,30,8266,
+6,21,34,8266,
+9,16,36,8266,
+12,20,33,8266,
+8,27,29,8266,
+3,16,37,8266,
+9,23,32,8266,
+4,23,33,8266,
+11,12,37,8266,
+16,17,33,8266,
+15,25,28,8270,
+3,5,40,8270,
+7,8,39,8270,
+7,17,36,8270,
+23,23,24,8326,
+3,28,29,8326,
+3,20,35,8326,
+13,13,36,8326,
+12,23,31,8326,
+11,27,28,8326,
+13,21,32,8326,
+7,25,31,8326,
+13,25,29,8326,
+11,17,35,8326,
+7,19,35,8326,
+12,14,36,8326,
+4,18,36,8326,
+0,6,40,8326,
+6,24,32,8326,
+22,24,24,8332,
+8,22,33,8332,
+15,16,34,8332,
+10,24,31,8332,
+17,18,32,8332,
+7,12,38,8332,
+9,20,34,8332,
+4,10,39,8332,
+18,23,28,8332,
+1,6,40,8332,
+0,26,31,8332,
+15,18,33,8332,
+10,13,37,8332,
+3,27,30,8332,
+22,23,25,8346,
+6,9,39,8346,
+11,19,34,8346,
+11,26,29,8346,
+1,26,31,8346,
+5,13,38,8346,
+16,22,30,8346,
+2,6,40,8346,
+8,26,30,8346,
+0,22,34,8346,
+0,14,38,8346,
+2,26,31,8346,
+1,22,34,8346,
+4,28,29,8346,
+20,20,29,8346,
+14,22,31,8346,
+14,17,34,8346,
+16,19,32,8346,
+4,20,35,8346,
+1,14,38,8346,
+17,26,26,8346,
+4,5,40,8346,
+4,16,37,8346,
+15,24,29,8346,
+21,24,25,8377,
+0,11,39,8377,
+11,15,36,8377,
+19,21,29,8377,
+7,15,37,8377,
+5,23,33,8377,
+1,11,39,8377,
+17,25,27,8377,
+2,14,38,8377,
+2,22,34,8377,
+22,22,26,8380,
+10,10,38,8380,
+3,6,40,8380,
+5,18,36,8380,
+4,27,30,8380,
+13,24,30,8380,
+18,19,31,8380,
+3,26,31,8380,
+5,10,39,8380,
+7,21,34,8380,
+2,11,39,8380,
+14,15,35,8380,
+21,23,26,8403,
+9,14,37,8403,
+11,25,30,8403,
+14,19,33,8403,
+9,11,38,8403,
+7,24,32,8403,
+17,24,28,8403,
+8,8,39,8403,
+0,25,32,8403,
+6,13,38,8403,
+18,22,29,8403,
+3,22,34,8403,
+0,7,40,8403,
+8,17,36,8403,
+15,20,32,8403,
+3,14,38,8403,
+10,18,35,8403,
+13,18,34,8403,
+9,28,28,8403,
+5,20,35,8403,
+1,25,32,8403,
+1,7,40,8403,
+17,20,31,8403,
+5,5,40,8403,
+5,16,37,8403,
+13,16,35,8403,
+8,25,31,8403,
+20,25,25,8425,
+8,19,35,8425,
+5,28,29,8425,
+7,9,39,8425,
+9,27,29,8425,
+3,11,39,8425,
+11,21,33,8425,
+20,24,26,8433,
+10,16,36,8433,
+12,22,32,8433,
+8,12,38,8433,
+4,6,40,8433,
+2,7,40,8433,
+4,26,31,8433,
+10,23,32,8433,
+2,25,32,8433,
+14,27,27,8433,
+21,22,27,8455,
+15,23,30,8455,
+5,27,30,8455,
+9,22,33,8455,
+6,23,33,8455,
+14,26,28,8455,
+10,20,34,8455,
+6,18,36,8455,
+4,14,38,8455,
+4,22,34,8455,
+6,10,39,8455,
+9,26,30,8455,
+12,12,37,8455,
+12,27,28,8455,
+0,19,36,8455,
+3,25,32,8455,
+16,21,31,8455,
+12,17,35,8455,
+4,11,39,8455,
+0,17,37,8455,
+13,20,33,8455,
+11,24,31,8455,
+20,23,27,8486,
+8,15,37,8486,
+3,7,40,8486,
+1,19,36,8486,
+11,13,37,8486,
+17,23,29,8486,
+1,17,37,8486,
+13,23,31,8486,
+12,26,29,8486,
+12,19,34,8486,
+19,20,30,8486,
+6,28,29,8486,
+6,16,37,8486,
+2,19,36,8486,
+13,14,36,8486,
+16,26,27,8486,
+8,21,34,8486,
+14,21,32,8486,
+5,6,40,8486,
+6,20,35,8486,
+19,25,26,8507,
+7,13,38,8507,
+2,17,37,8507,
+5,26,31,8507,
+14,25,29,8507,
+8,24,32,8507,
+0,8,40,8507,
+16,25,28,8507,
+4,7,40,8507,
+18,21,30,8507,
+10,14,37,8507,
+1,8,40,8507,
+5,22,34,8507,
+5,14,38,8507,
+0,12,39,8507,
+12,15,36,8507,
+6,27,30,8507,
+0,24,33,8507,
+4,25,32,8507,
+10,11,38,8507,
+1,12,39,8507,
+9,17,36,8507,
+19,24,27,8532,
+0,21,35,8532,
+8,9,39,8532,
+3,19,36,8532,
+1,24,33,8532,
+21,21,28,8532,
+3,17,37,8532,
+9,19,35,8532,
+9,25,31,8532,
+5,11,39,8532,
+17,17,33,8532,
+7,23,33,8532,
+1,21,35,8532,
+20,22,28,8536,
+10,28,28,8536,
+16,16,34,8536,
+2,8,40,8536,
+9,12,38,8536,
+2,12,39,8536,
+2,24,33,8536,
+16,18,33,8536,
+7,18,36,8536,
+0,15,38,8536,
+12,25,30,8536,
+15,22,31,8536,
+1,15,38,8536,
+10,27,29,8536,
+2,21,35,8536,
+11,18,35,8536,
+15,17,34,8536,
+7,10,39,8536,
+14,24,30,8536,
+18,18,32,8536,
+6,6,40,8536,
+16,24,29,8545,
+11,16,36,8545,
+6,26,31,8545,
+4,19,36,8545,
+17,22,30,8545,
+3,8,40,8545,
+2,15,38,8545,
+10,22,33,8545,
+5,25,32,8545,
+3,24,33,8545,
+5,7,40,8545,
+17,19,32,8545,
+7,16,37,8545,
+19,23,28,8580,
+7,28,29,8580,
+7,20,35,8580,
+4,17,37,8580,
+11,23,32,8580,
+3,12,39,8580,
+12,21,33,8580,
+9,15,37,8580,
+3,21,35,8580,
+15,15,35,8580,
+15,19,33,8580,
+10,26,30,8580,
+18,26,26,8582,
+14,18,34,8582,
+6,14,38,8582,
+6,22,34,8582,
+8,13,38,8582,
+11,20,34,8582,
+14,16,35,8582,
+13,22,32,8582,
+6,11,39,8582,
+3,15,38,8582,
+7,27,30,8582,
+9,21,34,8582,
+18,25,27,8602,
+16,20,32,8602,
+4,8,40,8602,
+4,24,33,8602,
+12,24,31,8602,
+9,24,32,8602,
+0,0,41,8602,
+0,9,40,8602,
+23,24,24,8652,
+4,12,39,8652,
+5,19,36,8652,
+20,21,29,8652,
+4,21,35,8652,
+13,27,28,8652,
+1,9,40,8652,
+0,29,29,8652,
+12,13,37,8652,
+8,23,33,8652,
+0,1,41,8652,
+13,17,35,8652,
+1,29,29,8652,
+15,27,27,8652,
+1,1,41,8652,
+9,9,39,8652,
+23,23,25,8667,
+19,19,31,8667,
+5,17,37,8667,
+18,24,28,8667,
+8,18,36,8667,
+0,28,30,8667,
+2,9,40,8667,
+1,28,30,8667,
+22,24,25,8672,
+15,26,28,8672,
+0,2,41,8672,
+14,20,33,8672,
+6,7,40,8672,
+4,15,38,8672,
+16,23,30,8672,
+6,25,32,8672,
+18,20,31,8672,
+0,23,34,8672,
+10,17,36,8672,
+8,10,39,8672,
+2,29,29,8672,
+1,2,41,8672,
+11,14,37,8672,
+11,11,38,8672,
+19,22,29,8672,
+1,23,34,8672,
+13,19,34,8672,
+10,25,31,8672,
+10,19,35,8672,
+7,26,31,8672,
+13,26,29,8672,
+14,23,31,8672,
+14,14,36,8672,
+10,12,38,8672,
+2,28,30,8672,
+8,16,37,8672,
+7,22,34,8672,
+8,20,35,8672,
+2,2,41,8672,
+7,14,38,8672,
+5,8,40,8672,
+11,28,28,8672,
+22,23,26,8689,
+2,23,34,8689,
+8,28,29,8689,
+15,21,32,8689,
+0,27,31,8689,
+13,15,36,8689,
+0,13,39,8689,
+5,24,33,8689,
+5,12,39,8689,
+0,3,41,8689,
+3,9,40,8689,
+1,13,39,8689,
+1,3,41,8689,
+1,27,31,8689,
+21,25,25,8706,
+3,29,29,8706,
+17,21,31,8706,
+15,25,29,8706,
+11,27,29,8706,
+5,21,35,8706,
+7,11,39,8706,
+21,24,26,8725,
+8,27,30,8725,
+6,19,36,8725,
+12,18,35,8725,
+0,18,37,8725,
+3,28,30,8725,
+9,13,38,8725,
+11,22,33,8725,
+2,27,31,8725,
+2,3,41,8725,
+3,23,34,8725,
+5,15,38,8725,
+13,25,30,8725,
+6,17,37,8725,
+10,15,37,8725,
+2,13,39,8725,
+18,23,29,8725,
+17,26,27,8725,
+1,18,37,8725,
+0,20,36,8725,
+12,16,36,8725,
+2,18,37,8725,
+0,4,41,8725,
+4,9,40,8725,
+11,26,30,8725,
+22,22,27,8741,
+10,21,34,8741,
+1,20,36,8741,
+12,23,32,8741,
+7,7,40,8741,
+1,4,41,8741,
+4,29,29,8741,
+7,25,32,8741,
+17,25,28,8741,
+3,27,31,8741,
+9,23,33,8741,
+3,13,39,8741,
+21,23,27,8759,
+13,21,33,8759,
+3,3,41,8759,
+2,20,36,8759,
+0,10,40,8759,
+12,20,34,8759,
+10,24,32,8759,
+20,20,30,8759,
+0,26,32,8759,
+0,16,38,8759,
+6,8,40,8759,
+4,28,30,8759,
+16,22,31,8759,
+15,24,30,8759,
+6,12,39,8759,
+16,17,34,8759,
+9,18,36,8759,
+2,4,41,8759,
+6,24,33,8759,
+8,26,31,8759,
+1,10,40,8759,
+1,16,38,8759,
+20,25,26,8772,
+1,26,32,8772,
+4,23,34,8772,
+6,21,35,8772,
+3,18,37,8772,
+9,10,39,8772,
+17,18,33,8772,
+19,21,30,8772,
+14,22,32,8772,
+8,14,38,8772,
+8,22,34,8772,
+2,26,32,8772,
+2,16,38,8772,
+2,10,40,8772,
+3,20,36,8772,
+15,18,34,8772,
+6,15,38,8772,
+20,24,27,8800,
+16,19,33,8800,
+9,28,29,8800,
+0,5,41,8800,
+7,19,36,8800,
+4,13,39,8800,
+5,9,40,8800,
+9,16,37,8800,
+8,11,39,8800,
+15,16,35,8800,
+11,17,36,8800,
+3,4,41,8800,
+9,20,35,8800,
+13,24,31,8800,
+4,27,31,8800,
+17,24,29,8800,
+13,13,37,8800,
+7,17,37,8800,
+11,19,35,8800,
+5,29,29,8800,
+11,25,31,8800,
+1,5,41,8800,
+18,22,30,8800,
+14,27,28,8800,
+0,22,35,8800,
+3,26,32,8800,
+4,18,37,8800,
+5,28,30,8800,
+21,22,28,8822,
+12,14,37,8822,
+18,19,32,8822,
+11,12,38,8822,
+3,16,38,8822,
+3,10,40,8822,
+9,27,30,8822,
+2,5,41,8822,
+5,23,34,8822,
+14,17,35,8822,
+1,22,35,8822,
+4,20,36,8822,
+12,28,28,8822,
+2,22,35,8822,
+19,26,26,8854,
+10,13,38,8854,
+14,26,29,8854,
+4,4,41,8854,
+14,19,34,8854,
+17,20,32,8854,
+8,25,32,8854,
+7,8,40,8854,
+20,23,28,8854,
+7,24,33,8854,
+16,27,27,8854,
+15,20,33,8854,
+0,25,33,8854,
+7,12,39,8854,
+12,27,29,8854,
+5,13,39,8854,
+11,15,37,8854,
+3,5,41,8854,
+7,21,35,8854,
+19,25,27,8866,
+5,27,31,8866,
+1,25,33,8866,
+15,23,31,8866,
+16,26,28,8866,
+4,16,38,8866,
+4,26,32,8866,
+4,10,40,8866,
+14,15,36,8866,
+12,22,33,8866,
+0,6,41,8866,
+6,9,40,8866,
+0,14,39,8866,
+7,15,38,8866,
+3,22,35,8866,
+6,29,29,8866,
+1,6,41,8866,
+17,23,30,8866,
+13,18,35,8866,
+10,23,33,8866,
+11,21,34,8866,
+2,25,33,8866,
+9,26,31,8866,
+5,18,37,8866,
+1,14,39,8866,
+10,18,36,8866,
+12,26,30,8866,
+6,28,30,8866,
+2,6,41,8866,
+0,11,40,8866,
+19,24,28,8886,
+6,23,34,8886,
+9,14,38,8886,
+10,10,39,8886,
+5,20,36,8886,
+16,21,32,8886,
+9,22,34,8886,
+14,25,30,8886,
+2,14,39,8886,
+8,19,36,8886,
+13,16,36,8886,
+11,24,32,8886,
+1,11,40,8886,
+8,17,37,8886,
+16,25,29,8886,
+13,23,32,8886,
+19,20,31,8886,
+4,5,41,8886,
+9,11,39,8886,
+21,21,29,8903,
+3,25,33,8903,
+2,11,40,8903,
+5,16,38,8903,
+13,20,34,8903,
+10,16,37,8903,
+20,22,29,8923,
+10,28,29,8923,
+5,10,40,8923,
+10,20,35,8923,
+4,22,35,8923,
+5,26,32,8923,
+6,13,39,8923,
+3,14,39,8923,
+14,21,33,8923,
+18,21,31,8923,
+6,27,31,8923,
+3,6,41,8923,
+24,24,24,8968,
+8,8,40,8968,
+6,18,37,8968,
+10,27,30,8968,
+8,12,39,8968,
+12,17,36,8968,
+18,26,27,8968,
+8,24,33,8968,
+3,11,40,8968,
+0,7,41,8968,
+7,9,40,8968,
+23,24,25,8987,
+12,19,35,8987,
+0,19,37,8987,
+12,25,31,8987,
+8,21,35,8987,
+4,25,33,8987,
+9,25,32,8987,
+5,5,41,8987,
+19,23,29,8987,
+1,19,37,8987,
+1,7,41,8987,
+7,29,29,8987,
+12,12,38,8987,
+6,20,36,8987,
+0,24,34,8987,
+16,24,30,8987,
+4,6,41,8987,
+8,15,38,8987,
+7,28,30,8987,
+4,14,39,8987,
+15,22,32,8987,
+0,17,38,8987,
+14,24,31,8987,
+1,24,34,8987,
+18,25,28,8987,
+2,7,41,8987,
+22,25,25,9007,
+17,22,31,9007,
+13,14,37,9007,
+17,17,34,9007,
+5,22,35,9007,
+1,17,38,9007,
+11,13,38,9007,
+2,19,37,9007,
+23,23,26,9007,
+7,23,34,9007,
+2,24,34,9007,
+6,10,40,9007,
+6,16,38,9007,
+16,18,34,9007,
+22,24,26,9019,
+6,26,32,9019,
+10,26,31,9019,
+13,28,28,9019,
+18,18,33,9019,
+0,21,36,9019,
+2,17,38,9019,
+4,11,40,9019,
+16,16,35,9019,
+12,15,37,9019,
+1,21,36,9019,
+9,19,36,9019,
+15,27,28,9019,
+17,19,33,9019,
+9,17,37,9019,
+7,13,39,9019,
+7,27,31,9019,
+3,19,37,9019,
+11,23,33,9019,
+3,7,41,9019,
+5,25,33,9019,
+13,27,29,9019,
+15,17,35,9019,
+10,14,38,9019,
+10,22,34,9019,
+11,18,36,9019,
+18,24,29,9025,
+2,21,36,9025,
+12,21,34,9025,
+20,21,30,9025,
+0,29,30,9025,
+3,24,34,9025,
+3,17,38,9025,
+1,29,30,9025,
+15,26,29,9025,
+7,18,37,9025,
+10,11,39,9025,
+13,22,33,9025,
+5,6,41,9025,
+22,23,27,9056,
+21,25,26,9056,
+5,14,39,9056,
+15,19,34,9056,
+0,12,40,9056,
+12,24,32,9056,
+0,8,41,9056,
+16,20,33,9056,
+13,26,30,9056,
+7,20,36,9056,
+19,22,30,9056,
+14,18,35,9056,
+1,12,40,9056,
+8,9,40,9056,
+0,28,31,9056,
+2,29,30,9056,
+6,22,35,9056,
+21,24,27,9086,
+15,15,36,9086,
+19,19,32,9086,
+1,28,31,9086,
+0,15,39,9086,
+3,21,36,9086,
+5,11,40,9086,
+16,23,31,9086,
+9,24,33,9086,
+4,19,37,9086,
+8,29,29,9086,
+11,16,37,9086,
+9,12,39,9086,
+4,7,41,9086,
+11,28,29,9086,
+1,8,41,9086,
+11,20,35,9086,
+17,27,27,9086,
+1,15,39,9086,
+9,21,35,9086,
+18,20,32,9086,
+4,24,34,9086,
+2,12,40,9086,
+8,28,30,9086,
+14,16,36,9086,
+4,17,38,9086,
+7,10,40,9086,
+2,28,31,9086,
+14,23,32,9086,
+10,25,32,9086,
+7,26,32,9086,
+17,26,28,9086,
+7,16,38,9086,
+2,8,41,9086,
+8,23,34,9086,
+3,29,30,9086,
+6,25,33,9086,
+11,27,30,9086,
+2,15,39,9086,
+9,15,38,9086,
+15,25,30,9086,
+20,26,26,9121,
+22,22,28,9121,
+14,20,34,9121,
+18,23,30,9121,
+6,14,39,9121,
+3,12,40,9121,
+0,27,32,9121,
+6,6,41,9121,
+4,21,36,9121,
+3,28,31,9121,
+17,21,32,9121,
+13,17,36,9121,
+8,13,39,9121,
+21,23,28,9144,
+3,8,41,9144,
+1,27,32,9144,
+0,23,35,9144,
+8,27,31,9144,
+20,25,27,9144,
+17,25,29,9144,
+15,21,33,9144,
+5,7,41,9144,
+5,19,37,9144,
+1,23,35,9144,
+3,15,39,9144,
+13,25,31,9144,
+13,19,35,9144,
+5,24,34,9144,
+8,18,37,9144,
+2,27,32,9144,
+4,29,30,9144,
+10,19,36,9144,
+12,13,38,9144,
+6,11,40,9144,
+2,23,35,9144,
+5,17,38,9144,
+7,22,35,9144,
+10,17,37,9144,
+11,26,31,9144,
+8,20,36,9144,
+4,12,40,9144,
+20,24,28,9177,
+14,14,37,9177,
+20,20,31,9177,
+4,8,41,9177,
+11,22,34,9177,
+11,14,38,9177,
+4,28,31,9177,
+0,9,41,9177,
+5,21,36,9177,
+12,23,33,9177,
+4,15,39,9177,
+9,9,40,9177,
+3,27,32,9177,
+15,24,31,9177,
+11,11,39,9177,
+13,15,37,9177,
+19,21,31,9177,
+3,23,35,9177,
+9,29,29,9177,
+1,9,41,9177,
+7,25,33,9177,
+16,22,32,9177,
+14,28,28,9177,
+0,0,42,9177,
+8,10,40,9177,
+12,18,36,9177,
+8,16,38,9177,
+8,26,32,9177,
+10,24,33,9177,
+10,12,39,9177,
+17,24,30,9190,
+9,28,30,9190,
+0,26,33,9190,
+0,1,42,9190,
+6,19,37,9190,
+6,7,41,9190,
+21,22,29,9218,
+5,29,30,9218,
+7,14,39,9218,
+19,26,27,9218,
+1,1,42,9218,
+1,26,33,9218,
+2,9,41,9218,
+14,27,29,9218,
+9,23,34,9218,
+13,21,34,9218,
+10,21,35,9218,
+0,18,38,9218,
+6,24,34,9218,
+0,2,42,9218,
+1,2,42,9218,
+0,20,37,9218,
+16,27,28,9218,
+2,26,33,9218,
+12,20,35,9218,
+6,17,38,9218,
+10,15,38,9218,
+18,22,31,9218,
+17,18,34,9218,
+4,27,32,9218,
+0,13,40,9218,
+13,24,32,9218,
+12,28,29,9218,
+14,22,33,9218,
+1,18,38,9218,
+5,12,40,9218,
+12,16,37,9218,
+1,13,40,9218,
+20,23,29,9250,
+7,11,40,9250,
+11,25,32,9250,
+4,23,35,9250,
+19,25,28,9250,
+5,28,31,9250,
+5,8,41,9250,
+16,17,35,9250,
+1,20,37,9250,
+3,9,41,9250,
+9,27,31,9250,
+5,15,39,9250,
+9,13,39,9250,
+2,2,42,9250,
+14,26,30,9250,
+2,18,38,9250,
+8,22,35,9250,
+0,3,42,9250,
+16,19,34,9250,
+2,20,37,9250,
+6,21,36,9250,
+2,13,40,9250,
+16,26,29,9250,
+12,27,30,9250,
+15,18,35,9250,
+3,26,33,9250,
+9,18,37,9250,
+18,19,33,9250,
+1,3,42,9250,
+6,29,30,9250,
+2,3,42,9250,
+9,20,36,9250,
+3,18,38,9250,
+15,16,36,9250,
+0,16,39,9250,
+24,24,25,9309,
+1,16,39,9309,
+17,20,33,9309,
+3,13,40,9309,
+4,9,41,9309,
+8,25,33,9309,
+19,24,29,9309,
+5,27,32,9309,
+15,23,32,9309,
+11,19,36,9309,
+3,20,37,9309,
+7,7,41,9309,
+17,23,31,9309,
+11,17,37,9309,
+7,19,37,9309,
+23,25,25,9320,
+5,23,35,9320,
+6,12,40,9320,
+0,22,36,9320,
+0,4,42,9320,
+9,26,32,9320,
+0,25,34,9320,
+8,14,39,9320,
+4,26,33,9320,
+6,8,41,9320,
+9,16,38,9320,
+2,16,39,9320,
+14,17,36,9320,
+1,22,36,9320,
+9,10,40,9320,
+6,28,31,9320,
+23,24,26,9337,
+16,25,30,9337,
+15,20,34,9337,
+7,24,34,9337,
+0,10,41,9337,
+12,26,31,9337,
+1,4,42,9337,
+1,10,41,9337,
+3,3,42,9337,
+14,19,35,9337,
+14,25,31,9337,
+7,17,38,9337,
+1,25,34,9337,
+21,21,30,9337,
+13,13,38,9337,
+18,27,27,9337,
+6,15,39,9337,
+10,29,29,9337,
+12,22,34,9337,
+2,22,36,9337,
+2,4,42,9337,
+12,14,38,9337,
+18,26,28,9337,
+10,28,30,9337,
+20,22,30,9337,
+4,18,38,9337,
+4,13,40,9337,
+19,20,32,9337,
+10,23,34,9337,
+22,25,26,9358,
+8,11,40,9358,
+4,20,37,9358,
+2,25,34,9358,
+2,10,41,9358,
+16,21,33,9358,
+3,16,39,9358,
+11,12,39,9358,
+11,24,33,9358,
+7,21,36,9358,
+13,23,33,9358,
+5,9,41,9358,
+23,23,27,9378,
+11,21,35,9378,
+18,21,32,9378,
+22,24,27,9391,
+0,5,42,9391,
+3,22,36,9391,
+3,4,42,9391,
+6,27,32,9391,
+13,18,36,9391,
+3,10,41,9391,
+10,13,39,9391,
+9,22,35,9391,
+7,29,30,9391,
+14,15,37,9391,
+3,25,34,9391,
+5,26,33,9391,
+11,15,38,9391,
+1,5,42,9391,
+19,23,30,9391,
+10,27,31,9391,
+6,23,35,9391,
+18,25,29,9391,
+14,21,34,9391,
+10,18,37,9391,
+16,24,31,9391,
+4,16,39,9391,
+7,12,40,9391,
+2,5,42,9391,
+5,18,38,9391,
+21,26,26,9412,
+15,28,28,9412,
+12,25,32,9412,
+5,20,37,9412,
+13,28,29,9412,
+7,28,31,9412,
+8,19,37,9412,
+13,16,37,9412,
+7,8,41,9412,
+5,13,40,9412,
+13,20,35,9412,
+9,25,33,9412,
+7,15,39,9412,
+15,27,29,9412,
+21,25,27,9429,
+8,24,34,9429,
+0,14,40,9429,
+4,22,36,9429,
+4,4,42,9429,
+10,20,36,9429,
+14,24,32,9429,
+17,22,32,9429,
+22,23,28,9439,
+1,14,40,9439,
+4,25,34,9439,
+8,17,38,9439,
+4,10,41,9439,
+9,14,39,9439,
+13,27,30,9439,
+15,22,33,9439,
+6,9,41,9439,
+3,5,42,9439,
+10,16,38,9439,
+2,14,40,9439,
+0,30,30,9439,
+10,10,40,9439,
+0,6,42,9439,
+10,26,32,9439,
+18,24,30,9439,
+21,24,28,9462,
+1,6,42,9462,
+1,30,30,9462,
+15,26,30,9462,
+12,19,36,9462,
+0,24,35,9462,
+8,21,36,9462,
+6,26,33,9462,
+17,27,28,9462,
+0,29,31,9462,
+0,11,41,9462,
+20,21,31,9462,
+1,24,35,9462,
+5,16,39,9462,
+7,27,32,9462,
+9,11,40,9462,
+12,17,37,9462,
+1,11,41,9462,
+11,29,29,9462,
+1,29,31,9462,
+7,23,35,9462,
+17,17,35,9462,
+18,18,34,9462,
+2,6,42,9462,
+2,30,30,9462,
+6,18,38,9462,
+8,29,30,9462,
+6,13,40,9462,
+11,28,30,9462,
+6,20,37,9462,
+16,18,35,9462,
+0,19,38,9462,
+2,24,35,9462,
+4,5,42,9462,
+20,26,27,9491,
+5,22,36,9491,
+3,14,40,9491,
+17,26,29,9491,
+2,29,31,9491,
+1,19,38,9491,
+5,10,41,9491,
+13,26,31,9491,
+11,23,34,9491,
+19,22,31,9491,
+17,19,34,9491,
+5,25,34,9491,
+2,11,41,9491,
+16,16,36,9491,
+0,28,32,9491,
+8,12,40,9491,
+3,30,30,9491,
+16,23,32,9491,
+8,8,41,9491,
+13,14,38,9491,
+10,22,35,9491,
+3,6,42,9491,
+2,19,38,9491,
+12,12,39,9491,
+22,22,29,9505,
+8,28,31,9505,
+1,28,32,9505,
+13,22,34,9505,
+12,24,33,9505,
+20,25,28,9505,
+0,21,37,9505,
+15,17,36,9505,
+3,24,35,9505,
+8,15,39,9505,
+0,17,39,9505,
+12,21,35,9505,
+21,23,29,9524,
+11,27,31,9524,
+19,19,33,9524,
+7,9,41,9524,
+11,13,39,9524,
+3,11,41,9524,
+15,25,31,9524,
+1,21,37,9524,
+9,19,37,9524,
+1,17,39,9524,
+15,19,35,9524,
+3,29,31,9524,
+4,14,40,9524,
+2,28,32,9524,
+16,20,34,9524,
+9,24,34,9524,
+6,16,39,9524,
+12,15,38,9524,
+0,7,42,9524,
+18,20,33,9524,
+18,23,31,9524,
+9,17,38,9524,
+7,26,33,9524,
+3,19,38,9524,
+10,25,33,9524,
+1,7,42,9524,
+2,21,37,9524,
+2,17,39,9524,
+5,5,42,9524,
+17,25,30,9524,
+14,23,33,9524,
+11,18,37,9524,
+6,22,36,9524,
+4,30,30,9524,
+14,18,36,9524,
+4,6,42,9524,
+6,10,41,9524,
+10,14,39,9524,
+6,25,34,9524,
+8,27,32,9524,
+3,28,32,9524,
+20,24,29,9562,
+4,24,35,9562,
+2,7,42,9562,
+7,18,38,9562,
+11,20,36,9562,
+4,11,41,9562,
+7,20,37,9562,
+8,23,35,9562,
+13,25,32,9562,
+0,27,33,9562,
+4,29,31,9562,
+7,13,40,9562,
+9,21,36,9562,
+15,15,37,9562,
+19,27,27,9575,
+17,21,33,9575,
+3,21,37,9575,
+1,27,33,9575,
+3,17,39,9575,
+14,20,35,9575,
+14,16,37,9575,
+10,11,40,9575,
+14,28,29,9575,
+5,14,40,9575,
+11,26,32,9575,
+4,19,38,9575,
+11,16,38,9575,
+19,26,28,9589,
+15,21,34,9589,
+3,7,42,9589,
+9,29,30,9589,
+2,27,33,9589,
+16,28,28,9589,
+4,28,32,9589,
+20,20,32,9589,
+15,24,32,9589,
+5,6,42,9589,
+0,23,36,9589,
+14,27,30,9589,
+5,30,30,9589,
+9,12,40,9589,
+0,12,41,9589,
+21,22,30,9620,
+0,15,40,9620,
+19,21,32,9620,
+7,16,39,9620,
+17,24,31,9620,
+24,25,25,9660,
+12,29,29,9660,
+4,21,37,9660,
+16,27,29,9660,
+9,28,31,9660,
+1,23,36,9660,
+1,15,40,9660,
+1,12,41,9660,
+4,17,39,9660,
+5,24,35,9660,
+13,19,36,9660,
+8,9,41,9660,
+5,29,31,9660,
+9,15,39,9660,
+13,17,37,9660,
+3,27,33,9660,
+19,25,29,9660,
+5,11,41,9660,
+0,8,42,9660,
+24,24,26,9666,
+12,28,30,9666,
+7,22,36,9666,
+2,12,41,9666,
+2,23,36,9666,
+1,8,42,9666,
+2,15,40,9666,
+8,26,33,9666,
+4,7,42,9666,
+20,23,30,9666,
+16,22,33,9666,
+12,23,34,9666,
+10,19,37,9666,
+11,22,35,9666,
+23,25,26,9682,
+7,25,34,9682,
+7,10,41,9682,
+5,19,38,9682,
+2,8,42,9682,
+6,14,40,9682,
+18,22,32,9682,
+0,26,34,9682,
+10,24,34,9682,
+8,18,38,9682,
+16,26,30,9682,
+8,20,37,9682,
+10,17,38,9682,
+1,26,34,9682,
+14,26,31,9682,
+5,28,32,9682,
+8,13,40,9682,
+12,27,31,9682,
+3,12,41,9682,
+9,27,32,9682,
+3,15,40,9682,
+12,13,39,9682,
+23,24,27,9716,
+4,27,33,9716,
+13,24,33,9716,
+3,23,36,9716,
+9,23,35,9716,
+13,21,35,9716,
+5,21,37,9716,
+5,17,39,9716,
+11,25,33,9716,
+6,6,42,9716,
+6,30,30,9716,
+14,22,34,9716,
+22,26,26,9720,
+14,14,38,9720,
+2,26,34,9720,
+6,24,35,9720,
+18,27,28,9720,
+12,18,37,9720,
+3,8,42,9720,
+10,21,36,9720,
+19,24,30,9720,
+6,29,31,9720,
+6,11,41,9720,
+17,18,35,9720,
+13,15,38,9720,
+5,7,42,9720,
+11,14,39,9720,
+22,25,27,9736,
+12,20,36,9736,
+8,16,39,9736,
+10,29,30,9736,
+6,19,38,9736,
+3,26,34,9736,
+4,23,36,9736,
+18,19,34,9736,
+4,12,41,9736,
+4,15,40,9736,
+18,26,29,9736,
+16,17,36,9736,
+16,19,35,9736,
+17,23,32,9736,
+23,23,28,9768,
+11,11,40,9768,
+16,25,31,9768,
+15,23,33,9768,
+5,27,33,9768,
+21,21,31,9768,
+9,9,41,9768,
+6,28,32,9768,
+8,22,36,9768,
+22,24,28,9771,
+12,26,32,9771,
+4,8,42,9771,
+12,16,38,9771,
+10,12,40,9771,
+0,20,38,9771,
+0,18,39,9771,
+8,25,34,9771,
+20,22,31,9771,
+0,9,42,9771,
+15,18,36,9771,
+14,25,32,9771,
+1,20,38,9771,
+8,10,41,9771,
+17,20,34,9771,
+7,14,40,9771,
+10,28,31,9771,
+1,18,39,9771,
+9,26,33,9771,
+6,21,37,9771,
+1,9,42,9771,
+6,17,39,9771,
+10,15,39,9771,
+21,26,27,9790,
+4,26,34,9790,
+2,20,38,9790,
+2,18,39,9790,
+6,7,42,9790,
+2,9,42,9790,
+7,30,30,9790,
+18,25,30,9790,
+0,0,43,9790,
+9,18,38,9790,
+5,15,40,9790,
+0,1,43,9790,
+0,13,41,9790,
+9,20,37,9790,
+0,25,35,9790,
+15,28,29,9790,
+7,24,35,9790,
+15,16,37,9790,
+21,25,28,9812,
+5,23,36,9812,
+5,12,41,9812,
+9,13,40,9812,
+19,20,33,9812,
+15,20,35,9812,
+19,23,31,9812,
+1,25,35,9812,
+7,11,41,9812,
+1,13,41,9812,
+1,1,43,9812,
+11,19,37,9812,
+13,29,29,9812,
+7,29,31,9812,
+3,20,38,9812,
+0,2,43,9812,
+11,24,34,9812,
+0,22,37,9812,
+10,27,32,9812,
+12,22,35,9812,
+14,19,36,9812,
+16,21,34,9812,
+13,28,30,9812,
+5,8,42,9812,
+2,13,41,9812,
+3,9,42,9812,
+15,27,30,9812,
+6,27,33,9812,
+11,17,38,9812,
+18,21,33,9812,
+1,2,43,9812,
+2,25,35,9812,
+13,23,34,9812,
+1,22,37,9812,
+22,23,29,9836,
+3,18,39,9836,
+7,19,38,9836,
+10,23,35,9836,
+14,17,37,9836,
+16,24,32,9836,
+0,16,40,9836,
+5,26,34,9836,
+2,2,43,9836,
+7,28,32,9836,
+17,28,28,9836,
+2,22,37,9836,
+1,16,40,9836,
+21,24,29,9863,
+0,3,43,9863,
+20,27,27,9863,
+12,25,33,9863,
+11,21,36,9863,
+9,16,39,9863,
+7,17,39,9863,
+7,21,37,9863,
+17,27,29,9863,
+13,13,39,9863,
+3,13,41,9863,
+1,3,43,9863,
+3,25,35,9863,
+13,27,31,9863,
+20,26,28,9869,
+4,20,38,9869,
+2,16,40,9869,
+8,14,40,9869,
+9,22,36,9869,
+4,9,42,9869,
+6,15,40,9869,
+4,18,39,9869,
+12,14,39,9869,
+0,30,31,9869,
+18,24,31,9869,
+6,23,36,9869,
+6,12,41,9869,
+14,24,33,9869,
+17,22,33,9869,
+7,7,42,9869,
+15,26,31,9869,
+9,10,41,9869,
+1,30,31,9869,
+11,29,30,9869,
+14,21,35,9869,
+3,22,37,9869,
+2,3,43,9869,
+9,25,34,9869,
+13,18,37,9869,
+0,10,42,9869,
+6,8,42,9869,
+8,30,30,9869,
+11,12,40,9869,
+0,4,43,9869,
+10,26,33,9869,
+13,20,36,9869,
+3,16,40,9869,
+20,21,32,9886,
+8,24,35,9886,
+14,15,38,9886,
+1,10,42,9886,
+0,29,32,9886,
+15,22,34,9886,
+2,30,31,9886,
+17,26,30,9886,
+1,29,32,9886,
+1,4,43,9886,
+4,13,41,9886,
+4,25,35,9886,
+8,29,31,9886,
+11,28,31,9886,
+8,11,41,9886,
+20,25,29,9919,
+7,27,33,9919,
+11,15,39,9919,
+3,3,43,9919,
+2,10,42,9919,
+22,22,30,9921,
+10,18,38,9921,
+6,26,34,9921,
+5,20,38,9921,
+10,20,37,9921,
+2,4,43,9921,
+4,22,37,9921,
+19,22,32,9921,
+8,19,38,9921,
+13,16,38,9921,
+2,29,32,9921,
+13,26,32,9921,
+10,13,40,9921,
+5,9,42,9921,
+3,30,31,9921,
+5,18,39,9921,
+21,23,30,9942,
+4,16,40,9942,
+8,28,32,9942,
+0,24,36,9942,
+0,28,33,9942,
+3,10,42,9942,
+1,24,36,9942,
+18,18,35,9942,
+11,27,32,9942,
+8,17,39,9942,
+3,29,32,9942,
+12,19,37,9942,
+17,17,36,9942,
+7,12,41,9942,
+7,23,36,9942,
+15,25,32,9942,
+1,28,33,9942,
+8,21,37,9942,
+7,15,40,9942,
+16,23,33,9942,
+3,4,43,9942,
+19,27,28,9970,
+0,5,43,9970,
+11,23,35,9970,
+25,25,25,10002,
+17,19,35,10002,
+5,25,35,10002,
+17,25,31,10002,
+1,5,43,10002,
+5,13,41,10002,
+20,24,30,10002,
+12,24,34,10002,
+16,18,36,10002,
+2,24,36,10002,
+0,14,41,10002,
+12,17,38,10002,
+9,14,40,10002,
+18,23,32,10002,
+4,30,31,10002,
+2,28,33,10002,
+24,25,26,10019,
+7,8,42,10019,
+10,16,39,10019,
+19,19,34,10019,
+2,5,43,10019,
+19,26,29,10019,
+13,22,35,10019,
+5,22,37,10019,
+1,14,41,10019,
+14,29,29,10019,
+10,22,36,10019,
+18,20,34,10019,
+6,20,38,10019,
+4,10,42,10019,
+14,28,30,10019,
+12,21,36,10019,
+3,24,36,10019,
+6,9,42,10019,
+4,4,43,10019,
+23,26,26,10036,
+16,20,35,10036,
+10,25,34,10036,
+24,24,27,10036,
+5,16,40,10036,
+7,26,34,10036,
+2,14,41,10036,
+16,28,29,10036,
+6,18,39,10036,
+14,23,34,10036,
+4,29,32,10036,
+9,30,30,10036,
+16,16,37,10036,
+10,10,41,10036,
+0,19,39,10036,
+3,28,33,10036,
+8,27,33,10036,
+9,24,35,10036,
+15,19,36,10036,
+1,19,39,10036,
+9,11,41,10036,
+9,29,31,10036,
+13,25,33,10036,
+23,25,27,10053,
+15,17,37,10053,
+3,5,43,10053,
+0,11,42,10053,
+0,27,34,10053,
+0,21,38,10053,
+0,6,43,10053,
+16,27,30,10053,
+12,29,30,10053,
+17,21,34,10053,
+5,30,31,10053,
+11,26,33,10053,
+6,25,35,10053,
+13,14,39,10053,
+2,19,39,10053,
+3,14,41,10053,
+19,25,30,10053,
+6,13,41,10053,
+9,19,38,10053,
+1,27,34,10053,
+1,21,38,10053,
+21,22,31,10053,
+1,6,43,10053,
+1,11,42,10053,
+14,27,31,10053,
+12,12,40,10053,
+4,24,36,10053,
+22,26,27,10098,
+4,28,33,10098,
+9,28,32,10098,
+5,10,42,10098,
+8,23,36,10098,
+23,24,28,10098,
+11,18,38,10098,
+2,11,42,10098,
+2,27,34,10098,
+6,22,37,10098,
+12,28,31,10098,
+20,20,33,10098,
+0,17,40,10098,
+8,15,40,10098,
+17,24,32,10098,
+2,21,38,10098,
+8,12,41,10098,
+14,18,37,10098,
+2,6,43,10098,
+12,15,39,10098,
+20,23,31,10098,
+1,17,40,10098,
+15,24,33,10098,
+5,29,32,10098,
+4,5,43,10098,
+11,13,40,10098,
+11,20,37,10098,
+9,21,37,10098,
+9,17,39,10098,
+19,21,33,10098,
+15,21,35,10098,
+3,19,39,10098,
+18,28,28,10098,
+8,8,42,10098,
+6,16,40,10098,
+14,20,36,10098,
+16,26,31,10098,
+4,14,41,10098,
+22,25,28,10117,
+2,17,40,10117,
+7,20,38,10117,
+18,27,29,10117,
+3,27,34,10117,
+3,6,43,10117,
+7,9,42,10117,
+3,21,38,10117,
+3,11,42,10117,
+15,15,38,10117,
+7,18,39,10117,
+8,26,34,10117,
+14,26,32,10117,
+16,22,34,10117,
+10,14,40,10117,
+14,16,38,10117,
+12,27,32,10117,
+5,24,36,10117,
+18,22,33,10117,
+6,30,31,10117,
+0,23,37,10117,
+19,24,31,10125,
+0,7,43,10125,
+3,17,40,10125,
+5,28,33,10125,
+12,23,35,10125,
+11,16,39,10125,
+4,19,39,10125,
+7,25,35,10125,
+1,23,37,10125,
+23,23,29,10160,
+1,7,43,10160,
+7,13,41,10160,
+5,5,43,10160,
+13,19,37,10160,
+21,27,27,10160,
+9,27,33,10160,
+18,26,30,10160,
+6,10,42,10160,
+10,30,30,10160,
+0,26,35,10160,
+13,24,34,10160,
+21,26,28,10173,
+11,22,36,10173,
+22,24,29,10173,
+4,6,43,10173,
+4,21,38,10173,
+6,29,32,10173,
+4,11,42,10173,
+4,27,34,10173,
+10,24,35,10173,
+13,17,38,10173,
+11,25,34,10173,
+7,22,37,10173,
+2,23,37,10173,
+10,29,31,10173,
+1,26,35,10173,
+5,14,41,10173,
+2,7,43,10173,
+10,11,41,10173,
+16,25,32,10173,
+4,17,40,10173,
+14,22,35,10173,
+10,19,38,10173,
+2,26,35,10173,
+7,16,40,10173,
+13,21,36,10173,
+9,15,40,10173,
+9,12,41,10173,
+0,15,41,10173,
+21,21,32,10187,
+9,23,36,10187,
+3,7,43,10187,
+1,15,41,10187,
+15,29,29,10187,
+17,23,33,10187,
+21,25,29,10220,
+3,23,37,10220,
+5,19,39,10220,
+0,12,42,10220,
+20,22,32,10220,
+8,20,38,10220,
+6,24,36,10220,
+10,28,32,10220,
+12,26,33,10220,
+17,18,36,10220,
+8,9,42,10220,
+15,28,30,10220,
+1,12,42,10220,
+8,18,39,10220,
+6,28,33,10220,
+5,21,38,10220,
+5,6,43,10220,
+5,11,42,10220,
+15,23,34,10220,
+18,25,31,10220,
+14,25,33,10220,
+10,21,37,10220,
+2,15,41,10220,
+5,27,34,10220,
+13,29,30,10220,
+7,30,31,10220,
+18,19,35,10220,
+10,17,39,10220,
+3,26,35,10220,
+12,18,38,10220,
+2,12,42,10220,
+12,13,40,10220,
+20,27,28,10259,
+6,14,41,10259,
+12,20,37,10259,
+0,8,43,10259,
+16,19,36,10259,
+14,14,39,10259,
+7,10,42,10259,
+9,26,34,10259,
+22,23,30,10259,
+8,25,35,10259,
+4,7,43,10259,
+13,28,31,10259,
+19,23,32,10259,
+4,23,37,10259,
+17,20,35,10259,
+5,17,40,10259,
+8,13,41,10259,
+17,28,29,10259,
+1,8,43,10259,
+7,29,32,10259,
+16,17,37,10259,
+15,27,31,10259,
+3,15,41,10259,
+13,15,39,10259,
+2,8,43,10259,
+3,12,42,10259,
+11,14,40,10259,
+4,26,35,10259,
+19,20,34,10259,
+20,26,29,10290,
+21,24,30,10290,
+8,22,37,10290,
+15,18,37,10290,
+6,19,39,10290,
+17,27,30,10290,
+10,27,33,10290,
+8,16,40,10290,
+6,21,38,10290,
+0,25,36,10290,
+6,11,42,10290,
+15,20,36,10290,
+6,27,34,10290,
+18,21,34,10290,
+0,20,39,10290,
+12,16,39,10290,
+6,6,43,10290,
+16,24,33,10290,
+7,24,36,10290,
+11,30,30,10290,
+0,31,31,10290,
+4,15,41,10290,
+1,20,39,10290,
+3,8,43,10290,
+13,27,32,10290,
+16,21,35,10290,
+7,28,33,10290,
+11,24,35,10290,
+1,25,36,10290,
+13,23,35,10290,
+11,29,31,10290,
+5,7,43,10290,
+1,31,31,10290,
+5,23,37,10290,
+11,11,41,10290,
+0,30,32,10290,
+12,22,36,10290,
+4,12,42,10290,
+0,18,40,10290,
+18,24,32,10301,
+15,26,32,10301,
+12,25,34,10301,
+8,30,31,10301,
+10,15,40,10301,
+2,25,36,10301,
+1,30,32,10301,
+2,20,39,10301,
+15,16,38,10301,
+10,12,41,10301,
+1,18,40,10301,
+10,23,36,10301,
+9,20,38,10301,
+20,25,30,10328,
+6,17,40,10328,
+25,25,26,10355,
+7,14,41,10355,
+11,19,38,10355,
+9,9,42,10355,
+9,18,39,10355,
+14,19,37,10355,
+17,26,31,10355,
+2,31,31,10355,
+5,26,35,10355,
+2,18,40,10355,
+14,24,34,10355,
+2,30,32,10355,
+0,22,38,10355,
+24,26,26,10369,
+8,10,42,10369,
+14,17,38,10369,
+19,28,28,10369,
+8,29,32,10369,
+1,22,38,10369,
+4,8,43,10369,
+22,22,31,10369,
+17,22,34,10369,
+11,28,32,10369,
+3,20,39,10369,
+0,29,33,10369,
+20,21,33,10369,
+24,25,27,10398,
+3,25,36,10398,
+0,9,43,10398,
+21,23,31,10398,
+11,17,39,10398,
+19,27,29,10398,
+5,15,41,10398,
+11,21,37,10398,
+1,9,43,10398,
+7,19,39,10398,
+1,29,33,10398,
+3,31,31,10398,
+9,25,35,10398,
+9,13,41,10398,
+2,22,38,10398,
+10,26,34,10398,
+3,30,32,10398,
+3,18,40,10398,
+14,21,36,10398,
+0,13,42,10398,
+5,12,42,10398,
+7,11,42,10398,
+23,26,27,10428,
+7,21,38,10428,
+19,22,33,10428,
+15,22,35,10428,
+1,13,42,10428,
+9,22,37,10428,
+6,7,43,10428,
+2,9,43,10428,
+2,29,33,10428,
+7,27,34,10428,
+13,26,33,10428,
+6,23,37,10428,
+24,24,28,10437,
+8,24,36,10437,
+0,0,44,10437,
+20,24,31,10437,
+4,25,36,10437,
+9,16,40,10437,
+4,20,39,10437,
+14,29,30,10437,
+3,22,38,10437,
+6,26,35,10437,
+8,28,33,10437,
+0,16,41,10437,
+0,1,44,10437,
+13,18,38,10437,
+2,13,42,10437,
+19,26,30,10437,
+13,13,40,10437,
+1,1,44,10437,
+13,20,37,10437,
+17,25,32,10437,
+5,8,43,10437,
+1,16,41,10437,
+4,31,31,10437,
+7,17,40,10437,
+23,25,28,10455,
+16,29,29,10455,
+15,25,33,10455,
+3,9,43,10455,
+11,27,33,10455,
+3,29,33,10455,
+4,30,32,10455,
+16,28,30,10455,
+0,2,44,10455,
+4,18,40,10455,
+0,28,34,10455,
+12,14,40,10455,
+14,28,31,10455,
+1,2,44,10455,
+8,14,41,10455,
+1,28,34,10455,
+2,16,41,10455,
+16,23,34,10455,
+6,15,41,10455,
+9,30,31,10455,
+14,15,39,10455,
+3,13,42,10455,
+22,27,27,10472,
+18,23,33,10472,
+12,30,30,10472,
+2,28,34,10472,
+4,22,38,10472,
+18,18,36,10472,
+2,2,44,10472,
+22,26,28,10488,
+10,20,38,10488,
+6,12,42,10488,
+9,10,42,10488,
+0,3,44,10488,
+0,24,37,10488,
+12,24,35,10488,
+10,18,39,10488,
+3,16,41,10488,
+5,20,39,10488,
+8,19,39,10488,
+1,24,37,10488,
+9,29,32,10488,
+17,19,36,10488,
+1,3,44,10488,
+16,27,31,10488,
+13,16,39,10488,
+23,24,29,10512,
+12,29,31,10512,
+4,29,33,10512,
+4,9,43,10512,
+11,12,41,10512,
+11,15,40,10512,
+5,25,36,10512,
+11,23,36,10512,
+7,23,37,10512,
+17,17,37,10512,
+7,7,43,10512,
+19,25,31,10512,
+5,31,31,10512,
+19,19,35,10512,
+14,27,32,10512,
+2,24,37,10512,
+8,11,42,10512,
+5,18,40,10512,
+18,20,35,10512,
+4,13,42,10512,
+8,21,38,10512,
+0,10,43,10512,
+3,28,34,10512,
+21,22,32,10512,
+12,19,38,10512,
+8,27,34,10512,
+2,3,44,10512,
+6,8,43,10512,
+13,22,36,10512,
+18,28,29,10512,
+5,30,32,10512,
+16,18,37,10512,
+13,25,34,10512,
+1,10,43,10512,
+7,26,35,10512,
+10,25,35,10512,
+22,25,29,10537,
+14,23,35,10537,
+10,13,41,10537,
+12,28,32,10537,
+16,20,36,10537,
+0,4,44,10537,
+11,26,34,10537,
+1,4,44,10537,
+2,10,43,10537,
+8,17,40,10537,
+5,22,38,10537,
+9,24,36,10537,
+4,16,41,10537,
+10,22,37,10537,
+18,27,30,10537,
+20,23,32,10537,
+9,28,33,10537,
+12,21,37,10537,
+3,3,44,10537,
+0,27,35,10537,
+12,17,39,10537,
+17,24,33,10537,
+3,24,37,10537,
+21,27,28,10558,
+5,29,33,10558,
+5,9,43,10558,
+1,27,35,10558,
+15,19,37,10558,
+17,21,35,10558,
+7,15,41,10558,
+16,26,32,10558,
+20,20,34,10558,
+2,4,44,10558,
+4,28,34,10558,
+10,16,40,10558,
+16,16,38,10558,
+6,25,36,10558,
+6,20,39,10558,
+7,12,42,10558,
+15,24,34,10558,
+21,26,29,10587,
+23,23,30,10587,
+9,14,41,10587,
+3,10,43,10587,
+6,31,31,10587,
+19,21,34,10587,
+5,13,42,10587,
+15,17,38,10587,
+2,27,35,10587,
+6,18,40,10587,
+0,14,42,10587,
+22,24,30,10601,
+6,30,32,10601,
+0,5,44,10601,
+4,24,37,10601,
+14,26,33,10601,
+1,14,42,10601,
+3,4,44,10601,
+0,19,40,10601,
+18,26,31,10601,
+10,30,31,10601,
+19,24,32,10601,
+8,23,37,10601,
+1,5,44,10601,
+15,21,36,10601,
+7,8,43,10601,
+1,19,40,10601,
+12,27,33,10601,
+0,21,39,10601,
+5,16,41,10601,
+3,27,35,10601,
+1,21,39,10601,
+9,19,39,10601,
+10,10,42,10601,
+6,22,38,10601,
+2,14,42,10601,
+14,18,38,10601,
+18,22,34,10601,
+8,26,35,10601,
+13,14,40,10601,
+14,20,37,10601,
+2,19,40,10601,
+11,20,38,10601,
+2,5,44,10601,
+5,28,34,10601,
+10,29,32,10601,
+16,22,35,10601,
+4,10,43,10601,
+2,21,39,10601,
+6,9,43,10601,
+6,29,33,10601,
+9,11,42,10601,
+9,21,38,10601,
+21,25,30,10633,
+15,29,30,10633,
+9,27,34,10633,
+11,18,39,10633,
+20,28,28,10640,
+4,4,44,10640,
+12,12,41,10640,
+3,14,42,10640,
+12,15,40,10640,
+13,30,30,10640,
+12,23,36,10640,
+6,13,42,10640,
+7,20,39,10640,
+3,5,44,10640,
+20,27,29,10668,
+5,24,37,10668,
+3,19,40,10668,
+8,15,41,10668,
+0,17,41,10668,
+0,11,43,10668,
+15,28,31,10668,
+4,27,35,10668,
+7,25,36,10668,
+16,25,33,10668,
+9,17,40,10668,
+13,24,35,10668,
+17,29,29,10668,
+7,31,31,10668,
+13,29,31,10668,
+15,15,39,10668,
+11,13,41,10668,
+1,17,41,10668,
+1,11,43,10668,
+21,21,33,10668,
+11,25,35,10668,
+3,21,39,10668,
+0,6,44,10668,
+10,24,36,10668,
+8,12,42,10668,
+0,26,36,10668,
+6,16,41,10668,
+7,30,32,10668,
+10,28,33,10668,
+18,25,32,10668,
+7,18,40,10668,
+1,6,44,10668,
+0,23,38,10668,
+1,26,36,10668,
+14,16,39,10668,
+17,28,30,10668,
+20,22,33,10668,
+22,23,31,10682,
+2,11,43,10682,
+2,17,41,10682,
+11,22,37,10682,
+1,23,38,10682,
+13,19,38,10682,
+5,10,43,10682,
+17,23,34,10682,
+12,26,34,10682,
+2,6,44,10682,
+2,26,36,10682,
+14,22,36,10682,
+4,14,42,10682,
+6,28,34,10682,
+20,26,30,10695,
+13,28,32,10695,
+14,25,34,10695,
+10,14,41,10695,
+11,16,40,10695,
+2,23,38,10695,
+7,22,38,10695,
+25,26,26,10733,
+8,8,43,10733,
+4,5,44,10733,
+4,19,40,10733,
+4,21,39,10733,
+15,27,32,10733,
+21,24,31,10733,
+3,17,41,10733,
+15,23,35,10733,
+7,9,43,10733,
+13,21,37,10733,
+3,11,43,10733,
+9,23,37,10733,
+17,27,31,10733,
+7,29,33,10733,
+13,17,39,10733,
+25,25,27,10748,
+19,23,33,10748,
+5,27,35,10748,
+24,26,27,10760,
+6,24,37,10760,
+18,19,36,10760,
+3,26,36,10760,
+3,6,44,10760,
+3,23,38,10760,
+17,18,37,10760,
+11,30,31,10760,
+9,26,35,10760,
+7,13,42,10760,
+10,19,39,10760,
+6,10,43,10760,
+10,27,34,10760,
+24,25,28,10773,
+17,20,36,10773,
+10,21,38,10773,
+0,7,44,10773,
+8,25,36,10773,
+5,14,42,10773,
+0,31,32,10773,
+10,11,42,10773,
+8,20,39,10773,
+4,17,41,10773,
+1,31,32,10773,
+19,20,35,10773,
+16,19,37,10773,
+8,31,31,10773,
+5,19,40,10773,
+5,5,44,10773,
+11,29,32,10773,
+4,11,43,10773,
+20,25,31,10773,
+19,28,29,10773,
+1,7,44,10773,
+7,16,41,10773,
+9,15,41,10773,
+5,21,39,10773,
+13,27,33,10773,
+23,27,27,10795,
+8,30,32,10795,
+16,24,34,10795,
+4,26,36,10795,
+8,18,40,10795,
+12,20,38,10795,
+4,6,44,10795,
+10,17,40,10795,
+4,23,38,10795,
+2,7,44,10795,
+7,28,34,10795,
+16,17,38,10795,
+23,26,28,10815,
+17,26,32,10815,
+12,18,39,10815,
+2,31,32,10815,
+18,24,33,10815,
+0,15,42,10815,
+0,30,33,10815,
+9,12,42,10815,
+15,26,33,10815,
+19,27,30,10815,
+1,15,42,10815,
+6,27,35,10815,
+1,30,33,10815,
+18,21,35,10815,
+22,22,32,10815,
+8,22,38,10815,
+14,14,40,10815,
+11,24,36,10815,
+0,12,43,10815,
+24,24,29,10843,
+2,30,33,10843,
+16,21,36,10843,
+2,15,42,10843,
+15,18,38,10843,
+21,23,32,10843,
+8,9,43,10843,
+15,20,37,10843,
+13,15,40,10843,
+13,23,36,10843,
+3,7,44,10843,
+12,25,35,10843,
+3,31,32,10843,
+1,12,43,10843,
+7,24,37,10843,
+12,13,41,10843,
+8,29,33,10843,
+0,25,37,10843,
+11,28,33,10843,
+23,25,29,10860,
+1,25,37,10860,
+5,17,41,10860,
+5,11,43,10860,
+14,30,30,10860,
+6,14,42,10860,
+20,21,34,10860,
+5,26,36,10860,
+16,29,30,10860,
+14,24,35,10860,
+0,29,34,10860,
+22,27,28,10871,
+5,6,44,10871,
+6,19,40,10871,
+2,12,43,10871,
+12,22,37,10871,
+8,13,42,10871,
+17,22,35,10871,
+14,29,31,10871,
+19,26,31,10871,
+6,21,39,10871,
+3,30,33,10871,
+11,14,41,10871,
+7,10,43,10871,
+3,15,42,10871,
+5,23,38,10871,
+10,23,37,10871,
+1,29,34,10871,
+2,25,37,10871,
+12,16,40,10871,
+20,24,32,10871,
+0,20,40,10871,
+0,8,44,10871,
+10,26,35,10871,
+13,26,34,10871,
+4,31,32,10871,
+22,26,29,10899,
+1,20,40,10899,
+4,7,44,10899,
+19,22,34,10899,
+16,28,31,10899,
+2,29,34,10899,
+8,16,41,10899,
+1,8,44,10899,
+14,19,38,10899,
+15,16,39,10899,
+9,20,39,10899,
+9,25,36,10899,
+3,12,43,10899,
+11,19,39,10899,
+3,25,37,10899,
+7,27,35,10899,
+9,31,31,10899,
+17,25,33,10899,
+8,28,34,10899,
+2,8,44,10899,
+2,20,40,10899,
+14,28,32,10899,
+0,22,39,10899,
+23,24,30,10927,
+12,30,31,10927,
+4,15,42,10927,
+4,30,33,10927,
+0,18,41,10927,
+15,22,36,10927,
+9,30,32,10927,
+9,18,40,10927,
+1,18,41,10927,
+6,11,43,10927,
+14,17,39,10927,
+11,27,34,10927,
+11,11,42,10927,
+6,17,41,10927,
+11,21,38,10927,
+14,21,37,10927,
+15,25,34,10927,
+18,29,29,10927,
+10,15,41,10927,
+1,22,39,10927,
+3,29,34,10927,
+6,6,44,10927,
+18,28,30,10927,
+6,26,36,10927,
+10,12,42,10927,
+6,23,38,10927,
+3,20,40,10927,
+16,27,32,10927,
+4,12,43,10927,
+2,18,41,10927,
+2,22,39,10927,
+0,28,35,10927,
+22,25,30,10948,
+12,29,32,10948,
+8,24,37,10948,
+21,28,28,10948,
+7,14,42,10948,
+9,22,38,10948,
+3,8,44,10948,
+18,23,34,10948,
+4,25,37,10948,
+11,17,40,10948,
+5,31,32,10948,
+5,7,44,10948,
+7,19,40,10948,
+19,25,32,10948,
+1,28,35,10948,
+16,23,35,10948,
+7,21,39,10948,
+9,29,33,10948,
+21,27,29,10974,
+9,9,43,10974,
+2,28,35,10974,
+8,10,43,10974,
+4,29,34,10974,
+13,20,38,10974,
+21,22,33,10974,
+13,18,39,10974,
+14,27,33,10974,
+3,22,39,10974,
+5,15,42,10974,
+18,27,31,10974,
+3,18,41,10974,
+9,13,42,10974,
+5,30,33,10974,
+12,24,36,10974,
+4,20,40,10974,
+4,8,44,10974,
+0,9,44,10974,
+18,18,37,10974,
+21,26,30,11009,
+12,28,33,11009,
+19,19,36,11009,
+20,23,33,11009,
+9,16,41,11009,
+3,28,35,11009,
+1,9,44,11009,
+5,12,43,11009,
+0,13,43,11009,
+8,27,35,11009,
+13,25,35,11009,
+11,23,37,11009,
+1,13,43,11009,
+13,13,41,11009,
+17,19,37,11009,
+7,17,41,11009,
+23,23,31,11025,
+7,11,43,11025,
+5,25,37,11025,
+18,20,36,11025,
+0,24,38,11025,
+0,16,42,11025,
+7,26,36,11025,
+16,26,33,11025,
+10,25,36,11025,
+12,14,41,11025,
+6,31,32,11025,
+14,23,36,11025,
+1,16,42,11025,
+10,20,39,11025,
+1,24,38,11025,
+17,24,34,11025,
+4,18,41,11025,
+2,9,44,11025,
+6,7,44,11025,
+14,15,40,11025,
+4,22,39,11025,
+22,24,31,11040,
+9,28,34,11040,
+5,29,34,11040,
+17,17,38,11040,
+10,31,31,11040,
+13,22,37,11040,
+2,13,43,11040,
+11,26,35,11040,
+7,23,38,11040,
+8,14,42,11040,
+16,18,38,11040,
+2,16,42,11040,
+10,18,40,11040,
+10,30,32,11040,
+2,24,38,11040,
+18,26,32,11040,
+5,8,44,11040,
+0,0,45,11040,
+15,30,30,11040,
+5,20,40,11040,
+20,20,35,11040,
+4,28,35,11040,
+16,20,37,11040,
+6,15,42,11040,
+8,19,40,11040,
+20,28,29,11070,
+6,30,33,11070,
+0,27,36,11070,
+13,16,40,11070,
+19,24,33,11070,
+0,1,45,11070,
+17,21,36,11070,
+3,9,44,11070,
+15,24,35,11070,
+8,21,39,11070,
+1,27,36,11070,
+9,24,37,11070,
+12,19,39,11070,
+11,15,41,11070,
+19,21,35,11070,
+21,25,31,11079,
+1,1,45,11079,
+15,29,31,11079,
+3,13,43,11079,
+10,22,38,11079,
+14,26,34,11079,
+26,26,26,11109,
+3,24,38,11109,
+0,2,45,11109,
+12,21,38,11109,
+12,27,34,11109,
+11,12,42,11109,
+3,16,42,11109,
+6,12,43,11109,
+20,27,30,11109,
+2,27,36,11109,
+5,22,39,11109,
+13,30,31,11109,
+1,2,45,11109,
+6,25,37,11109,
+9,10,43,11109,
+5,18,41,11109,
+10,29,33,11109,
+15,19,38,11109,
+17,29,30,11109,
+25,26,27,11129,
+16,16,39,11129,
+4,9,44,11129,
+2,2,45,11129,
+12,17,40,11129,
+10,13,42,11129,
+18,22,35,11129,
+6,29,34,11129,
+15,28,32,11129,
+3,27,36,11129,
+8,11,43,11129,
+5,28,35,11129,
+17,28,31,11129,
+13,29,32,11129,
+0,3,45,11129,
+25,25,28,11159,
+7,31,32,11159,
+24,27,27,11159,
+4,13,43,11159,
+7,7,44,11159,
+8,17,41,11159,
+15,17,39,11159,
+1,3,45,11159,
+9,27,35,11159,
+15,21,37,11159,
+4,24,38,11159,
+24,26,28,11164,
+8,26,36,11164,
+4,16,42,11164,
+16,22,36,11164,
+6,20,40,11164,
+6,8,44,11164,
+0,10,44,11164,
+1,10,44,11164,
+8,23,38,11164,
+22,23,32,11164,
+10,16,41,11164,
+20,26,31,11164,
+16,25,34,11164,
+21,21,34,11164,
+7,15,42,11164,
+7,30,33,11164,
+18,25,33,11164,
+2,3,45,11164,
+2,10,44,11164,
+20,22,34,11164,
+10,28,34,11164,
+14,20,38,11164,
+6,18,41,11164,
+13,24,36,11164,
+21,24,32,11174,
+9,14,42,11174,
+0,4,45,11174,
+4,27,36,11174,
+0,21,40,11174,
+14,18,39,11174,
+6,22,39,11174,
+23,27,28,11208,
+0,19,41,11208,
+24,25,29,11208,
+7,12,43,11208,
+17,27,32,11208,
+11,20,39,11208,
+13,28,33,11208,
+5,9,44,11208,
+11,25,36,11208,
+9,19,40,11208,
+12,23,37,11208,
+1,4,45,11208,
+1,21,40,11208,
+3,3,45,11208,
+19,29,29,11208,
+17,23,35,11208,
+9,21,39,11208,
+15,27,33,11208,
+11,31,31,11208,
+5,13,43,11208,
+1,19,41,11208,
+7,25,37,11208,
+3,10,44,11208,
+2,4,45,11208,
+5,16,42,11208,
+2,21,40,11208,
+11,18,40,11208,
+11,30,32,11208,
+0,26,37,11208,
+10,24,37,11208,
+19,28,30,11208,
+5,24,38,11208,
+12,26,35,11208,
+0,14,43,11208,
+6,28,35,11208,
+1,14,43,11208,
+2,19,41,11208,
+23,26,29,11233,
+1,26,37,11233,
+19,23,34,11233,
+14,25,35,11233,
+13,14,41,11233,
+7,29,34,11233,
+0,32,32,11233,
+2,26,37,11233,
+11,22,38,11233,
+2,14,43,11233,
+14,22,37,11233,
+8,31,32,11233,
+20,25,32,11233,
+7,20,40,11233,
+10,10,43,11233,
+7,8,44,11233,
+1,32,32,11233,
+0,31,33,11233,
+3,21,40,11233,
+15,15,40,11233,
+0,23,39,11233,
+12,15,41,11233,
+3,4,45,11233,
+0,5,45,11233,
+15,23,36,11233,
+5,27,36,11233,
+9,17,41,11233,
+13,19,39,11233,
+1,23,39,11233,
+19,27,31,11240,
+9,11,43,11240,
+1,31,33,11240,
+11,29,33,11240,
+1,5,45,11240,
+3,19,41,11240,
+22,28,28,11269,
+24,24,30,11269,
+2,32,32,11269,
+14,16,40,11269,
+12,12,42,11269,
+4,10,44,11269,
+9,26,36,11269,
+6,9,44,11269,
+8,30,33,11269,
+8,15,42,11269,
+0,17,42,11269,
+18,19,37,11269,
+13,27,34,11269,
+6,13,43,11269,
+2,31,33,11269,
+3,14,43,11269,
+9,23,38,11269,
+17,26,33,11269,
+2,23,39,11269,
+3,26,37,11269,
+7,22,39,11269,
+1,17,42,11269,
+2,5,45,11269,
+11,13,42,11269,
+22,27,29,11290,
+7,18,41,11290,
+10,27,35,11290,
+13,21,38,11290,
+23,25,30,11290,
+16,30,30,11290,
+0,30,34,11290,
+6,16,42,11290,
+18,24,34,11290,
+6,24,38,11290,
+19,20,36,11290,
+1,30,34,11290,
+0,11,44,11290,
+4,4,45,11290,
+3,32,32,11290,
+4,21,40,11290,
+15,26,34,11290,
+17,18,38,11290,
+16,24,35,11290,
+14,30,31,11290,
+2,17,42,11290,
+8,12,43,11290,
+22,22,33,11290,
+16,29,31,11290,
+1,11,44,11290,
+8,25,37,11290,
+13,17,40,11290,
+7,28,35,11290,
+4,19,41,11290,
+11,16,41,11290,
+17,20,37,11290,
+3,23,39,11290,
+3,5,45,11290,
+3,31,33,11290,
+21,23,33,11298,
+2,30,34,11298,
+10,14,42,11298,
+22,26,30,11321,
+14,29,32,11321,
+2,11,44,11321,
+11,28,34,11321,
+10,19,40,11321,
+18,21,36,11321,
+16,19,38,11321,
+4,14,43,11321,
+6,27,36,11321,
+5,10,44,11321,
+8,29,34,11321,
+19,26,32,11321,
+4,26,37,11321,
+0,6,45,11321,
+3,17,42,11321,
+1,6,45,11321,
+10,21,39,11321,
+8,8,44,11321,
+8,20,40,11321,
+4,32,32,11321,
+16,28,32,11321,
+12,20,39,11321,
+12,25,36,11321,
+2,6,45,11321,
+20,24,33,11332,
+3,30,34,11332,
+18,29,30,11332,
+20,21,35,11332,
+23,24,31,11371,
+7,9,44,11371,
+16,17,39,11371,
+4,31,33,11371,
+21,28,29,11371,
+5,21,40,11371,
+16,21,37,11371,
+0,29,35,11371,
+3,11,44,11371,
+4,23,39,11371,
+12,31,31,11371,
+4,5,45,11371,
+9,31,32,11371,
+11,24,37,11371,
+7,13,43,11371,
+1,29,35,11371,
+5,19,41,11371,
+13,23,37,11371,
+12,30,32,11371,
+12,18,40,11371,
+14,24,36,11371,
+14,28,33,11371,
+0,25,38,11371,
+7,24,38,11371,
+18,28,31,11371,
+8,22,39,11371,
+17,22,36,11371,
+7,16,42,11371,
+15,20,38,11371,
+8,18,41,11371,
+4,17,42,11371,
+2,29,35,11371,
+1,25,38,11371,
+21,27,30,11404,
+5,26,37,11404,
+17,25,34,11404,
+10,11,43,11404,
+5,14,43,11404,
+22,25,31,11404,
+15,18,39,11404,
+10,17,41,11404,
+9,15,42,11404,
+9,30,33,11404,
+3,6,45,11404,
+19,22,35,11404,
+13,26,35,11404,
+6,10,44,11404,
+12,22,38,11404,
+4,30,34,11404,
+10,26,36,11404,
+5,32,32,11404,
+8,28,35,11404,
+10,23,38,11404,
+4,11,44,11404,
+14,14,41,11404,
+2,25,38,11404,
+16,27,33,11404,
+0,15,43,11404,
+7,27,36,11404,
+0,7,45,11404,
+12,29,33,11404,
+9,12,43,11404,
+5,5,45,11404,
+9,25,37,11404,
+1,7,45,11404,
+3,29,35,11404,
+19,25,33,11408,
+5,31,33,11408,
+1,15,43,11408,
+15,25,35,11408,
+11,27,35,11408,
+13,15,41,11408,
+5,23,39,11408,
+6,21,40,11408,
+12,13,42,11408,
+4,6,45,11408,
+18,27,32,11416,
+2,15,43,11416,
+21,26,31,11444,
+18,23,35,11444,
+2,7,45,11444,
+6,19,41,11444,
+9,29,34,11444,
+5,17,42,11444,
+3,25,38,11444,
+15,22,37,11444,
+14,19,39,11444,
+0,12,44,11444,
+0,28,36,11444,
+14,21,38,11444,
+8,9,44,11444,
+21,22,34,11444,
+5,30,34,11444,
+14,27,34,11444,
+1,12,44,11444,
+15,16,40,11444,
+0,20,41,11444,
+12,16,41,11444,
+26,26,27,11502,
+9,20,40,11502,
+6,14,43,11502,
+6,26,37,11502,
+1,28,36,11502,
+11,14,42,11502,
+16,23,36,11502,
+11,19,40,11502,
+1,20,41,11502,
+4,29,35,11502,
+8,13,43,11502,
+5,11,44,11502,
+23,23,32,11502,
+20,29,29,11502,
+3,7,45,11502,
+11,21,39,11502,
+3,15,43,11502,
+25,27,27,11519,
+12,28,34,11519,
+6,32,32,11519,
+8,24,38,11519,
+8,16,42,11519,
+22,24,32,11519,
+0,22,40,11519,
+20,28,30,11519,
+2,12,44,11519,
+2,28,36,11519,
+10,31,32,11519,
+25,26,28,11529,
+7,10,44,11529,
+1,22,40,11529,
+14,17,40,11529,
+2,20,41,11529,
+20,23,34,11529,
+4,25,38,11529,
+6,31,33,11529,
+6,23,39,11529,
+9,18,41,11529,
+9,22,39,11529,
+5,6,45,11529,
+15,30,31,11529,
+16,26,34,11529,
+0,18,42,11529,
+2,22,40,11529,
+8,27,36,11529,
+17,30,30,11529,
+10,30,33,11529,
+10,15,42,11529,
+18,26,33,11529,
+1,18,42,11529,
+12,24,37,11529,
+24,27,28,11557,
+0,8,45,11557,
+3,12,44,11557,
+3,28,36,11557,
+6,17,42,11557,
+7,21,40,11557,
+15,29,32,11557,
+13,25,36,11557,
+21,25,32,11557,
+4,15,43,11557,
+17,24,35,11557,
+4,7,45,11557,
+20,27,31,11557,
+1,8,45,11557,
+13,20,39,11557,
+3,20,41,11557,
+9,28,35,11557,
+5,29,35,11557,
+17,29,31,11557,
+19,19,37,11557,
+11,17,41,11557,
+13,31,31,11557,
+25,25,29,11568,
+11,11,43,11568,
+7,19,41,11568,
+2,18,42,11568,
+6,30,34,11568,
+18,18,38,11568,
+11,26,36,11568,
+24,26,29,11592,
+13,18,40,11592,
+10,12,43,11592,
+3,22,40,11592,
+19,24,34,11592,
+13,30,32,11592,
+18,20,37,11592,
+6,11,44,11592,
+2,8,45,11592,
+7,14,43,11592,
+17,19,38,11592,
+11,23,38,11592,
+10,25,37,11592,
+14,23,37,11592,
+5,25,38,11592,
+7,26,37,11592,
+4,28,36,11592,
+4,12,44,11592,
+20,20,36,11592,
+14,26,35,11592,
+6,6,45,11592,
+0,24,39,11592,
+15,24,36,11592,
+3,18,42,11592,
+10,29,34,11592,
+13,22,38,11592,
+4,20,41,11592,
+23,28,28,11609,
+7,32,32,11609,
+17,28,32,11609,
+1,24,39,11609,
+15,28,33,11609,
+3,8,45,11609,
+0,27,37,11609,
+19,21,36,11609,
+9,9,44,11609,
+12,27,35,11609,
+13,29,33,11609,
+5,15,43,11609,
+7,31,33,11609,
+5,7,45,11609,
+17,17,39,11609,
+17,21,37,11609,
+1,27,37,11609,
+7,23,39,11609,
+9,13,43,11609,
+23,27,29,11631,
+4,22,40,11631,
+20,26,32,11631,
+8,10,44,11631,
+16,20,38,11631,
+10,20,40,11631,
+2,24,39,11631,
+16,18,39,11631,
+9,24,38,11631,
+9,16,42,11631,
+24,25,30,11645,
+19,29,30,11645,
+2,27,37,11645,
+13,13,42,11645,
+22,23,33,11645,
+7,17,42,11645,
+14,15,41,11645,
+6,29,35,11645,
+12,14,42,11645,
+4,18,42,11645,
+18,22,36,11645,
+7,30,34,11645,
+5,28,36,11645,
+10,18,41,11645,
+10,22,39,11645,
+4,8,45,11645,
+8,21,40,11645,
+0,16,43,11645,
+5,12,44,11645,
+6,25,38,11645,
+23,26,30,11666,
+18,25,34,11666,
+0,13,44,11666,
+12,19,40,11666,
+11,31,32,11666,
+1,16,43,11666,
+3,24,39,11666,
+13,16,41,11666,
+12,21,39,11666,
+19,28,31,11666,
+0,9,45,11666,
+16,25,35,11666,
+7,11,44,11666,
+8,19,41,11666,
+21,24,33,11666,
+9,27,36,11666,
+1,13,44,11666,
+5,20,41,11666,
+17,27,33,11666,
+15,19,39,11666,
+3,27,37,11666,
+21,21,35,11666,
+1,9,45,11666,
+20,22,35,11666,
+2,16,43,11666,
+16,22,37,11666,
+8,14,43,11666,
+8,26,37,11666,
+2,13,44,11666,
+10,28,35,11666,
+22,28,29,11695,
+5,22,40,11695,
+13,28,34,11695,
+15,27,34,11695,
+2,9,45,11695,
+11,15,42,11695,
+6,15,43,11695,
+6,7,45,11695,
+11,30,33,11695,
+15,21,38,11695,
+8,32,32,11695,
+16,16,40,11695,
+0,32,33,11695,
+24,24,31,11726,
+5,18,42,11726,
+4,24,39,11726,
+22,27,30,11726,
+8,23,39,11726,
+5,8,45,11726,
+19,27,32,11726,
+12,17,41,11726,
+13,24,37,11726,
+17,23,36,11726,
+3,13,44,11726,
+3,16,43,11726,
+20,25,33,11726,
+1,32,33,11726,
+11,12,43,11726,
+8,31,33,11726,
+15,17,40,11726,
+4,27,37,11726,
+23,25,31,11737,
+19,23,35,11737,
+7,29,35,11737,
+3,9,45,11737,
+11,25,37,11737,
+0,0,46,11737,
+6,28,36,11737,
+6,12,44,11737,
+12,26,36,11737,
+9,10,44,11737,
+2,32,33,11737,
+0,31,34,11737,
+0,1,46,11737,
+12,23,38,11737,
+14,20,39,11737,
+6,20,41,11737,
+8,17,42,11737,
+16,30,31,11737,
+14,25,36,11737,
+7,25,38,11737,
+10,13,43,11737,
+1,1,46,11737,
+11,29,34,11737,
+14,31,31,11737,
+1,31,34,11737,
+0,26,38,11737,
+14,30,32,11737,
+8,30,34,11737,
+10,24,38,11737,
+0,2,46,11737,
+14,18,40,11737,
+6,22,40,11737,
+10,16,42,11737,
+22,26,31,11772,
+4,16,43,11772,
+11,20,40,11772,
+16,29,32,11772,
+1,26,38,11772,
+1,2,46,11772,
+8,11,44,11772,
+17,26,34,11772,
+4,13,44,11772,
+2,31,34,11772,
+9,21,40,11772,
+4,9,45,11772,
+0,21,41,11772,
+5,24,39,11772,
+3,32,33,11772,
+7,15,43,11772,
+7,7,45,11772,
+5,27,37,11772,
+21,29,29,11795,
+13,27,35,11795,
+1,21,41,11795,
+15,23,37,11795,
+9,19,41,11795,
+2,26,38,11795,
+22,22,34,11795,
+18,30,30,11795,
+14,22,38,11795,
+2,2,46,11795,
+6,18,42,11795,
+0,19,42,11795,
+18,24,35,11795,
+21,28,30,11811,
+0,3,46,11811,
+0,30,35,11811,
+10,27,36,11811,
+0,10,45,11811,
+6,8,45,11811,
+1,3,46,11811,
+11,22,39,11811,
+21,23,34,11811,
+14,29,33,11811,
+1,19,42,11811,
+2,21,41,11811,
+1,30,35,11811,
+11,18,41,11811,
+9,14,43,11811,
+18,29,31,11811,
+1,10,45,11811,
+19,26,33,11811,
+9,26,37,11811,
+3,31,34,11811,
+15,26,35,11811,
+16,24,36,11811,
+12,31,32,11811,
+2,3,46,11811,
+16,28,33,11811,
+7,12,44,11811,
+23,24,32,11837,
+2,10,45,11837,
+2,30,35,11837,
+3,26,38,11837,
+9,32,32,11837,
+0,23,40,11837,
+2,19,42,11837,
+13,14,42,11837,
+18,19,38,11837,
+4,32,33,11837,
+7,28,36,11837,
+19,20,37,11837,
+13,19,40,11837,
+8,29,35,11837,
+1,23,40,11837,
+11,28,35,11837,
+7,20,41,11837,
+5,13,44,11837,
+5,16,43,11837,
+21,27,31,11852,
+13,21,39,11852,
+9,31,33,11852,
+3,21,41,11852,
+5,9,45,11852,
+15,15,41,11852,
+9,23,39,11852,
+18,28,32,11852,
+20,24,34,11852,
+0,4,46,11852,
+0,14,44,11852,
+4,31,34,11852,
+14,16,41,11852,
+6,24,39,11852,
+12,30,33,11852,
+17,20,38,11852,
+7,22,40,11852,
+2,23,40,11852,
+1,14,44,11852,
+22,25,32,11861,
+8,25,38,11861,
+1,4,46,11861,
+12,15,42,11861,
+9,17,42,11861,
+3,3,46,11861,
+6,27,37,11861,
+18,21,37,11861,
+26,27,27,11898,
+17,18,39,11898,
+3,10,45,11898,
+3,19,42,11898,
+3,30,35,11898,
+4,26,38,11898,
+2,14,44,11898,
+2,4,46,11898,
+26,26,28,11906,
+10,10,44,11906,
+14,28,34,11906,
+20,21,36,11906,
+9,30,34,11906,
+12,12,43,11906,
+0,29,36,11906,
+7,18,42,11906,
+9,11,44,11906,
+0,17,43,11906,
+5,32,33,11906,
+7,8,45,11906,
+25,27,28,11927,
+4,21,41,11927,
+8,15,43,11927,
+1,29,36,11927,
+16,19,39,11927,
+12,25,37,11927,
+3,23,40,11927,
+1,17,43,11927,
+13,17,41,11927,
+17,25,35,11927,
+11,13,43,11927,
+4,19,42,11927,
+13,26,36,11927,
+3,4,46,11927,
+2,29,36,11927,
+11,16,42,11927,
+3,14,44,11927,
+14,24,37,11927,
+16,21,38,11927,
+21,26,32,11927,
+12,29,34,11927,
+16,27,34,11927,
+4,10,45,11927,
+6,13,44,11927,
+6,16,43,11927,
+19,22,36,11927,
+11,24,38,11927,
+10,21,40,11927,
+20,29,30,11927,
+4,30,35,11927,
+0,5,46,11927,
+25,26,29,11956,
+18,27,33,11956,
+10,19,41,11956,
+1,5,46,11956,
+19,25,34,11956,
+13,23,38,11956,
+2,17,43,11956,
+6,9,45,11956,
+17,22,37,11956,
+5,31,34,11956,
+8,12,44,11956,
+24,28,28,11968,
+12,20,40,11968,
+8,28,36,11968,
+20,28,31,11968,
+8,20,41,11968,
+4,23,40,11968,
+2,5,46,11968,
+5,26,38,11968,
+10,26,37,11968,
+10,14,43,11968,
+16,17,40,11968,
+24,27,29,11986,
+7,24,39,11986,
+0,11,45,11986,
+15,25,36,11986,
+0,25,39,11986,
+11,27,36,11986,
+15,20,39,11986,
+3,29,36,11986,
+7,27,37,11986,
+1,11,45,11986,
+5,21,41,11986,
+9,29,35,11986,
+1,25,39,11986,
+15,31,31,11986,
+3,17,43,11986,
+23,23,33,11986,
+10,32,32,11986,
+4,14,44,11986,
+8,22,40,11986,
+4,4,46,11986,
+12,22,39,11986,
+6,32,33,11986,
+12,18,41,11986,
+15,30,32,11986,
+18,23,36,11986,
+22,24,33,11986,
+15,18,40,11986,
+17,30,31,11986,
+10,23,39,11986,
+3,5,46,11986,
+25,25,30,12010,
+2,25,39,12010,
+2,11,45,12010,
+5,10,45,12010,
+9,25,38,12010,
+14,27,35,12010,
+5,19,42,12010,
+10,31,33,12010,
+21,22,35,12010,
+5,30,35,12010,
+24,26,30,12028,
+0,6,46,12028,
+8,18,42,12028,
+12,28,35,12028,
+8,8,45,12028,
+4,29,36,12028,
+6,31,34,12028,
+0,28,37,12028,
+10,17,42,12028,
+20,27,32,12028,
+1,6,46,12028,
+15,22,38,12028,
+17,29,32,12028,
+7,16,43,12028,
+13,31,32,12028,
+5,23,40,12028,
+20,23,35,12028,
+7,13,44,12028,
+23,28,29,12049,
+16,23,37,12049,
+4,17,43,12049,
+1,28,37,12049,
+15,29,33,12049,
+9,15,43,12049,
+3,11,45,12049,
+3,25,39,12049,
+21,25,33,12049,
+7,9,45,12049,
+2,6,46,12049,
+14,14,42,12049,
+18,26,34,12049,
+10,30,34,12049,
+6,26,38,12049,
+14,19,40,12049,
+2,28,37,12049,
+10,11,44,12049,
+5,14,44,12049,
+16,26,35,12049,
+4,5,46,12049,
+14,21,39,12049,
+6,21,41,12049,
+23,27,30,12072,
+13,15,42,12072,
+13,30,33,12072,
+17,24,36,12072,
+19,30,30,12072,
+0,15,44,12072,
+6,19,42,12072,
+6,30,35,12072,
+8,24,39,12072,
+6,10,45,12072,
+3,6,46,12072,
+9,12,44,12072,
+9,28,36,12072,
+8,27,37,12072,
+19,24,35,12072,
+1,15,44,12072,
+7,32,33,12072,
+12,13,43,12072,
+15,16,41,12072,
+24,25,31,12091,
+11,21,40,12091,
+9,20,41,12091,
+5,29,36,12091,
+17,28,33,12091,
+4,11,45,12091,
+4,25,39,12091,
+3,28,37,12091,
+11,19,41,12091,
+5,17,43,12091,
+19,29,31,12091,
+13,25,37,12091,
+12,24,38,12091,
+12,16,42,12091,
+0,20,42,12091,
+2,15,44,12091,
+9,22,40,12091,
+6,23,40,12091,
+1,20,42,12091,
+20,26,33,12091,
+0,22,41,12091,
+15,28,34,12091,
+0,7,46,12091,
+22,29,29,12110,
+7,31,34,12110,
+1,7,46,12110,
+10,29,35,12110,
+23,26,31,12110,
+5,5,46,12110,
+13,29,34,12110,
+11,14,43,12110,
+1,22,41,12110,
+11,26,37,12110,
+14,17,41,12110,
+19,19,38,12110,
+22,28,30,12125,
+14,26,36,12125,
+6,14,44,12125,
+4,6,46,12125,
+2,20,42,12125,
+18,20,38,12125,
+9,18,42,12125,
+2,22,41,12125,
+7,26,38,12125,
+11,32,32,12125,
+22,23,34,12125,
+13,20,40,12125,
+8,13,44,12125,
+10,25,38,12125,
+20,20,37,12125,
+18,18,39,12125,
+8,16,43,12125,
+0,12,45,12125,
+2,7,46,12125,
+12,27,36,12125,
+14,23,38,12125,
+19,28,32,12125,
+4,28,37,12125,
+1,12,45,12125,
+15,24,37,12125,
+8,9,45,12125,
+3,15,44,12125,
+5,11,45,12125,
+19,21,37,12125,
+5,25,39,12125,
+11,31,33,12125,
+17,19,39,12125,
+11,23,39,12125,
+7,21,41,12125,
+3,20,42,12125,
+21,24,34,12140,
+6,29,36,12140,
+0,27,38,12140,
+2,12,45,12140,
+0,18,43,12140,
+17,27,34,12140,
+7,30,35,12140,
+11,17,42,12140,
+3,7,46,12140,
+10,15,43,12140,
+17,21,38,12140,
+1,27,38,12140,
+18,25,35,12140,
+6,17,43,12140,
+7,10,45,12140,
+13,22,39,12140,
+3,22,41,12140,
+1,18,43,12140,
+7,19,42,12140,
+13,18,41,12140,
+22,27,31,12180,
+0,24,40,12180,
+24,24,32,12191,
+5,6,46,12191,
+4,15,44,12191,
+18,22,37,12191,
+2,18,43,12191,
+1,24,40,12191,
+2,27,38,12191,
+8,32,33,12191,
+11,30,34,12191,
+16,20,39,12191,
+16,25,36,12191,
+11,11,44,12191,
+23,25,32,12212,
+7,23,40,12212,
+17,17,40,12212,
+21,21,36,12212,
+0,33,33,12212,
+5,28,37,12212,
+16,31,31,12212,
+13,28,35,12212,
+9,24,39,12212,
+3,12,45,12212,
+9,27,37,12212,
+19,27,33,12212,
+1,33,33,12212,
+15,27,35,12212,
+0,8,46,12212,
+16,18,40,12212,
+0,32,34,12212,
+20,22,36,12212,
+2,24,40,12212,
+10,28,36,12212,
+16,30,32,12212,
+4,20,42,12212,
+10,12,44,12212,
+1,32,34,12212,
+20,25,34,12212,
+8,31,34,12212,
+4,22,41,12212,
+14,31,32,12212,
+4,7,46,12212,
+7,14,44,12212,
+1,8,46,12212,
+10,20,41,12212,
+3,18,43,12212,
+6,25,39,12212,
+3,27,38,12212,
+21,29,30,12233,
+2,33,33,12233,
+6,11,45,12233,
+2,32,34,12233,
+8,26,38,12233,
+22,26,32,12246,
+2,8,46,12246,
+10,22,40,12246,
+16,22,38,12246,
+4,12,45,12246,
+14,15,42,12246,
+14,30,33,12246,
+3,24,40,12246,
+18,30,31,12246,
+12,21,40,12246,
+19,23,36,12246,
+9,16,43,12246,
+12,19,41,12246,
+8,21,41,12246,
+16,29,33,12246,
+5,15,44,12246,
+15,19,40,12246,
+0,31,35,12246,
+9,13,44,12246,
+21,28,31,12260,
+7,29,36,12260,
+9,9,45,12260,
+11,29,35,12260,
+1,31,35,12260,
+7,17,43,12260,
+17,23,37,12260,
+27,27,27,12290,
+3,33,33,12290,
+15,21,39,12290,
+13,13,43,12290,
+10,18,42,12290,
+6,6,46,12290,
+8,19,42,12290,
+3,8,46,12290,
+13,24,38,12290,
+8,10,45,12290,
+3,32,34,12290,
+5,20,42,12290,
+18,29,32,12290,
+12,14,43,12290,
+12,26,37,12290,
+4,27,38,12290,
+6,28,37,12290,
+13,16,42,12290,
+8,30,35,12290,
+26,27,28,12309,
+4,18,43,12309,
+14,25,37,12309,
+5,22,41,12309,
+11,25,38,12309,
+17,26,35,12309,
+2,31,35,12309,
+5,7,46,12309,
+0,16,44,12309,
+12,32,32,12309,
+4,24,40,12309,
+26,26,29,12343,
+19,26,34,12343,
+8,23,40,12343,
+14,29,34,12343,
+16,16,41,12343,
+25,28,28,12343,
+22,22,35,12343,
+1,16,44,12343,
+5,12,45,12343,
+13,27,36,12343,
+12,23,39,12343,
+23,24,33,12343,
+4,33,33,12343,
+12,31,33,12343,
+9,32,33,12343,
+21,27,32,12343,
+0,13,45,12343,
+7,25,39,12343,
+1,13,45,12343,
+11,15,43,12343,
+15,17,41,12343,
+25,27,29,12358,
+21,23,35,12358,
+3,31,35,12358,
+7,11,45,12358,
+4,32,34,12358,
+8,14,44,12358,
+18,24,36,12358,
+14,20,40,12358,
+16,28,34,12358,
+4,8,46,12358,
+2,16,44,12358,
+0,30,36,12358,
+15,26,36,12358,
+0,9,46,12358,
+18,28,33,12358,
+1,30,36,12358,
+12,17,42,12358,
+6,15,44,12358,
+10,24,39,12358,
+0,26,39,12358,
+22,25,33,12358,
+1,26,39,12358,
+15,23,38,12358,
+1,9,46,12358,
+5,18,43,12358,
+9,31,34,12358,
+5,27,38,12358,
+10,27,37,12358,
+2,13,45,12358,
+20,30,30,12364,
+12,30,34,12364,
+2,30,36,12364,
+6,20,42,12364,
+2,9,46,12364,
+5,24,40,12364,
+14,18,41,12364,
+6,7,46,12364,
+9,26,38,12364,
+11,12,44,12364,
+2,26,39,12364,
+11,28,36,12364,
+24,28,29,12404,
+14,22,39,12404,
+6,22,41,12404,
+25,26,30,12404,
+16,24,37,12404,
+20,24,35,12404,
+8,29,36,12404,
+3,16,44,12404,
+20,29,31,12404,
+7,28,37,12404,
+8,17,43,12404,
+4,31,35,12404,
+11,20,41,12404,
+5,33,33,12404,
+3,13,45,12404,
+9,21,41,12404,
+14,28,35,12404,
+6,12,45,12404,
+0,21,42,12404,
+10,13,44,12404,
+5,8,46,12404,
+11,22,40,12404,
+10,16,43,12404,
+5,32,34,12404,
+19,20,38,12404,
+3,30,36,12404,
+24,27,30,12434,
+9,19,42,12434,
+3,26,39,12434,
+18,19,39,12434,
+1,21,42,12434,
+9,30,35,12434,
+3,9,46,12434,
+21,26,33,12434,
+9,10,45,12434,
+20,28,32,12434,
+4,16,44,12434,
+18,21,38,12434,
+6,27,38,12434,
+0,0,47,12434,
+2,21,42,12434,
+11,18,42,12434,
+18,27,34,12434,
+6,18,43,12434,
+0,29,37,12434,
+13,21,40,12434,
+17,25,36,12434,
+20,21,37,12434,
+9,23,40,12434,
+8,25,39,12434,
+12,29,35,12434,
+17,20,39,12434,
+0,23,41,12434,
+0,1,47,12434,
+8,11,45,12434,
+4,13,45,12434,
+7,15,44,12434,
+16,27,35,12434,
+15,31,32,12434,
+0,19,43,12434,
+5,31,35,12434,
+23,29,29,12471,
+17,31,31,12471,
+19,25,35,12471,
+1,23,41,12471,
+1,29,37,12471,
+1,1,47,12471,
+1,19,43,12471,
+25,25,31,12471,
+13,19,41,12471,
+4,30,36,12471,
+6,24,40,12471,
+10,32,33,12471,
+4,26,39,12471,
+17,18,40,12471,
+7,20,42,12471,
+24,26,31,12493,
+23,28,30,12493,
+17,30,32,12493,
+4,9,46,12493,
+12,25,38,12493,
+0,2,47,12493,
+9,14,44,12493,
+13,14,43,12493,
+2,29,37,12493,
+15,30,33,12493,
+3,21,42,12493,
+15,15,42,12493,
+1,2,47,12493,
+7,22,41,12493,
+2,19,43,12493,
+23,23,34,12493,
+6,33,33,12493,
+7,7,46,12493,
+2,23,41,12493,
+13,26,37,12493,
+19,22,37,12493,
+14,24,38,12493,
+6,8,46,12493,
+22,24,34,12493,
+6,32,34,12493,
+14,16,42,12493,
+0,10,46,12493,
+8,28,37,12493,
+10,31,34,12493,
+5,16,44,12493,
+1,10,46,12493,
+16,19,40,12493,
+17,22,38,12493,
+2,2,47,12493,
+13,32,32,12493,
+20,27,33,12501,
+12,15,43,12501,
+11,24,39,12501,
+0,3,47,12501,
+16,21,39,12501,
+9,29,36,12501,
+7,12,45,12501,
+5,13,45,12501,
+23,27,31,12528,
+17,29,33,12528,
+13,23,39,12528,
+11,27,37,12528,
+15,25,37,12528,
+3,23,41,12528,
+9,17,43,12528,
+13,31,33,12528,
+3,29,37,12528,
+1,3,47,12528,
+3,19,43,12528,
+2,10,46,12528,
+10,26,38,12528,
+4,21,42,12528,
+0,14,45,12528,
+21,22,36,12528,
+14,27,36,12528,
+5,30,36,12528,
+5,26,39,12528,
+18,23,37,12528,
+10,21,41,12528,
+2,3,47,12528,
+19,30,31,12528,
+7,27,38,12528,
+6,31,35,12528,
+13,17,42,12528,
+5,9,46,12528,
+7,18,43,12528,
+15,29,34,12528,
+1,14,45,12528,
+21,25,34,12528,
+12,12,44,12528,
+12,28,36,12528,
+12,20,41,12528,
+0,17,44,12528,
+8,15,44,12528,
+0,4,47,12528,
+13,30,34,12528,
+15,20,40,12528,
+7,24,40,12528,
+0,25,40,12528,
+3,10,46,12528,
+20,23,36,12528,
+2,14,45,12528,
+18,26,35,12528,
+10,10,45,12528,
+10,19,42,12528,
+22,29,30,12567,
+10,30,35,12567,
+24,25,32,12567,
+4,19,43,12567,
+4,23,41,12567,
+16,17,41,12567,
+1,17,44,12567,
+1,4,47,12567,
+4,29,37,12567,
+11,13,44,12567,
+11,16,43,12567,
+19,29,32,12567,
+1,25,40,12567,
+7,33,33,12567,
+3,3,47,12567,
+9,25,39,12567,
+9,11,45,12567,
+16,26,36,12567,
+8,20,42,12567,
+12,22,40,12567,
+6,16,44,12567,
+0,28,38,12567,
+7,8,46,12567,
+1,28,38,12567,
+2,25,40,12567,
+22,28,31,12601,
+2,4,47,12601,
+2,17,44,12601,
+23,26,32,12601,
+17,28,34,12601,
+8,22,41,12601,
+10,23,40,12601,
+7,32,34,12601,
+16,23,38,12601,
+5,21,42,12601,
+15,22,39,12601,
+6,13,45,12601,
+15,18,41,12601,
+3,14,45,12601,
+12,18,42,12601,
+10,14,44,12601,
+4,10,46,12601,
+20,26,34,12601,
+6,30,36,12601,
+2,28,38,12601,
+6,9,46,12601,
+6,26,39,12601,
+8,12,45,12601,
+19,24,36,12601,
+9,28,37,12601,
+0,5,47,12601,
+17,24,37,12601,
+3,25,40,12601,
+3,17,44,12601,
+3,4,47,12601,
+11,32,33,12601,
+19,28,33,12606,
+15,28,35,12606,
+7,31,35,12606,
+5,29,37,12606,
+1,5,47,12606,
+5,19,43,12606,
+13,29,35,12606,
+5,23,41,12606,
+4,14,45,12606,
+22,27,32,12652,
+10,29,36,12652,
+8,18,43,12652,
+3,28,38,12652,
+8,27,38,12652,
+0,11,46,12652,
+14,21,40,12652,
+13,25,38,12652,
+1,11,46,12652,
+22,23,35,12652,
+10,17,43,12652,
+11,31,34,12652,
+2,5,47,12652,
+14,19,41,12652,
+8,24,40,12652,
+24,24,33,12677,
+6,21,42,12677,
+21,30,30,12677,
+7,16,44,12677,
+14,14,43,12677,
+14,26,37,12677,
+5,10,46,12677,
+4,17,44,12677,
+4,4,47,12677,
+2,11,46,12677,
+4,25,40,12677,
+16,31,32,12677,
+11,26,38,12677,
+12,24,39,12677,
+8,33,33,12677,
+27,27,28,12720,
+9,15,44,12720,
+12,27,37,12720,
+21,24,35,12720,
+3,5,47,12720,
+21,29,31,12720,
+13,15,43,12720,
+17,27,35,12720,
+7,13,45,12720,
+11,21,41,12720,
+23,25,33,12720,
+19,19,39,12720,
+4,28,38,12720,
+26,28,28,12725,
+20,20,38,12725,
+14,32,32,12725,
+8,32,34,12725,
+8,8,46,12725,
+18,20,39,12725,
+9,20,42,12725,
+18,25,36,12725,
+0,6,47,12725,
+7,30,36,12725,
+0,33,34,12725,
+15,16,42,12725,
+15,24,38,12725,
+16,30,33,12725,
+1,33,34,12725,
+3,11,46,12725,
+14,23,39,12725,
+6,29,37,12725,
+1,6,47,12725,
+10,25,39,12725,
+19,27,34,12725,
+11,30,35,12725,
+6,23,41,12725,
+26,27,29,12749,
+19,21,38,12749,
+18,31,31,12749,
+7,26,39,12749,
+11,19,42,12749,
+6,19,43,12749,
+14,31,33,12749,
+9,22,41,12749,
+5,14,45,12749,
+7,9,46,12749,
+10,11,45,12749,
+18,30,32,12749,
+18,18,40,12749,
+0,22,42,12749,
+2,6,47,12749,
+1,22,42,12749,
+14,17,42,12749,
+12,13,44,12749,
+0,20,43,12749,
+0,32,35,12749,
+21,28,32,12749,
+2,33,34,12749,
+22,26,33,12749,
+13,28,36,12749,
+12,16,43,12749,
+15,27,36,12749,
+1,20,43,12749,
+0,15,45,12749,
+11,23,40,12749,
+5,17,44,12749,
+20,25,35,12749,
+8,31,35,12749,
+1,32,35,12749,
+4,5,47,12749,
+0,27,39,12749,
+16,25,37,12749,
+13,20,41,12749,
+17,19,40,12749,
+9,12,45,12749,
+25,28,29,12767,
+5,25,40,12767,
+21,21,37,12767,
+1,15,45,12767,
+1,27,39,12767,
+17,21,39,12767,
+6,10,46,12767,
+14,30,34,12767,
+2,22,42,12767,
+26,26,30,12771,
+18,22,38,12771,
+20,22,37,12771,
+11,14,44,12771,
+16,29,34,12771,
+13,22,40,12771,
+4,11,46,12771,
+2,32,35,12771,
+10,28,37,12771,
+5,28,38,12771,
+2,20,43,12771,
+18,29,33,12771,
+3,33,34,12771,
+2,27,39,12771,
+9,18,43,12771,
+3,6,47,12771,
+7,21,42,12771,
+9,27,38,12771,
+25,27,30,12790,
+2,15,45,12790,
+16,20,40,12790,
+8,16,44,12790,
+9,24,40,12790,
+12,32,33,12790,
+3,22,42,12790,
+0,24,41,12790,
+6,14,45,12790,
+13,18,42,12790,
+0,31,36,12790,
+1,31,36,12790,
+8,13,45,12790,
+3,32,35,12790,
+1,24,41,12790,
+0,7,47,12790,
+24,29,29,12823,
+3,20,43,12823,
+11,29,36,12823,
+9,33,33,12823,
+21,27,33,12823,
+17,17,41,12823,
+3,27,39,12823,
+19,23,37,12823,
+7,23,41,12823,
+11,17,43,12823,
+7,19,43,12823,
+3,15,45,12823,
+5,5,47,12823,
+7,29,37,12823,
+1,7,47,12823,
+0,18,44,12823,
+24,28,30,12832,
+0,12,46,12832,
+8,30,36,12832,
+8,9,46,12832,
+1,12,46,12832,
+8,26,39,12832,
+4,33,34,12832,
+23,24,34,12832,
+2,31,36,12832,
+9,32,34,12832,
+10,15,44,12832,
+4,6,47,12832,
+16,18,41,12832,
+2,24,41,12832,
+6,17,44,12832,
+6,25,40,12832,
+12,31,34,12832,
+20,30,31,12832,
+1,18,44,12832,
+17,26,36,12832,
+16,22,39,12832,
+25,26,31,12853,
+17,23,38,12853,
+14,29,35,12853,
+2,7,47,12853,
+19,26,35,12853,
+5,11,46,12853,
+10,20,42,12853,
+6,28,38,12853,
+18,28,34,12853,
+12,26,38,12853,
+2,12,46,12853,
+2,18,44,12853,
+4,22,42,12853,
+22,22,36,12853,
+16,28,35,12853,
+22,25,34,12853,
+14,25,38,12853,
+4,32,35,12853,
+4,20,43,12853,
+7,10,46,12853,
+20,29,32,12853,
+10,22,41,12853,
+12,21,41,12853,
+13,24,39,12853,
+15,21,40,12853,
+3,24,41,12853,
+4,15,45,12853,
+24,27,31,12888,
+4,27,39,12888,
+21,23,36,12888,
+3,31,36,12888,
+13,27,37,12888,
+15,19,41,12888,
+11,25,39,12888,
+11,11,45,12888,
+9,31,35,12888,
+3,7,47,12888,
+8,21,42,12888,
+3,12,46,12888,
+10,12,45,12888,
+3,18,44,12888,
+18,24,37,12888,
+0,30,37,12888,
+12,30,35,12888,
+12,19,42,12888,
+1,30,37,12888,
+14,15,43,12888,
+5,6,47,12888,
+7,14,45,12888,
+5,33,34,12888,
+23,29,30,12927,
+15,26,37,12927,
+20,24,36,12927,
+21,26,34,12927,
+0,8,47,12927,
+10,18,43,12927,
+2,30,37,12927,
+5,22,42,12927,
+10,27,38,12927,
+20,28,33,12927,
+4,31,36,12927,
+12,23,40,12927,
+4,24,41,12927,
+6,11,46,12927,
+15,32,32,12927,
+9,16,44,12927,
+5,32,35,12927,
+1,8,47,12927,
+17,31,32,12927,
+11,28,37,12927,
+7,25,40,12927,
+23,28,31,12953,
+5,20,43,12953,
+7,17,44,12953,
+4,7,47,12953,
+8,29,37,12953,
+8,23,41,12953,
+13,13,44,12953,
+25,25,32,12953,
+13,16,43,12953,
+8,19,43,12953,
+5,15,45,12953,
+9,13,45,12953,
+5,27,39,12953,
+15,23,39,12953,
+15,31,33,12953,
+14,28,36,12953,
+24,26,32,12960,
+16,24,38,12960,
+4,12,46,12960,
+16,16,42,12960,
+10,24,40,12960,
+12,14,44,12960,
+0,26,40,12960,
+4,18,44,12960,
+9,30,36,12960,
+14,20,41,12960,
+2,8,47,12960,
+7,28,38,12960,
+1,26,40,12960,
+18,27,35,12960,
+9,9,46,12960,
+3,30,37,12960,
+9,26,39,12960,
+15,17,42,12960,
+17,30,33,12960,
+10,33,33,12960,
+2,26,40,12960,
+8,10,46,12960,
+14,22,40,12960,
+10,32,34,12960,
+15,30,34,12960,
+16,27,36,12960,
+6,33,34,12960,
+6,6,47,12960,
+0,16,45,12960,
+12,29,36,12960,
+19,20,39,12960,
+5,24,41,12960,
+3,8,47,12960,
+11,15,44,12960,
+12,17,43,12960,
+13,32,33,12960,
+5,31,36,12960,
+1,16,45,12960,
+23,27,32,13011,
+19,25,36,13011,
+5,7,47,13011,
+23,23,35,13011,
+19,31,31,13011,
+17,25,37,13011,
+22,30,30,13014,
+14,18,42,13014,
+6,22,42,13014,
+4,30,37,13014,
+5,18,44,13014,
+20,21,38,13014,
+0,29,38,13014,
+18,19,40,13014,
+3,26,40,13014,
+2,16,45,13014,
+20,27,34,13014,
+6,20,43,13014,
+22,24,35,13014,
+5,12,46,13014,
+0,13,46,13014,
+11,20,42,13014,
+8,14,45,13014,
+19,30,32,13014,
+6,32,35,13014,
+6,27,39,13014,
+1,13,46,13014,
+13,31,34,13014,
+11,22,41,13014,
+22,29,31,13036,
+18,21,39,13036,
+10,31,35,13036,
+6,15,45,13036,
+17,29,34,13036,
+9,21,42,13036,
+7,11,46,13036,
+1,29,38,13036,
+8,25,40,13036,
+17,20,40,13036,
+13,26,38,13036,
+19,22,38,13036,
+2,13,46,13036,
+4,8,47,13036,
+2,29,38,13036,
+8,17,44,13036,
+11,12,45,13036,
+0,21,43,13036,
+24,25,33,13070,
+3,16,45,13070,
+0,9,47,13070,
+12,25,39,13070,
+9,23,41,13070,
+19,29,33,13070,
+13,21,41,13070,
+9,19,43,13070,
+9,29,37,13070,
+21,25,35,13070,
+1,21,43,13070,
+1,9,47,13070,
+15,29,35,13070,
+4,26,40,13070,
+10,16,44,13070,
+22,28,32,13072,
+8,28,38,13072,
+14,24,39,13072,
+0,23,42,13072,
+6,31,36,13072,
+6,24,41,13072,
+14,27,37,13072,
+6,7,47,13072,
+11,18,43,13072,
+15,25,38,13072,
+17,22,39,13072,
+13,30,35,13072,
+13,19,42,13072,
+1,23,42,13072,
+23,26,33,13090,
+21,22,37,13090,
+7,33,34,13090,
+10,13,45,13090,
+3,29,38,13090,
+11,27,38,13090,
+5,30,37,13090,
+2,9,47,13090,
+2,21,43,13090,
+17,18,41,13090,
+3,13,46,13090,
+10,30,36,13090,
+6,12,46,13090,
+18,26,36,13090,
+6,18,44,13090,
+11,24,40,13090,
+9,10,46,13090,
+2,23,42,13090,
+12,28,37,13090,
+4,16,45,13090,
+0,19,44,13090,
+18,23,38,13090,
+16,21,40,13090,
+7,22,42,13090,
+27,28,28,13129,
+10,26,39,13129,
+7,32,35,13129,
+17,28,35,13129,
+13,23,40,13129,
+1,19,44,13129,
+5,8,47,13129,
+16,19,41,13129,
+7,20,43,13129,
+20,23,37,13129,
+7,15,45,13129,
+11,33,33,13129,
+15,15,43,13129,
+3,9,47,13129,
+7,27,39,13129,
+3,21,43,13129,
+27,27,29,13149,
+13,14,44,13149,
+20,26,35,13149,
+5,26,40,13149,
+19,28,34,13149,
+2,19,44,13149,
+26,28,29,13166,
+4,29,38,13166,
+8,11,46,13166,
+14,16,43,13166,
+11,32,34,13166,
+16,26,37,13166,
+4,13,46,13166,
+3,23,42,13166,
+22,27,33,13166,
+9,14,45,13166,
+21,30,31,13166,
+0,0,48,13166,
+16,32,32,13166,
+10,21,42,13166,
+26,27,30,13199,
+0,1,48,13199,
+15,28,36,13199,
+6,30,37,13199,
+12,15,44,13199,
+0,28,39,13199,
+7,31,36,13199,
+1,28,39,13199,
+0,25,41,13199,
+9,17,44,13199,
+7,24,41,13199,
+13,29,36,13199,
+1,1,48,13199,
+16,23,39,13199,
+9,25,40,13199,
+21,29,32,13199,
+19,24,37,13199,
+16,31,33,13199,
+5,16,45,13199,
+4,9,47,13199,
+4,21,43,13199,
+3,19,44,13199,
+15,20,41,13199,
+13,17,43,13199,
+25,29,29,13222,
+11,31,35,13222,
+1,25,41,13222,
+7,7,47,13222,
+0,2,48,13222,
+12,20,42,13222,
+24,24,34,13222,
+15,22,40,13222,
+7,12,46,13222,
+12,22,41,13222,
+22,23,36,13222,
+9,28,38,13222,
+7,18,44,13222,
+17,24,38,13222,
+1,2,48,13222,
+8,33,34,13222,
+0,10,47,13222,
+16,17,42,13222,
+6,8,47,13222,
+2,28,39,13222,
+4,23,42,13222,
+18,31,32,13222,
+14,32,33,13222,
+25,28,30,13228,
+1,10,47,13228,
+10,29,37,13228,
+10,19,43,13228,
+10,23,41,13228,
+23,25,34,13228,
+5,29,38,13228,
+5,13,46,13228,
+2,25,41,13228,
+2,2,48,13228,
+8,22,42,13228,
+0,14,46,13228,
+16,30,34,13228,
+6,26,40,13228,
+0,34,34,13228,
+1,34,34,13228,
+15,18,42,13228,
+8,20,43,13228,
+4,19,44,13228,
+14,31,34,13228,
+1,14,46,13228,
+26,26,31,13252,
+21,24,36,13252,
+2,10,47,13252,
+18,30,33,13252,
+0,3,48,13252,
+11,16,44,13252,
+12,12,45,13252,
+8,32,35,13252,
+8,27,39,13252,
+17,27,36,13252,
+8,15,45,13252,
+0,17,45,13252,
+0,33,35,13252,
+3,28,39,13252,
+21,28,33,13252,
+1,3,48,13252,
+5,9,47,13252,
+1,17,45,13252,
+3,25,41,13252,
+5,21,43,13252,
+13,25,39,13252,
+19,27,35,13252,
+1,33,35,13252,
+25,27,31,13266,
+11,13,45,13266,
+2,34,34,13266,
+2,14,46,13266,
+14,26,38,13266,
+22,26,34,13266,
+10,10,46,13266,
+12,18,43,13266,
+24,29,30,13284,
+2,3,48,13284,
+6,16,45,13284,
+11,30,36,13284,
+12,27,38,13284,
+7,30,37,13284,
+14,21,41,13284,
+3,10,47,13284,
+2,17,45,13284,
+2,33,35,13284,
+18,25,37,13284,
+11,26,39,13284,
+5,23,42,13284,
+9,11,46,13284,
+0,4,48,13284,
+0,32,36,13284,
+12,24,40,13284,
+3,34,34,13284,
+8,24,41,13284,
+14,19,42,13284,
+3,14,46,13284,
+6,13,46,13284,
+20,20,39,13284,
+6,29,38,13284,
+1,32,36,13284,
+20,25,36,13284,
+10,14,45,13284,
+1,4,48,13284,
+24,28,31,13309,
+8,31,36,13309,
+14,30,35,13309,
+18,29,34,13309,
+4,28,39,13309,
+19,19,40,13309,
+7,8,47,13309,
+5,19,44,13309,
+15,24,39,13309,
+16,29,35,13309,
+3,3,48,13309,
+20,31,31,13309,
+12,33,33,13309,
+4,25,41,13309,
+13,28,37,13309,
+15,27,37,13309,
+19,21,39,13309,
+3,17,45,13309,
+3,33,35,13309,
+12,32,34,13309,
+20,30,32,13309,
+2,4,48,13309,
+8,18,44,13309,
+8,12,46,13309,
+18,20,40,13309,
+2,32,36,13309,
+10,25,40,13309,
+7,26,40,13309,
+4,10,47,13309,
+10,17,44,13309,
+25,26,32,13349,
+14,23,40,13349,
+16,25,38,13349,
+21,21,38,13349,
+21,27,34,13349,
+9,33,34,13349,
+6,21,43,13349,
+11,21,42,13349,
+6,9,47,13349,
+4,34,34,13349,
+4,14,46,13349,
+14,14,44,13349,
+20,22,38,13349,
+10,28,38,13349,
+6,23,42,13349,
+18,22,39,13349,
+9,22,42,13349,
+0,5,48,13349,
+24,27,32,13375,
+3,4,48,13375,
+18,18,41,13375,
+0,27,40,13375,
+3,32,36,13375,
+23,30,30,13375,
+5,28,39,13375,
+1,27,40,13375,
+23,24,35,13375,
+15,16,43,13375,
+9,32,35,13375,
+7,16,45,13375,
+13,15,44,13375,
+9,20,43,13375,
+12,31,35,13375,
+0,11,47,13375,
+4,33,35,13375,
+1,5,48,13375,
+17,21,40,13375,
+4,17,45,13375,
+20,29,33,13375,
+0,31,37,13375,
+9,15,45,13375,
+11,29,37,13375,
+5,25,41,13375,
+17,19,41,13375,
+11,23,41,13375,
+1,31,37,13375,
+11,19,43,13375,
+9,27,39,13375,
+1,11,47,13375,
+23,29,31,13394,
+2,27,40,13394,
+13,20,42,13394,
+18,28,35,13394,
+6,19,44,13394,
+0,22,43,13394,
+2,5,48,13394,
+14,29,36,13394,
+8,30,37,13394,
+19,26,36,13394,
+1,22,43,13394,
+7,13,46,13394,
+14,17,43,13394,
+22,25,35,13394,
+19,23,38,13394,
+17,26,37,13394,
+13,22,41,13394,
+7,29,38,13394,
+2,11,47,13394,
+2,31,37,13394,
+5,10,47,13394,
+16,28,36,13394,
+4,32,36,13394,
+4,4,48,13394,
+12,16,44,13394,
+0,20,44,13394,
+2,22,43,13394,
+10,11,46,13394,
+22,22,37,13394,
+5,14,46,13394,
+17,32,32,13394,
+1,20,44,13394,
+8,8,47,13394,
+5,34,34,13394,
+16,20,41,13394,
+23,28,32,13434,
+15,32,33,13434,
+3,27,40,13434,
+9,24,41,13434,
+3,5,48,13434,
+9,31,36,13434,
+12,13,45,13434,
+17,23,39,13434,
+7,21,43,13434,
+3,31,37,13434,
+21,23,37,13434,
+7,9,47,13434,
+25,25,33,13445,
+3,11,47,13445,
+17,31,33,13445,
+5,17,45,13445,
+5,33,35,13445,
+2,20,44,13445,
+0,24,42,13445,
+12,30,36,13445,
+0,6,48,13445,
+16,22,40,13445,
+8,26,40,13445,
+20,28,34,13445,
+6,28,39,13445,
+1,6,48,13445,
+24,26,33,13451,
+9,12,46,13451,
+12,26,39,13451,
+9,18,44,13451,
+1,24,42,13451,
+0,15,46,13451,
+15,31,34,13451,
+14,25,39,13451,
+17,17,42,13451,
+11,14,45,13451,
+1,15,46,13451,
+13,18,43,13451,
+6,25,41,13451,
+7,23,42,13451,
+21,26,35,13451,
+13,27,38,13451,
+3,22,43,13451,
+2,6,48,13451,
+18,24,38,13451,
+0,30,38,13451,
+16,18,42,13451,
+2,24,42,13451,
+4,27,40,13451,
+15,26,38,13451,
+1,30,38,13451,
+22,30,31,13467,
+6,10,47,13467,
+8,16,45,13467,
+20,24,37,13467,
+10,33,34,13467,
+2,15,46,13467,
+5,32,36,13467,
+17,30,34,13467,
+4,5,48,13467,
+13,24,40,13467,
+3,20,44,13467,
+4,11,47,13467,
+19,31,32,13467,
+7,19,44,13467,
+11,25,40,13467,
+4,31,37,13467,
+11,17,44,13467,
+23,27,33,13495,
+15,21,41,13495,
+13,33,33,13495,
+6,34,34,13495,
+2,30,38,13495,
+10,22,42,13495,
+6,14,46,13495,
+10,20,43,13495,
+12,21,42,13495,
+0,18,45,13495,
+18,27,36,13495,
+8,13,46,13495,
+11,28,38,13495,
+8,29,38,13495,
+3,24,42,13495,
+22,29,32,13510,
+14,28,37,13510,
+4,22,43,13510,
+3,6,48,13510,
+10,32,35,13510,
+13,32,34,13510,
+10,15,45,13510,
+3,15,46,13510,
+6,17,45,13510,
+9,30,37,13510,
+19,30,33,13510,
+1,18,45,13510,
+15,19,42,13510,
+15,30,35,13510,
+6,33,35,13510,
+10,27,39,13510,
+4,20,44,13510,
+28,28,28,13559,
+0,12,47,13559,
+0,7,48,13559,
+3,30,38,13559,
+16,24,39,13559,
+2,18,45,13559,
+12,23,41,13559,
+15,23,40,13559,
+20,27,35,13559,
+8,21,43,13559,
+12,29,37,13559,
+16,27,37,13559,
+23,23,36,13559,
+12,19,43,13559,
+8,9,47,13559,
+7,28,39,13559,
+1,12,47,13559,
+5,5,48,13559,
+1,7,48,13559,
+27,28,29,13584,
+5,27,40,13584,
+7,25,41,13584,
+13,31,35,13584,
+17,29,35,13584,
+19,25,37,13584,
+5,31,37,13584,
+5,11,47,13584,
+6,32,36,13584,
+4,6,48,13584,
+4,24,42,13584,
+22,24,36,13584,
+10,24,41,13584,
+22,28,33,13584,
+10,31,36,13584,
+8,23,42,13584,
+2,12,47,13584,
+2,7,48,13584,
+14,15,44,13584,
+24,25,34,13584,
+0,26,41,13584,
+9,26,40,13584,
+4,15,46,13584,
+5,22,43,13584,
+27,27,30,13616,
+26,29,29,13616,
+19,29,34,13616,
+17,25,38,13616,
+3,18,45,13616,
+7,10,47,13616,
+11,11,46,13616,
+1,26,41,13616,
+10,12,46,13616,
+10,18,44,13616,
+14,20,42,13616,
+26,28,30,13628,
+4,30,38,13628,
+14,22,41,13628,
+16,16,43,13628,
+8,19,44,13628,
+7,14,46,13628,
+23,26,34,13628,
+13,16,44,13628,
+2,26,41,13628,
+5,20,44,13628,
+19,20,40,13628,
+7,34,34,13628,
+20,21,39,13628,
+21,25,36,13628,
+15,29,36,13628,
+3,7,48,13628,
+0,29,39,13628,
+9,16,45,13628,
+3,12,47,13628,
+13,13,45,13628,
+7,33,35,13628,
+1,29,39,13628,
+7,17,45,13628,
+15,17,43,13628,
+21,31,31,13628,
+13,30,36,13628,
+5,24,42,13628,
+6,27,40,13628,
+4,18,45,13628,
+12,14,45,13628,
+5,6,48,13628,
+18,21,40,13628,
+21,30,32,13638,
+11,33,34,13638,
+26,27,31,13677,
+6,11,47,13677,
+6,31,37,13677,
+13,26,39,13677,
+19,22,39,13677,
+2,29,39,13677,
+9,29,38,13677,
+9,13,46,13677,
+25,29,30,13677,
+5,15,46,13677,
+18,19,41,13677,
+3,26,41,13677,
+0,8,48,13677,
+6,22,43,13677,
+16,32,33,13677,
+18,26,37,13677,
+4,7,48,13677,
+11,22,42,13677,
+21,22,38,13677,
+4,12,47,13677,
+12,17,44,13677,
+7,32,36,13677,
+22,27,34,13677,
+17,28,36,13677,
+8,28,39,13677,
+5,30,38,13677,
+1,8,48,13677,
+14,27,38,13677,
+12,25,40,13677,
+10,30,37,13677,
+14,18,43,13677,
+25,28,31,13698,
+8,25,41,13698,
+17,20,41,13698,
+11,32,35,13698,
+11,20,43,13698,
+19,28,35,13698,
+3,29,39,13698,
+9,21,43,13698,
+15,25,39,13698,
+11,27,39,13698,
+11,15,45,13698,
+21,29,33,13698,
+9,9,47,13698,
+12,28,38,13698,
+18,32,32,13698,
+14,24,40,13698,
+2,8,48,13698,
+0,16,46,13698,
+20,26,36,13698,
+6,20,44,13698,
+1,16,46,13698,
+4,26,41,13698,
+20,23,38,13698,
+8,10,47,13698,
+16,31,34,13698,
+17,22,40,13698,
+13,21,42,13698,
+14,33,33,13698,
+18,23,39,13698,
+9,23,42,13698,
+5,18,45,13698,
+18,31,33,13698,
+8,34,34,13698,
+8,14,46,13698,
+2,16,46,13698,
+14,32,34,13698,
+6,24,42,13698,
+16,26,38,13698,
+6,6,48,13698,
+10,26,40,13698,
+26,26,32,13734,
+24,30,30,13734,
+6,15,46,13734,
+0,21,44,13734,
+17,18,42,13734,
+24,24,35,13734,
+3,8,48,13734,
+11,31,36,13734,
+24,29,31,13760,
+1,21,44,13760,
+25,27,32,13760,
+5,7,48,13760,
+5,12,47,13760,
+8,17,45,13760,
+15,28,37,13760,
+4,29,39,13760,
+0,13,47,13760,
+11,24,41,13760,
+16,21,41,13760,
+0,23,43,13760,
+7,27,40,13760,
+8,33,35,13760,
+9,19,44,13760,
+7,11,47,13760,
+23,25,35,13760,
+1,23,43,13760,
+13,29,37,13760,
+7,31,37,13760,
+1,13,47,13760,
+13,23,41,13760,
+13,19,43,13760,
+18,30,34,13760,
+6,30,38,13760,
+16,30,35,13760,
+11,18,44,13760,
+19,24,38,13760,
+16,19,42,13760,
+21,28,34,13760,
+11,12,46,13760,
+3,16,46,13760,
+10,16,45,13760,
+2,21,44,13760,
+0,34,35,13760,
+14,31,35,13760,
+2,23,43,13760,
+7,22,43,13760,
+5,26,41,13760,
+1,34,35,13760,
+2,13,47,13760,
+22,23,37,13760,
+4,8,48,13760,
+8,32,36,13760,
+24,28,32,13801,
+0,28,40,13801,
+1,28,40,13801,
+10,13,46,13801,
+7,20,44,13801,
+0,33,36,13801,
+6,18,45,13801,
+10,29,38,13801,
+20,31,32,13801,
+0,9,48,13801,
+16,23,40,13801,
+2,34,35,13801,
+22,26,35,13801,
+9,28,39,13801,
+1,9,48,13801,
+21,24,37,13801,
+0,19,45,13801,
+19,27,36,13801,
+1,33,36,13801,
+15,15,44,13801,
+17,24,39,13801,
+3,21,44,13801,
+17,27,37,13801,
+1,19,45,13801,
+3,23,43,13801,
+3,13,47,13801,
+5,29,39,13801,
+9,25,41,13801,
+14,16,44,13801,
+4,16,46,13801,
+2,28,40,13801,
+6,7,48,13801,
+7,24,42,13801,
+2,9,48,13801,
+6,12,47,13801,
+20,30,33,13809,
+15,20,42,13809,
+0,25,42,13809,
+2,33,36,13809,
+12,33,34,13809,
+10,21,43,13809,
+2,19,45,13809,
+25,26,33,13835,
+11,30,37,13835,
+13,14,45,13835,
+3,34,35,13835,
+1,25,42,13835,
+23,30,31,13835,
+7,15,46,13835,
+18,29,35,13835,
+15,22,41,13835,
+9,10,47,13835,
+12,22,42,13835,
+14,30,36,13835,
+14,26,39,13835,
+18,25,38,13835,
+3,28,40,13835,
+12,20,43,13835,
+9,14,46,13835,
+9,34,34,13835,
+16,29,36,13835,
+7,30,38,13835,
+6,26,41,13835,
+5,8,48,13835,
+0,32,37,13835,
+4,21,44,13835,
+12,32,35,13835,
+8,27,40,13835,
+10,23,42,13835,
+2,25,42,13835,
+8,11,47,13835,
+20,25,37,13835,
+23,29,32,13873,
+16,17,43,13873,
+12,15,45,13873,
+8,31,37,13873,
+1,32,37,13873,
+12,27,39,13873,
+13,25,40,13873,
+13,17,44,13873,
+4,13,47,13873,
+3,33,36,13873,
+3,9,48,13873,
+24,27,33,13873,
+4,23,43,13873,
+21,27,35,13873,
+3,19,45,13873,
+9,33,35,13873,
+9,17,45,13873,
+5,16,46,13873,
+20,29,34,13873,
+13,28,38,13873,
+2,32,37,13873,
+10,19,44,13873,
+4,34,35,13873,
+11,26,40,13873,
+8,22,43,13873,
+7,18,45,13873,
+3,25,42,13873,
+15,18,43,13873,
+15,27,38,13873,
+6,29,39,13873,
+4,28,40,13873,
+8,20,44,13873,
+20,20,40,13873,
+12,31,36,13873,
+0,0,49,13873,
+4,9,48,13873,
+23,24,36,13894,
+4,33,36,13894,
+15,24,40,13894,
+9,32,36,13894,
+14,21,42,13894,
+12,24,41,13894,
+17,32,33,13894,
+5,21,44,13894,
+4,19,45,13894,
+23,28,33,13943,
+11,16,45,13943,
+7,12,47,13943,
+19,21,40,13943,
+3,32,37,13943,
+16,25,39,13943,
+7,7,48,13943,
+0,1,49,13943,
+21,21,39,13943,
+19,19,41,13943,
+5,13,47,13943,
+1,1,49,13943,
+5,23,43,13943,
+15,33,33,13943,
+12,18,44,13943,
+0,10,48,13943,
+6,8,48,13943,
+18,28,36,13943,
+8,24,42,13943,
+12,12,46,13943,
+10,28,39,13943,
+4,25,42,13943,
+1,10,48,13943,
+0,17,46,13943,
+0,2,49,13943,
+0,14,47,13943,
+15,32,34,13943,
+18,20,41,13943,
+0,31,38,13943,
+20,22,39,13943,
+22,25,36,13943,
+8,15,46,13943,
+22,31,31,13972,
+1,14,47,13972,
+10,25,41,13972,
+5,34,35,13972,
+19,26,37,13972,
+14,19,43,13972,
+7,26,41,13972,
+25,25,34,13972,
+1,17,46,13972,
+17,31,34,13972,
+1,2,49,13972,
+14,23,41,13972,
+11,13,46,13972,
+11,29,38,13972,
+1,31,38,13972,
+14,29,37,13972,
+18,22,40,13972,
+2,10,48,13972,
+6,16,46,13972,
+24,26,34,13987,
+22,30,32,13987,
+8,30,38,13987,
+4,32,37,13987,
+19,32,32,13987,
+17,26,38,13987,
+2,31,38,13987,
+2,17,46,13987,
+20,28,35,13987,
+10,10,47,13987,
+2,14,47,13987,
+5,28,40,13987,
+16,28,37,13987,
+2,2,49,13987,
+28,28,29,14016,
+0,3,49,14016,
+5,33,36,14016,
+9,27,40,14016,
+5,9,48,14016,
+0,27,41,14016,
+7,29,39,14016,
+17,21,41,14016,
+5,19,45,14016,
+11,21,43,14016,
+27,29,29,14032,
+1,27,41,14032,
+9,31,37,14032,
+19,23,39,14032,
+15,31,35,14032,
+1,3,49,14032,
+19,31,33,14032,
+9,11,47,14032,
+22,22,38,14032,
+18,18,42,14032,
+10,34,34,14032,
+10,14,46,14032,
+21,26,36,14032,
+8,18,45,14032,
+27,28,30,14049,
+6,21,44,14049,
+3,10,48,14049,
+12,30,37,14049,
+13,33,34,14049,
+6,13,47,14049,
+3,17,46,14049,
+10,17,45,14049,
+3,14,47,14049,
+17,19,42,14049,
+11,23,42,14049,
+17,30,35,14049,
+21,23,38,14049,
+23,27,34,14049,
+5,25,42,14049,
+6,23,43,14049,
+9,22,43,14049,
+2,27,41,14049,
+22,29,33,14049,
+2,3,49,14049,
+3,31,38,14049,
+10,33,35,14049,
+19,30,34,14049,
+15,16,44,14049,
+14,14,45,14049,
+7,8,48,14049,
+8,12,47,14049,
+6,34,35,14049,
+0,4,49,14049,
+26,29,30,14070,
+13,22,42,14070,
+9,20,44,14070,
+5,32,37,14070,
+11,19,44,14070,
+13,32,35,14070,
+17,23,40,14070,
+13,20,43,14070,
+1,4,49,14070,
+3,27,41,14070,
+27,27,31,14094,
+13,27,39,14094,
+13,15,45,14094,
+3,3,49,14094,
+6,28,40,14094,
+16,20,42,14094,
+12,26,40,14094,
+4,10,48,14094,
+20,24,38,14094,
+0,22,44,14094,
+10,32,36,14094,
+0,30,39,14094,
+8,26,41,14094,
+4,31,38,14094,
+14,25,40,14094,
+26,28,31,14104,
+14,17,44,14104,
+15,30,36,14104,
+18,24,39,14104,
+2,4,49,14104,
+4,14,47,14104,
+6,33,36,14104,
+6,9,48,14104,
+1,22,44,14104,
+4,17,46,14104,
+16,22,41,14104,
+7,16,46,14104,
+9,24,42,14104,
+15,26,39,14104,
+1,30,39,14104,
+18,27,37,14104,
+6,19,45,14104,
+9,15,46,14104,
+22,28,34,14104,
+14,28,38,14104,
+2,22,44,14104,
+0,11,48,14104,
+2,30,39,14104,
+25,30,30,14133,
+12,16,45,14133,
+20,27,36,14133,
+6,25,42,14133,
+0,20,45,14133,
+9,30,38,14133,
+0,24,43,14133,
+7,21,44,14133,
+4,27,41,14133,
+13,24,41,14133,
+3,4,49,14133,
+1,11,48,14133,
+0,5,49,14133,
+8,29,39,14133,
+1,20,45,14133,
+21,31,32,14133,
+17,29,36,14133,
+24,25,35,14133,
+1,24,43,14133,
+11,28,39,14133,
+13,31,36,14133,
+25,29,31,14149,
+23,23,37,14149,
+7,23,43,14149,
+17,17,43,14149,
+7,13,47,14149,
+11,25,41,14149,
+1,5,49,14149,
+19,29,35,14149,
+16,27,38,14149,
+13,18,44,14149,
+12,29,38,14149,
+16,18,43,14149,
+5,10,48,14149,
+12,13,46,14149,
+6,32,37,14149,
+3,22,44,14149,
+2,24,43,14149,
+10,27,40,14149,
+26,27,32,14161,
+2,20,45,14161,
+22,24,37,14161,
+2,11,48,14161,
+19,25,38,14161,
+3,30,39,14161,
+23,26,35,14161,
+21,30,33,14161,
+10,11,47,14161,
+10,31,37,14161,
+5,14,47,14161,
+5,31,38,14161,
+7,34,35,14161,
+9,18,45,14161,
+15,21,42,14161,
+2,5,49,14161,
+5,17,46,14161,
+8,8,48,14161,
+16,24,40,14161,
+4,4,49,14161,
+25,28,32,14180,
+11,14,46,14180,
+7,28,40,14180,
+11,34,34,14180,
+10,22,43,14180,
+3,11,48,14180,
+3,24,43,14180,
+9,12,47,14180,
+0,15,47,14180,
+7,9,48,14180,
+16,33,33,14180,
+3,20,45,14180,
+7,33,36,14180,
+12,21,43,14180,
+17,25,39,14180,
+1,15,47,14180,
+3,5,49,14180,
+21,25,37,14180,
+15,29,37,14180,
+5,27,41,14180,
+15,19,43,14180,
+7,19,45,14180,
+11,17,45,14180,
+15,23,41,14180,
+11,33,35,14180,
+16,32,34,14180,
+10,20,44,14180,
+4,22,44,14180,
+8,16,46,14180,
+24,30,31,14227,
+12,23,42,14227,
+4,30,39,14227,
+0,6,49,14227,
+18,32,33,14227,
+9,26,41,14227,
+21,29,34,14227,
+2,15,47,14227,
+7,25,42,14227,
+1,6,49,14227,
+13,30,37,14227,
+22,27,35,14227,
+10,24,42,14227,
+0,26,42,14227,
+6,10,48,14227,
+0,18,46,14227,
+4,11,48,14227,
+6,14,47,14227,
+11,32,36,14227,
+20,21,40,14227,
+4,24,43,14227,
+24,29,32,14254,
+12,19,44,14254,
+1,26,42,14254,
+1,18,46,14254,
+18,31,34,14254,
+14,33,34,14254,
+19,28,36,14254,
+6,17,46,14254,
+26,26,33,14254,
+4,20,45,14254,
+2,6,49,14254,
+0,29,40,14254,
+8,21,44,14254,
+10,15,46,14254,
+6,31,38,14254,
+16,31,35,14254,
+8,13,47,14254,
+4,5,49,14254,
+19,20,41,14254,
+8,23,43,14254,
+17,28,37,14254,
+7,32,37,14254,
+1,29,40,14254,
+9,29,39,14254,
+3,15,47,14254,
+25,27,33,14266,
+2,26,42,14266,
+2,18,46,14266,
+14,22,42,14266,
+18,26,38,14266,
+10,30,38,14266,
+20,26,37,14266,
+2,29,40,14266,
+13,26,40,14266,
+5,22,44,14266,
+14,20,43,14266,
+8,34,35,14266,
+19,22,40,14266,
+14,32,35,14266,
+14,27,39,14266,
+21,22,39,14266,
+6,27,41,14266,
+18,21,41,14266,
+3,6,49,14266,
+14,15,45,14266,
+5,30,39,14266,
+20,32,32,14272,
+8,28,40,14272,
+16,16,44,14272,
+0,12,48,14272,
+24,24,36,14272,
+3,18,46,14272,
+3,26,42,14272,
+18,19,42,14272,
+8,33,36,14272,
+10,18,45,14272,
+8,9,48,14272,
+1,12,48,14272,
+12,28,39,14272,
+24,28,33,14304,
+18,30,35,14304,
+4,15,47,14304,
+8,19,45,14304,
+13,16,45,14304,
+20,31,33,14304,
+5,24,43,14304,
+15,17,44,14304,
+21,28,35,14304,
+0,35,35,14304,
+20,23,39,14304,
+0,7,49,14304,
+15,25,40,14304,
+3,29,40,14304,
+11,27,40,14304,
+12,25,41,14304,
+5,20,45,14304,
+5,11,48,14304,
+23,25,36,14304,
+23,31,31,14316,
+11,31,37,14316,
+1,35,35,14316,
+5,5,49,14316,
+11,11,47,14316,
+1,7,49,14316,
+0,34,36,14316,
+16,30,36,14316,
+2,12,48,14316,
+8,25,42,14316,
+1,34,36,14316,
+15,28,38,14316,
+10,12,47,14316,
+23,30,32,14337,
+9,16,46,14337,
+17,20,42,14337,
+16,26,39,14337,
+14,24,41,14337,
+14,31,36,14337,
+7,10,48,14337,
+4,6,49,14337,
+18,23,40,14337,
+7,31,38,14337,
+7,17,46,14337,
+11,22,43,14337,
+2,35,35,14337,
+17,22,41,14337,
+7,14,47,14337,
+13,13,46,14337,
+13,29,38,14337,
+2,7,49,14337,
+14,18,44,14337,
+22,26,36,14337,
+2,34,36,14337,
+20,30,34,14337,
+4,18,46,14337,
+6,22,44,14337,
+12,14,46,14337,
+12,34,34,14337,
+4,26,42,14337,
+22,23,38,14337,
+6,30,39,14337,
+8,32,37,14337,
+10,26,41,14337,
+4,29,40,14337,
+11,20,44,14337,
+25,26,34,14358,
+3,12,48,14358,
+12,17,45,14358,
+0,33,37,14358,
+9,21,44,14358,
+12,33,35,14358,
+19,24,39,14358,
+13,21,43,14358,
+7,27,41,14358,
+9,13,47,14358,
+9,23,43,14358,
+5,15,47,14358,
+3,7,49,14358,
+1,33,37,14358,
+19,27,37,14358,
+23,29,33,14378,
+3,35,35,14378,
+24,27,34,14394,
+11,24,42,14394,
+3,34,36,14394,
+21,24,38,14394,
+18,29,36,14394,
+6,20,45,14394,
+6,24,43,14394,
+6,11,48,14394,
+16,21,42,14394,
+9,34,35,14394,
+13,23,42,14394,
+5,6,49,14394,
+11,15,46,14394,
+17,27,38,14394,
+10,29,39,14394,
+17,18,43,14394,
+2,33,37,14394,
+12,32,36,14394,
+4,12,48,14394,
+5,26,42,14394,
+9,28,40,14394,
+17,24,40,14394,
+0,23,44,14394,
+5,18,46,14394,
+0,16,47,14394,
+0,8,49,14394,
+0,28,41,14394,
+14,30,37,14394,
+11,30,38,14394,
+4,7,49,14394,
+1,28,41,14394,
+13,19,44,14394,
+16,19,43,14394,
+28,29,29,14461,
+20,29,35,14461,
+5,29,40,14461,
+1,8,49,14461,
+16,23,41,14461,
+9,9,48,14461,
+9,33,36,14461,
+1,16,47,14461,
+21,27,36,14461,
+0,21,45,14461,
+4,35,35,14461,
+16,29,37,14461,
+1,23,44,14461,
+17,33,33,14461,
+3,33,37,14461,
+1,21,45,14461,
+9,19,45,14461,
+8,10,48,14461,
+4,34,36,14461,
+28,28,30,14468,
+0,32,38,14468,
+20,25,38,14468,
+23,28,34,14468,
+22,31,32,14468,
+2,28,41,14468,
+2,8,49,14468,
+8,31,38,14468,
+2,16,47,14468,
+2,23,44,14468,
+17,32,34,14468,
+8,17,46,14468,
+8,14,47,14468,
+7,22,44,14468,
+1,32,38,14468,
+9,25,42,14468,
+18,25,39,14468,
+27,29,30,14504,
+2,21,45,14504,
+7,30,39,14504,
+15,33,34,14504,
+11,18,45,14504,
+6,15,47,14504,
+10,16,46,14504,
+2,32,38,14504,
+14,26,40,14504,
+0,13,48,14504,
+15,22,42,14504,
+5,12,48,14504,
+22,30,33,14504,
+6,6,49,14504,
+12,27,40,14504,
+3,8,49,14504,
+7,20,45,14504,
+11,12,47,14504,
+7,24,43,14504,
+27,28,31,14525,
+12,31,37,14525,
+4,33,37,14525,
+19,32,33,14525,
+8,27,41,14525,
+3,23,44,14525,
+23,24,37,14525,
+15,32,35,14525,
+3,16,47,14525,
+1,13,48,14525,
+0,25,43,14525,
+3,28,41,14525,
+7,11,48,14525,
+15,20,43,14525,
+13,28,39,14525,
+9,32,37,14525,
+1,25,43,14525,
+13,25,41,14525,
+5,7,49,14525,
+3,21,45,14525,
+5,35,35,14525,
+25,25,35,14525,
+17,31,35,14525,
+15,27,39,14525,
+15,15,45,14525,
+6,26,42,14525,
+26,30,30,14527,
+6,18,46,14527,
+2,13,48,14527,
+3,32,38,14527,
+6,29,40,14527,
+14,16,45,14527,
+0,19,46,14527,
+5,34,36,14527,
+18,28,37,14527,
+10,21,44,14527,
+12,22,43,14527,
+24,26,35,14527,
+10,13,47,14527,
+11,26,41,14527,
+19,31,34,14527,
+26,29,31,14558,
+10,23,43,14558,
+2,25,43,14558,
+22,25,37,14558,
+1,19,46,14558,
+20,28,36,14558,
+12,20,44,14558,
+16,17,44,14558,
+4,8,49,14558,
+20,20,41,14558,
+19,26,38,14558,
+13,14,46,14558,
+4,23,44,14558,
+4,16,47,14558,
+16,25,40,14558,
+4,28,41,14558,
+10,34,35,14558,
+2,19,46,14558,
+14,29,38,14558,
+22,29,34,14558,
+13,34,34,14558,
+15,31,36,14558,
+27,27,32,14594,
+0,9,49,14594,
+4,21,45,14594,
+0,31,39,14594,
+21,21,40,14594,
+3,13,48,14594,
+15,24,41,14594,
+3,25,43,14594,
+5,33,37,14594,
+13,33,35,14594,
+19,21,41,14594,
+13,17,45,14594,
+7,15,47,14594,
+1,31,39,14594,
+11,29,39,14594,
+23,27,35,14594,
+1,9,49,14594,
+26,28,32,14602,
+8,22,44,14602,
+4,32,38,14602,
+12,24,42,14602,
+20,22,40,14602,
+10,28,40,14602,
+16,28,38,14602,
+6,12,48,14602,
+17,30,36,14602,
+9,10,48,14602,
+15,18,44,14602,
+8,30,39,14602,
+10,33,36,14602,
+12,15,46,14602,
+9,14,47,14602,
+14,21,43,14602,
+21,26,37,14602,
+6,35,35,14602,
+2,31,39,14602,
+9,17,46,14602,
+19,19,42,14602,
+2,9,49,14602,
+25,30,31,14619,
+10,19,45,14619,
+3,19,46,14619,
+6,7,49,14619,
+17,26,39,14619,
+9,31,38,14619,
+19,30,35,14619,
+6,34,36,14619,
+18,20,42,14619,
+12,30,38,14619,
+7,18,46,14619,
+8,24,43,14619,
+8,20,45,14619,
+21,32,32,14619,
+10,25,42,14619,
+14,23,42,14619,
+4,13,48,14619,
+18,22,41,14619,
+13,32,36,14619,
+7,26,42,14619,
+8,11,48,14619,
+22,22,39,14619,
+5,16,47,14619,
+19,23,40,14619,
+4,25,43,14619,
+5,23,44,14619,
+5,28,41,14619,
+7,29,40,14619,
+5,8,49,14619,
+25,29,32,14654,
+5,21,45,14654,
+21,23,39,14654,
+9,27,41,14654,
+21,31,33,14654,
+3,31,39,14654,
+3,9,49,14654,
+12,18,45,14654,
+14,19,44,14654,
+4,19,46,14654,
+5,32,38,14654,
+10,32,37,14654,
+0,27,42,14654,
+22,28,35,14654,
+11,16,46,14654,
+17,21,42,14654,
+1,27,42,14654,
+15,30,37,14654,
+26,27,33,14684,
+6,33,37,14684,
+12,12,47,14684,
+21,30,34,14684,
+24,25,36,14684,
+20,24,39,14684,
+18,27,38,14684,
+2,27,42,14684,
+18,18,43,14684,
+7,12,48,14684,
+19,29,36,14684,
+20,27,37,14684,
+0,17,47,14684,
+11,21,44,14684,
+25,28,33,14711,
+4,9,49,14711,
+24,31,31,14711,
+4,31,39,14711,
+8,15,47,14711,
+13,27,40,14711,
+5,13,48,14711,
+5,25,43,14711,
+7,7,49,14711,
+11,23,43,14711,
+17,29,37,14711,
+17,19,43,14711,
+11,13,47,14711,
+7,35,35,14711,
+1,17,47,14711,
+13,31,37,14711,
+17,23,41,14711,
+0,14,48,14711,
+0,30,40,14711,
+24,30,32,14717,
+18,24,40,14717,
+0,0,50,14717,
+0,10,49,14717,
+6,23,44,14717,
+12,26,41,14717,
+16,33,34,14717,
+1,30,40,14717,
+9,22,44,14717,
+6,16,47,14717,
+7,34,36,14717,
+1,14,48,14717,
+14,28,39,14717,
+23,26,36,14717,
+15,26,40,14717,
+6,28,41,14717,
+0,1,50,14717,
+6,8,49,14717,
+14,25,41,14717,
+23,23,38,14717,
+2,17,47,14717,
+6,21,45,14717,
+1,10,49,14717,
+5,19,46,14717,
+13,22,43,14717,
+11,34,35,14717,
+18,33,33,14717,
+9,30,39,14717,
+1,1,50,14717,
+3,27,42,14717,
+8,18,46,14717,
+10,10,48,14717,
+18,32,34,14717,
+8,26,42,14717,
+2,30,40,14717,
+16,22,42,14717,
+22,24,38,14717,
+0,2,50,14717,
+6,32,38,14717,
+2,14,48,14717,
+13,20,44,14717,
+1,2,50,14717,
+10,17,46,14717,
+2,10,49,14717,
+16,32,35,14717,
+10,14,47,14717,
+16,20,43,14717,
+8,29,40,14717,
+10,31,38,14717,
+11,28,40,14717,
+24,29,33,14774,
+9,11,48,14774,
+15,16,45,14774,
+12,29,39,14774,
+16,27,39,14774,
+9,24,43,14774,
+11,33,36,14774,
+9,20,45,14774,
+7,33,37,14774,
+11,19,45,14774,
+19,25,39,14774,
+21,29,35,14774,
+3,17,47,14774,
+5,31,39,14774,
+5,9,49,14774,
+14,34,34,14774,
+14,14,46,14774,
+26,26,34,14777,
+2,2,50,14777,
+0,3,50,14777,
+22,27,36,14777,
+3,30,40,14777,
+6,13,48,14777,
+4,27,42,14777,
+3,14,48,14777,
+0,22,45,14777,
+13,24,42,14777,
+3,10,49,14777,
+1,3,50,14777,
+6,25,43,14777,
+14,33,35,14777,
+1,22,45,14777,
+15,29,38,14777,
+25,27,34,14796,
+13,15,46,14796,
+11,25,42,14796,
+10,27,41,14796,
+14,17,45,14796,
+18,31,35,14796,
+21,25,38,14796,
+8,12,48,14796,
+0,24,44,14796,
+6,19,46,14796,
+13,30,38,14796,
+1,24,44,14796,
+16,24,41,14796,
+2,22,45,14796,
+2,3,50,14796,
+20,32,33,14796,
+16,31,36,14796,
+8,35,35,14796,
+11,32,37,14796,
+23,31,32,14830,
+19,28,37,14830,
+7,8,49,14830,
+17,25,40,14830,
+4,17,47,14830,
+17,17,44,14830,
+7,28,41,14830,
+7,23,44,14830,
+7,16,47,14830,
+7,21,45,14830,
+9,15,47,14830,
+15,21,43,14830,
+14,32,36,14830,
+0,20,46,14830,
+0,4,50,14830,
+24,28,34,14833,
+2,24,44,14833,
+16,18,44,14833,
+8,34,36,14833,
+12,16,46,14833,
+4,30,40,14833,
+4,14,48,14833,
+4,10,49,14833,
+1,4,50,14833,
+20,31,34,14833,
+7,32,38,14833,
+1,20,46,14833,
+17,28,38,14833,
+3,22,45,14833,
+6,9,49,14833,
+13,18,45,14833,
+5,27,42,14833,
+3,3,50,14833,
+6,31,39,14833,
+15,23,42,14833,
+23,30,33,14858,
+2,4,50,14858,
+10,22,44,14858,
+18,30,36,14858,
+2,20,46,14858,
+20,26,38,14858,
+24,24,37,14858,
+0,35,36,14858,
+10,30,39,14858,
+3,24,44,14858,
+21,28,36,14858,
+9,26,42,14858,
+9,18,46,14858,
+12,21,44,14858,
+18,26,39,14858,
+12,13,47,14858,
+0,29,41,14858,
+8,33,37,14858,
+7,13,48,14858,
+1,35,36,14858,
+0,11,49,14858,
+15,19,44,14858,
+12,23,43,14858,
+9,29,40,14858,
+20,21,41,14858,
+5,17,47,14858,
+1,29,41,14858,
+7,25,43,14858,
+1,11,49,14858,
+29,29,29,14911,
+23,25,37,14911,
+2,35,36,14911,
+5,30,40,14911,
+19,20,42,14911,
+12,34,35,14911,
+10,24,43,14911,
+5,14,48,14911,
+28,29,30,14925,
+4,22,45,14925,
+21,22,40,14925,
+3,4,50,14925,
+20,30,35,14925,
+0,34,37,14925,
+16,30,37,14925,
+0,5,50,14925,
+0,26,43,14925,
+10,11,48,14925,
+10,20,45,14925,
+14,27,40,14925,
+3,20,46,14925,
+11,31,38,14925,
+19,22,41,14925,
+14,31,37,14925,
+1,26,43,14925,
+11,14,47,14925,
+1,34,37,14925,
+7,19,46,14925,
+2,11,49,14925,
+5,10,49,14925,
+23,29,34,14925,
+1,5,50,14925,
+13,26,41,14925,
+25,26,35,14925,
+2,29,41,14925,
+11,17,46,14925,
+12,28,40,14925,
+4,24,44,14925,
+22,26,37,14925,
+27,30,30,14963,
+6,27,42,14963,
+14,22,43,14963,
+8,23,44,14963,
+9,12,48,14963,
+0,15,48,14963,
+2,5,50,14963,
+8,28,41,14963,
+12,33,36,14963,
+8,8,49,14963,
+2,34,37,14963,
+20,23,40,14963,
+18,21,42,14963,
+2,26,43,14963,
+8,16,47,14963,
+28,28,31,14963,
+8,21,45,14963,
+1,15,48,14963,
+15,28,39,14963,
+12,19,45,14963,
+24,27,35,14963,
+3,35,36,14963,
+11,27,41,14963,
+27,29,31,14985,
+7,31,39,14985,
+3,29,41,14985,
+13,29,39,14985,
+9,35,35,14985,
+15,25,41,14985,
+3,11,49,14985,
+7,9,49,14985,
+4,4,50,14985,
+8,32,38,14985,
+14,20,44,14985,
+16,26,40,14985,
+4,20,46,14985,
+22,32,32,14985,
+9,34,36,14985,
+12,25,42,14985,
+0,33,38,14985,
+0,18,47,14985,
+2,15,48,14985,
+22,23,39,14985,
+1,33,38,14985,
+3,26,43,14985,
+18,29,37,14985,
+18,19,43,14985,
+1,18,47,14985,
+3,34,37,14985,
+5,22,45,14985,
+17,33,34,14985,
+6,17,47,14985,
+22,31,33,14985,
+19,27,38,14985,
+10,15,47,14985,
+3,5,50,14985,
+18,23,41,14985,
+6,30,40,14985,
+14,24,42,14985,
+0,6,50,14985,
+6,14,48,14985,
+4,35,36,14985,
+2,18,47,14985,
+15,34,34,14985,
+26,30,31,15022,
+5,24,44,15022,
+6,10,49,15022,
+12,32,37,15022,
+16,16,45,15022,
+2,33,38,15022,
+1,6,50,15022,
+27,28,32,15022,
+20,29,36,15022,
+8,13,48,15022,
+14,15,46,15022,
+19,24,40,15022,
+17,22,42,15022,
+17,32,35,15022,
+4,29,41,15022,
+23,28,35,15022,
+21,24,39,15022,
+3,15,48,15022,
+8,25,43,15022,
+4,11,49,15022,
+17,20,43,15022,
+15,17,45,15022,
+19,33,33,15022,
+15,33,35,15022,
+21,27,37,15022,
+9,33,37,15022,
+17,27,39,15022,
+10,26,42,15022,
+22,30,34,15022,
+2,6,50,15022,
+14,30,38,15022,
+10,18,46,15022,
+4,26,43,15022,
+4,34,37,15022,
+19,32,34,15022,
+11,22,44,15022,
+16,29,38,15022,
+8,19,46,15022,
+26,29,32,15059,
+13,16,46,15059,
+10,29,40,15059,
+5,20,46,15059,
+4,5,50,15059,
+11,30,39,15059,
+3,18,47,15059,
+3,33,38,15059,
+7,27,42,15059,
+0,32,39,15059,
+14,18,45,15059,
+3,6,50,15059,
+0,12,49,15059,
+4,15,48,15059,
+6,22,45,15059,
+15,32,36,15059,
+17,31,36,15059,
+11,20,45,15059,
+16,21,43,15059,
+5,35,36,15059,
+9,23,44,15059,
+8,9,49,15059,
+8,31,39,15059,
+20,25,39,15059,
+9,16,47,15059,
+1,12,49,15059,
+13,21,44,15059,
+25,25,36,15064,
+11,24,43,15064,
+1,32,39,15064,
+9,28,41,15064,
+17,24,41,15064,
+11,11,48,15064,
+25,31,31,15103,
+5,29,41,15103,
+13,13,47,15103,
+9,21,45,15103,
+19,31,35,15103,
+5,11,49,15103,
+27,27,33,15103,
+13,23,43,15103,
+7,17,47,15103,
+24,26,36,15103,
+6,24,44,15103,
+0,28,42,15103,
+10,12,48,15103,
+2,12,49,15103,
+12,31,38,15103,
+23,24,38,15103,
+0,7,50,15103,
+9,32,38,15103,
+1,28,42,15103,
+12,14,47,15103,
+26,28,33,15121,
+2,32,39,15121,
+7,14,48,15121,
+17,18,44,15121,
+12,17,46,15121,
+18,25,40,15121,
+16,23,42,15121,
+4,33,38,15121,
+25,30,32,15121,
+4,18,47,15121,
+7,30,40,15121,
+7,10,49,15121,
+5,26,43,15121,
+22,29,35,15121,
+10,35,35,15121,
+5,34,37,15121,
+5,5,50,15121,
+13,34,35,15121,
+1,7,50,15121,
+2,28,42,15121,
+18,28,38,15121,
+10,34,36,15121,
+4,6,50,15121,
+6,20,46,15121,
+22,25,38,15121,
+14,26,41,15121,
+13,28,40,15121,
+2,7,50,15121,
+20,28,37,15121,
+16,19,44,15121,
+21,32,33,15131,
+15,27,40,15131,
+0,23,45,15131,
+12,27,41,15131,
+9,13,48,15131,
+3,12,49,15131,
+13,33,36,15131,
+23,27,36,15131,
+3,32,39,15131,
+5,15,48,15131,
+13,19,45,15131,
+9,25,43,15131,
+11,15,47,15131,
+1,23,45,15131,
+15,31,37,15131,
+25,29,33,15160,
+8,27,42,15160,
+19,30,36,15160,
+0,21,46,15160,
+6,35,36,15160,
+3,28,42,15160,
+3,7,50,15160,
+15,22,43,15160,
+10,33,37,15160,
+2,23,45,15160,
+14,29,39,15160,
+17,30,37,15160,
+5,33,38,15160,
+13,25,42,15160,
+9,19,46,15160,
+1,21,46,15160,
+6,29,41,15160,
+7,22,45,15160,
+6,11,49,15160,
+21,31,34,15160,
+5,18,47,15160,
+19,26,39,15160,
+0,16,48,15160,
+24,31,32,15204,
+6,26,43,15204,
+21,26,38,15204,
+4,12,49,15204,
+15,20,44,15204,
+0,25,44,15204,
+26,27,34,15204,
+11,18,46,15204,
+5,6,50,15204,
+16,28,39,15204,
+1,16,48,15204,
+4,32,39,15204,
+0,31,40,15204,
+7,24,44,15204,
+2,21,46,15204,
+11,26,42,15204,
+6,34,37,15204,
+1,25,44,15204,
+1,31,40,15204,
+11,29,40,15204,
+13,32,37,15204,
+16,25,41,15204,
+8,17,47,15204,
+9,31,39,15204,
+21,21,41,15204,
+9,9,49,15204,
+3,23,45,15204,
+22,28,36,15204,
+20,20,42,15204,
+2,16,48,15204,
+0,8,50,15204,
+8,30,40,15204,
+12,22,44,15204,
+4,28,42,15204,
+8,14,48,15204,
+2,25,44,15204,
+2,31,40,15204,
+15,24,42,15204,
+20,22,41,15204,
+12,30,39,15204,
+17,26,40,15204,
+24,30,33,15244,
+7,20,46,15244,
+4,7,50,15244,
+10,23,44,15244,
+25,28,34,15244,
+10,28,41,15244,
+10,16,47,15244,
+6,15,48,15244,
+8,10,49,15244,
+1,8,50,15244,
+3,21,46,15244,
+21,30,35,15244,
+19,21,42,15244,
+15,15,46,15244,
+10,21,45,15244,
+14,16,46,15244,
+22,22,40,15244,
+10,32,38,15244,
+16,34,34,15244,
+2,8,50,15244,
+3,16,48,15244,
+15,30,38,15244,
+11,12,48,15244,
+18,33,34,15244,
+6,18,47,15244,
+12,24,43,15244,
+6,33,38,15244,
+12,20,45,15244,
+0,13,49,15244,
+7,35,36,15244,
+16,33,35,15244,
+4,23,45,15244,
+24,25,37,15254,
+21,23,40,15254,
+16,17,45,15254,
+3,31,40,15254,
+5,12,49,15254,
+0,19,47,15254,
+5,32,39,15254,
+3,25,44,15254,
+11,35,35,15254,
+19,23,41,15254,
+7,29,41,15254,
+19,29,37,15254,
+19,19,43,15254,
+1,19,47,15254,
+1,13,49,15254,
+7,11,49,15254,
+6,6,50,15254,
+18,22,42,15254,
+10,13,48,15254,
+20,27,38,15254,
+3,8,50,15254,
+14,21,44,15254,
+18,32,35,15254,
+5,28,42,15254,
+18,20,43,15254,
+8,22,45,15254,
+24,29,34,15296,
+4,21,46,15296,
+11,34,36,15296,
+13,31,38,15296,
+23,26,37,15296,
+2,13,49,15296,
+14,23,43,15296,
+2,19,47,15296,
+7,26,43,15296,
+17,29,38,15296,
+18,27,39,15296,
+10,25,43,15296,
+7,34,37,15296,
+15,18,45,15296,
+9,27,42,15296,
+13,14,47,15296,
+5,7,50,15296,
+13,17,46,15296,
+16,32,36,15296,
+20,24,40,15296,
+8,24,44,15296,
+4,16,48,15296,
+14,34,35,15296,
+4,25,44,15296,
+10,19,46,15296,
+23,32,32,15332,
+26,26,35,15332,
+4,31,40,15332,
+21,29,36,15332,
+12,15,47,15332,
+7,15,48,15332,
+20,33,33,15332,
+0,27,43,15332,
+17,21,43,15332,
+23,31,33,15354,
+5,23,45,15354,
+3,13,49,15354,
+3,19,47,15354,
+25,27,35,15354,
+9,17,47,15354,
+23,23,39,15354,
+13,27,41,15354,
+11,33,37,15354,
+1,27,43,15354,
+14,28,40,15354,
+4,8,50,15354,
+20,32,34,15354,
+8,20,46,15354,
+14,33,36,15354,
+0,30,41,15354,
+22,24,39,15354,
+0,9,50,15354,
+18,24,41,15354,
+6,12,49,15354,
+9,14,48,15354,
+6,32,39,15354,
+18,31,36,15354,
+9,30,40,15354,
+14,19,45,15354,
+7,18,47,15354,
+1,9,50,15354,
+7,33,38,15354,
+2,27,43,15354,
+15,26,41,15354,
+17,23,42,15354,
+22,27,37,15354,
+29,29,30,15398,
+9,10,49,15398,
+5,21,46,15398,
+1,30,41,15398,
+10,31,39,15398,
+18,18,44,15398,
+28,30,30,15408,
+12,18,46,15408,
+6,28,42,15408,
+12,26,42,15408,
+23,30,34,15408,
+2,30,41,15408,
+12,29,40,15408,
+24,28,35,15408,
+16,27,40,15408,
+2,9,50,15408,
+5,16,48,15408,
+14,25,42,15408,
+6,7,50,15408,
+8,35,36,15408,
+5,31,40,15408,
+11,23,44,15408,
+4,13,49,15408,
+19,25,40,15408,
+28,29,31,15427,
+8,29,41,15427,
+17,19,44,15427,
+11,16,47,15427,
+20,31,35,15427,
+5,25,44,15427,
+16,31,37,15427,
+11,28,41,15427,
+8,11,49,15427,
+4,19,47,15427,
+3,27,43,15427,
+15,29,39,15427,
+11,21,45,15427,
+21,25,39,15427,
+11,32,38,15427,
+8,26,43,15427,
+13,22,44,15427,
+8,34,37,15427,
+5,8,50,15427,
+16,22,43,15427,
+14,32,37,15427,
+19,28,38,15427,
+3,9,50,15427,
+3,30,41,15427,
+9,22,45,15427,
+6,23,45,15427,
+27,30,31,15461,
+13,30,39,15461,
+12,12,48,15461,
+16,20,44,15461,
+0,36,36,15461,
+28,28,32,15470,
+8,15,48,15470,
+1,36,36,15470,
+9,24,44,15470,
+18,30,37,15470,
+10,27,42,15470,
+0,17,48,15470,
+6,21,46,15470,
+13,20,45,15470,
+0,35,37,15470,
+7,32,39,15470,
+17,28,39,15470,
+21,28,37,15470,
+7,12,49,15470,
+1,17,48,15470,
+13,24,43,15470,
+4,27,43,15470,
+27,29,32,15492,
+12,35,35,15492,
+11,13,48,15492,
+23,29,35,15492,
+17,25,41,15492,
+11,25,43,15492,
+5,19,47,15492,
+1,35,37,15492,
+5,13,49,15492,
+24,24,38,15492,
+12,34,36,15492,
+16,24,42,15492,
+6,16,48,15492,
+2,36,36,15492,
+20,30,36,15492,
+0,14,49,15492,
+6,31,40,15492,
+7,28,42,15492,
+4,9,50,15492,
+15,16,46,15492,
+6,25,44,15492,
+25,26,36,15492,
+20,26,39,15492,
+4,30,41,15492,
+9,20,46,15492,
+8,33,38,15492,
+2,17,48,15492,
+22,32,33,15492,
+8,18,47,15492,
+11,19,46,15492,
+1,14,49,15492,
+7,7,50,15492,
+26,31,31,15520,
+2,35,37,15520,
+10,17,47,15520,
+23,25,38,15520,
+0,34,38,15520,
+6,8,50,15520,
+18,26,40,15520,
+26,30,32,15533,
+10,14,48,15533,
+0,10,50,15533,
+10,30,40,15533,
+16,30,38,15533,
+0,22,46,15533,
+14,31,38,15533,
+1,10,50,15533,
+10,10,49,15533,
+0,24,45,15533,
+24,27,36,15533,
+1,34,38,15533,
+22,31,34,15533,
+17,34,34,15533,
+2,14,49,15533,
+14,14,47,15533,
+1,22,46,15533,
+3,36,36,15533,
+0,0,51,15533,
+14,17,46,15533,
+0,1,51,15533,
+9,35,36,15533,
+15,21,44,15533,
+12,33,37,15533,
+27,28,33,15561,
+1,24,45,15561,
+3,17,48,15561,
+15,23,43,15561,
+1,1,51,15561,
+17,33,35,15561,
+9,11,49,15561,
+17,17,45,15561,
+5,27,43,15561,
+9,29,41,15561,
+11,31,39,15561,
+13,15,47,15561,
+3,35,37,15561,
+7,23,45,15561,
+2,34,38,15561,
+2,22,46,15561,
+22,26,38,15561,
+2,10,50,15561,
+16,18,45,15561,
+0,29,42,15561,
+20,21,42,15561,
+0,2,51,15561,
+2,24,45,15561,
+9,26,43,15561,
+6,19,47,15561,
+19,33,34,15561,
+9,34,37,15561,
+1,29,42,15561,
+5,9,50,15561,
+7,21,46,15561,
+5,30,41,15561,
+26,29,33,15585,
+21,22,41,15585,
+1,2,51,15585,
+15,34,35,15585,
+6,13,49,15585,
+14,27,41,15585,
+3,14,49,15585,
+4,36,36,15585,
+3,10,50,15585,
+8,32,39,15585,
+13,26,42,15585,
+15,28,40,15585,
+2,2,51,15585,
+12,28,41,15585,
+4,17,48,15585,
+18,29,38,15585,
+7,16,48,15585,
+23,28,36,15585,
+3,34,38,15585,
+0,20,47,15585,
+12,16,47,15585,
+13,18,46,15585,
+2,29,42,15585,
+19,22,42,15585,
+17,32,36,15585,
+22,30,35,15585,
+3,22,46,15585,
+8,12,49,15585,
+10,22,45,15585,
+12,23,44,15585,
+3,24,45,15585,
+7,25,44,15585,
+13,29,40,15585,
+15,33,36,15585,
+9,15,48,15585,
+19,20,43,15585,
+19,32,35,15585,
+20,23,41,15585,
+4,35,37,15585,
+25,31,32,15610,
+7,31,40,15610,
+12,21,45,15610,
+0,33,39,15610,
+0,3,51,15610,
+1,20,47,15610,
+20,29,37,15610,
+15,19,45,15610,
+1,33,39,15610,
+19,27,39,15610,
+1,3,51,15610,
+10,24,44,15610,
+8,28,42,15610,
+12,32,38,15610,
+0,26,44,15610,
+1,26,44,15610,
+7,8,50,15610,
+22,23,40,15610,
+4,14,49,15610,
+16,26,41,15610,
+2,20,47,15610,
+25,30,33,15636,
+15,25,42,15636,
+18,21,43,15636,
+9,18,47,15636,
+21,27,38,15636,
+2,3,51,15636,
+27,27,34,15636,
+3,29,42,15636,
+2,33,39,15636,
+9,33,38,15636,
+11,27,42,15636,
+6,27,43,15636,
+14,22,44,15636,
+10,20,46,15636,
+2,26,44,15636,
+26,28,34,15650,
+4,22,46,15650,
+4,10,50,15650,
+4,34,38,15650,
+21,24,40,15650,
+6,30,41,15650,
+18,23,42,15650,
+5,36,36,15650,
+4,24,45,15650,
+12,13,48,15650,
+0,4,51,15650,
+14,30,39,15650,
+6,9,50,15650,
+16,29,39,15650,
+8,23,45,15650,
+5,17,48,15650,
+17,27,40,15650,
+3,20,47,15650,
+19,31,36,15650,
+15,32,37,15650,
+1,4,51,15650,
+12,25,43,15650,
+19,24,41,15650,
+11,17,47,15650,
+5,35,37,15650,
+7,19,47,15650,
+3,33,39,15650,
+21,33,33,15650,
+3,3,51,15650,
+25,25,37,15650,
+13,35,35,15650,
+7,13,49,15650,
+17,31,37,15650,
+14,20,45,15650,
+11,30,40,15650,
+4,29,42,15650,
+8,21,46,15650,
+18,19,44,15650,
+13,34,36,15650,
+11,14,48,15650,
+2,4,51,15650,
+0,11,50,15650,
+24,26,37,15670,
+10,35,36,15670,
+3,26,44,15670,
+12,19,46,15670,
+14,24,43,15670,
+21,32,34,15670,
+22,29,36,15670,
+25,29,34,15699,
+1,11,50,15699,
+10,29,41,15699,
+17,22,43,15699,
+10,11,49,15699,
+5,14,49,15699,
+0,32,40,15699,
+24,32,32,15715,
+8,16,48,15715,
+2,11,50,15715,
+10,26,43,15715,
+8,31,40,15715,
+1,32,40,15715,
+10,34,37,15715,
+5,10,50,15715,
+20,25,40,15715,
+4,20,47,15715,
+17,20,44,15715,
+8,25,44,15715,
+5,22,46,15715,
+5,34,38,15715,
+24,31,33,15736,
+12,31,39,15736,
+0,15,49,15736,
+9,32,39,15736,
+23,24,39,15736,
+5,24,45,15736,
+3,4,51,15736,
+9,12,49,15736,
+0,5,51,15736,
+4,33,39,15736,
+1,15,49,15736,
+1,5,51,15736,
+7,27,43,15736,
+21,31,35,15736,
+23,27,37,15736,
+13,33,37,15736,
+6,36,36,15736,
+16,16,46,15736,
+20,28,38,15736,
+4,26,44,15736,
+2,32,40,15736,
+8,8,50,15736,
+0,18,48,15736,
+10,15,48,15736,
+9,28,42,15736,
+1,18,48,15736,
+17,24,42,15736,
+18,28,39,15736,
+6,17,48,15736,
+14,15,47,15736,
+18,25,41,15736,
+5,29,42,15736,
+22,25,39,15736,
+6,35,37,15736,
+26,27,35,15769,
+11,22,45,15769,
+2,5,51,15769,
+19,30,37,15769,
+15,17,46,15769,
+15,31,38,15769,
+3,11,50,15769,
+7,30,41,15769,
+7,9,50,15769,
+2,15,49,15769,
+24,30,34,15781,
+2,18,48,15781,
+10,33,38,15781,
+17,30,38,15781,
+6,14,49,15781,
+16,21,44,15781,
+4,4,51,15781,
+0,28,43,15781,
+11,24,44,15781,
+10,18,47,15781,
+3,32,40,15781,
+8,13,49,15781,
+13,16,47,15781,
+8,19,47,15781,
+16,23,43,15781,
+1,28,43,15781,
+13,23,44,15781,
+13,28,41,15781,
+5,20,47,15781,
+25,28,35,15795,
+3,5,51,15795,
+15,27,41,15795,
+5,33,39,15795,
+3,15,49,15795,
+13,21,45,15795,
+9,23,45,15795,
+6,34,38,15795,
+6,22,46,15795,
+18,34,34,15795,
+14,26,42,15795,
+14,18,46,15795,
+6,10,50,15795,
+0,6,51,15795,
+12,27,42,15795,
+16,34,35,15795,
+19,26,40,15795,
+2,28,43,15795,
+11,20,46,15795,
+5,26,44,15795,
+4,11,50,15795,
+21,30,36,15795,
+22,28,37,15795,
+13,32,38,15795,
+14,29,40,15795,
+3,18,48,15795,
+6,24,45,15795,
+9,21,46,15795,
+21,26,39,15795,
+17,18,45,15795,
+18,33,35,15795,
+1,6,51,15795,
+4,32,40,15795,
+16,28,40,15795,
+7,36,36,15795,
+9,16,48,15795,
+2,6,51,15795,
+6,29,42,15795,
+16,33,36,15795,
+29,30,30,15876,
+16,19,45,15876,
+23,32,33,15876,
+4,5,51,15876,
+12,17,47,15876,
+9,31,40,15876,
+9,25,44,15876,
+3,28,43,15876,
+13,13,48,15876,
+8,27,43,15876,
+11,35,36,15876,
+4,15,49,15876,
+24,29,35,15876,
+7,17,48,15876,
+0,31,41,15876,
+29,29,31,15895,
+1,31,41,15895,
+11,11,49,15895,
+7,35,37,15895,
+13,25,43,15895,
+11,29,41,15895,
+12,14,48,15895,
+18,32,36,15895,
+4,18,48,15895,
+0,12,50,15895,
+12,30,40,15895,
+10,12,49,15895,
+8,30,41,15895,
+24,25,38,15895,
+20,33,34,15895,
+8,9,50,15895,
+16,25,42,15895,
+15,22,44,15895,
+1,12,50,15895,
+6,20,47,15895,
+0,23,46,15895,
+10,32,39,15895,
+28,30,31,15907,
+1,23,46,15907,
+23,31,34,15907,
+3,6,51,15907,
+13,19,46,15907,
+5,11,50,15907,
+6,33,39,15907,
+14,35,35,15907,
+21,21,42,15907,
+19,29,38,15907,
+11,26,43,15907,
+17,26,41,15907,
+11,34,37,15907,
+15,30,39,15907,
+7,14,49,15907,
+2,31,41,15907,
+2,12,50,15907,
+26,26,36,15907,
+14,34,36,15907,
+10,28,42,15907,
+20,22,42,15907,
+6,26,44,15907,
+16,32,37,15907,
+20,32,35,15907,
+7,34,38,15907,
+4,28,43,15907,
+20,20,43,15907,
+2,23,46,15907,
+22,22,41,15907,
+7,22,46,15907,
+5,32,40,15907,
+28,29,32,15938,
+23,26,38,15938,
+7,10,50,15938,
+0,21,47,15938,
+7,24,45,15938,
+15,24,43,15938,
+11,15,48,15938,
+15,20,45,15938,
+0,25,45,15938,
+20,27,39,15938,
+0,7,51,15938,
+25,27,36,15938,
+19,21,43,15938,
+17,29,39,15938,
+9,19,47,15938,
+1,7,51,15938,
+21,23,41,15938,
+21,29,37,15938,
+1,25,45,15938,
+5,15,49,15938,
+13,31,39,15938,
+1,21,47,15938,
+9,13,49,15938,
+3,31,41,15938,
+5,5,51,15938,
+27,31,31,15948,
+27,30,32,15962,
+18,27,40,15962,
+12,22,45,15962,
+3,12,50,15962,
+5,18,48,15962,
+4,6,51,15962,
+2,7,51,15962,
+14,33,37,15962,
+2,25,45,15962,
+11,18,47,15962,
+19,23,42,15962,
+11,33,38,15962,
+10,23,45,15962,
+2,21,47,15962,
+23,30,35,15962,
+18,31,37,15962,
+3,23,46,15962,
+7,29,42,15962,
+24,28,36,15962,
+8,36,36,15962,
+12,24,44,15962,
+6,11,50,15962,
+18,22,43,15962,
+28,28,33,15983,
+22,27,38,15983,
+20,31,36,15983,
+8,17,48,15983,
+10,21,46,15983,
+0,16,49,15983,
+20,24,41,15983,
+23,23,40,15983,
+4,31,41,15983,
+7,20,47,15983,
+1,16,49,15983,
+19,19,44,15983,
+8,35,37,15983,
+5,28,43,15983,
+3,25,45,15983,
+27,29,33,16004,
+3,7,51,16004,
+3,21,47,16004,
+15,15,47,16004,
+7,33,39,16004,
+9,27,43,16004,
+22,24,40,16004,
+6,32,40,16004,
+10,16,48,16004,
+4,12,50,16004,
+18,20,44,16004,
+12,20,46,16004,
+14,16,47,16004,
+14,28,41,16004,
+10,25,44,16004,
+14,23,44,16004,
+10,31,40,16004,
+4,23,46,16004,
+16,31,38,16004,
+2,16,49,16004,
+8,14,49,16004,
+16,17,46,16004,
+7,26,44,16004,
+26,31,32,16026,
+13,27,42,16026,
+9,30,41,16026,
+14,21,45,16026,
+6,15,49,16026,
+5,6,51,16026,
+9,9,50,16026,
+22,33,33,16026,
+8,22,46,16026,
+18,24,42,16026,
+22,32,34,16026,
+14,32,38,16026,
+0,30,42,16026,
+8,10,50,16026,
+8,34,38,16026,
+6,18,48,16026,
+26,30,33,16056,
+0,27,44,16056,
+15,18,46,16056,
+0,19,48,16056,
+12,35,36,16056,
+15,26,42,16056,
+0,8,51,16056,
+1,30,42,16056,
+0,36,37,16056,
+8,24,45,16056,
+17,21,44,16056,
+23,29,36,16056,
+21,25,40,16056,
+16,27,41,16056,
+1,36,37,16056,
+11,12,49,16056,
+4,21,47,16056,
+1,8,51,16056,
+1,27,44,16056,
+3,16,49,16056,
+19,28,39,16056,
+11,32,39,16056,
+1,19,48,16056,
+12,29,41,16056,
+4,7,51,16056,
+15,29,40,16056,
+4,25,45,16056,
+19,25,41,16056,
+13,17,47,16056,
+5,31,41,16056,
+17,23,43,16056,
+2,30,42,16056,
+18,30,38,16056,
+2,8,51,16056,
+2,36,37,16056,
+13,30,40,16056,
+20,30,37,16056,
+2,19,48,16056,
+2,27,44,16056,
+0,35,38,16056,
+11,28,42,16056,
+0,13,50,16056,
+8,29,42,16056,
+27,28,34,16081,
+5,12,50,16081,
+6,28,43,16081,
+12,26,43,16081,
+12,34,37,16081,
+13,14,48,16081,
+21,28,38,16081,
+25,26,37,16081,
+22,31,35,16081,
+10,13,49,16081,
+1,35,38,16081,
+5,23,46,16081,
+1,13,50,16081,
+10,19,47,16081,
+14,25,43,16081,
+17,34,35,16081,
+7,11,50,16081,
+9,36,36,16081,
+8,20,47,16081,
+2,13,50,16081,
+17,28,40,16081,
+25,32,32,16118,
+14,19,46,16118,
+7,32,40,16118,
+24,24,39,16118,
+26,29,34,16118,
+12,15,48,16118,
+19,34,34,16118,
+6,6,51,16118,
+2,35,38,16118,
+18,18,45,16118,
+3,30,42,16118,
+4,16,49,16118,
+3,8,51,16118,
+3,27,44,16118,
+8,33,39,16118,
+3,36,37,16118,
+24,27,37,16118,
+17,33,36,16118,
+9,17,48,16118,
+3,19,48,16118,
+9,35,37,16118,
+7,15,49,16118,
+5,21,47,16118,
+19,33,35,16118,
+25,31,33,16138,
+17,19,45,16138,
+5,7,51,16138,
+15,35,35,16138,
+11,23,45,16138,
+23,25,39,16138,
+5,25,45,16138,
+8,26,44,16138,
+20,26,40,16138,
+16,22,44,16138,
+12,33,38,16138,
+7,18,48,16138,
+16,30,39,16138,
+15,34,36,16138,
+0,34,39,16138,
+12,18,47,16138,
+17,25,42,16138,
+13,22,45,16138,
+3,35,38,16138,
+3,13,50,16138,
+11,21,46,16138,
+9,14,49,16138,
+14,31,39,16138,
+10,27,43,16138,
+1,34,39,16138,
+6,31,41,16138,
+22,30,36,16149,
+6,12,50,16149,
+4,30,42,16149,
+9,22,46,16149,
+9,34,38,16149,
+22,26,39,16149,
+16,20,45,16149,
+25,30,34,16177,
+2,34,39,16177,
+6,23,46,16177,
+4,36,37,16177,
+4,19,48,16177,
+18,26,41,16177,
+9,10,50,16177,
+4,27,44,16177,
+4,8,51,16177,
+19,32,36,16177,
+16,24,43,16177,
+10,30,41,16177,
+13,24,44,16177,
+11,16,48,16177,
+9,24,45,16177,
+5,16,49,16177,
+7,28,43,16177,
+17,32,37,16177,
+11,25,44,16177,
+0,9,51,16177,
+23,28,37,16177,
+11,31,40,16177,
+27,27,35,16210,
+15,33,37,16210,
+1,9,51,16210,
+8,11,50,16210,
+26,28,35,16222,
+13,20,46,16222,
+4,35,38,16222,
+4,13,50,16222,
+20,29,38,16222,
+6,21,47,16222,
+6,7,51,16222,
+6,25,45,16222,
+9,29,42,16222,
+18,29,39,16222,
+3,34,39,16222,
+2,9,51,16222,
+21,33,34,16222,
+8,32,40,16222,
+24,32,33,16241,
+12,32,39,16241,
+5,30,42,16241,
+14,27,42,16241,
+21,22,42,16241,
+12,12,49,16241,
+0,33,40,16241,
+20,21,43,16241,
+13,35,36,16241,
+1,33,40,16241,
+0,17,49,16241,
+15,28,41,16241,
+8,15,49,16241,
+5,8,51,16241,
+21,32,35,16241,
+15,23,44,16241,
+5,36,37,16241,
+19,27,40,16241,
+5,27,44,16241,
+15,16,47,16241,
+5,19,48,16241,
+0,29,43,16241,
+9,20,47,16241,
+11,19,47,16241,
+1,17,49,16241,
+1,29,43,16241,
+21,27,39,16241,
+7,31,41,16241,
+15,21,45,16241,
+19,31,37,16241,
+3,9,51,16241,
+13,29,41,16241,
+25,29,35,16262,
+9,33,39,16262,
+11,13,49,16262,
+0,24,46,16262,
+12,28,42,16262,
+8,18,48,16262,
+10,36,36,16262,
+4,34,39,16262,
+0,22,47,16262,
+20,23,42,16262,
+2,33,40,16262,
+24,31,34,16276,
+15,32,38,16276,
+9,26,44,16276,
+6,16,49,16276,
+7,12,50,16276,
+1,24,46,16276,
+10,17,48,16276,
+2,29,43,16276,
+13,34,37,16276,
+5,35,38,16276,
+7,23,46,16276,
+13,26,43,16276,
+22,29,37,16276,
+17,31,38,16276,
+5,13,50,16276,
+17,17,46,16276,
+1,22,47,16276,
+25,25,38,16276,
+2,17,49,16276,
+22,23,41,16276,
+19,22,43,16276,
+14,17,47,16276,
+10,35,37,16276,
+14,14,48,16276,
+2,24,46,16276,
+24,26,38,16276,
+0,14,50,16276,
+16,26,42,16276,
+16,18,46,16276,
+14,30,40,16276,
+10,14,49,16276,
+8,28,43,16276,
+1,14,50,16276,
+16,29,40,16276,
+19,20,44,16276,
+2,22,47,16276,
+21,31,36,16288,
+21,24,41,16288,
+13,15,48,16288,
+3,33,40,16288,
+4,9,51,16288,
+12,23,45,16288,
+15,25,43,16288,
+7,21,47,16288,
+17,27,41,16288,
+3,29,43,16288,
+7,25,45,16288,
+3,17,49,16288,
+7,7,51,16288,
+11,27,43,16288,
+10,34,38,16288,
+2,14,50,16288,
+10,22,46,16288,
+6,30,42,16288,
+30,30,30,16354,
+10,10,50,16354,
+6,27,44,16354,
+10,24,45,16354,
+19,24,42,16354,
+3,24,46,16354,
+6,19,48,16354,
+0,10,51,16354,
+18,21,44,16354,
+6,8,51,16354,
+0,26,45,16354,
+12,21,46,16354,
+26,27,36,16354,
+6,36,37,16354,
+24,30,35,16354,
+13,33,38,16354,
+1,26,45,16354,
+18,23,43,16354,
+11,30,41,16354,
+3,22,47,16354,
+15,19,46,16354,
+23,27,38,16354,
+13,18,47,16354,
+5,34,39,16354,
+29,30,31,16374,
+9,11,50,16374,
+1,10,51,16374,
+0,0,52,16374,
+0,20,48,16374,
+12,16,48,16374,
+10,29,42,16374,
+20,28,39,16374,
+1,20,48,16374,
+19,30,38,16374,
+6,35,38,16374,
+0,1,52,16374,
+25,28,36,16374,
+23,24,40,16374,
+12,31,40,16374,
+6,13,50,16374,
+0,32,41,16374,
+14,22,45,16374,
+3,14,50,16374,
+2,10,51,16374,
+18,34,35,16374,
+4,33,40,16374,
+9,32,40,16374,
+12,25,44,16374,
+2,26,45,16374,
+4,17,49,16374,
+4,29,43,16374,
+20,25,41,16374,
+7,16,49,16374,
+1,1,52,16374,
+28,31,31,16416,
+29,29,32,16416,
+8,31,41,16416,
+16,35,35,16416,
+1,32,41,16416,
+15,31,39,16416,
+23,33,33,16416,
+9,15,49,16416,
+5,9,51,16416,
+14,24,44,16416,
+2,20,48,16416,
+16,34,36,16416,
+18,28,40,16416,
+8,12,50,16416,
+28,30,32,16424,
+0,2,52,16424,
+4,24,46,16424,
+9,18,48,16424,
+8,23,46,16424,
+17,22,44,16424,
+4,22,47,16424,
+23,32,34,16424,
+22,25,40,16424,
+2,32,41,16424,
+10,20,47,16424,
+1,2,52,16424,
+18,33,36,16424,
+3,10,51,16424,
+3,26,45,16424,
+10,33,39,16424,
+17,30,39,16424,
+18,19,45,16424,
+21,30,37,16424,
+22,28,38,16424,
+10,26,44,16424,
+2,2,52,16424,
+14,20,46,16424,
+20,34,34,16424,
+4,14,50,16424,
+0,3,52,16424,
+18,25,42,16424,
+7,30,42,16424,
+11,36,36,16424,
+3,20,48,16424,
+24,29,36,16436,
+6,34,39,16436,
+9,28,43,16436,
+7,36,37,16436,
+13,32,39,16436,
+8,25,45,16436,
+27,31,32,16481,
+17,24,43,16481,
+20,33,35,16481,
+3,32,41,16481,
+7,19,48,16481,
+16,33,37,16481,
+28,29,33,16481,
+8,21,47,16481,
+12,13,49,16481,
+5,33,40,16481,
+1,3,52,16481,
+11,17,48,16481,
+17,20,45,16481,
+7,27,44,16481,
+12,19,47,16481,
+7,8,51,16481,
+23,31,35,16481,
+5,29,43,16481,
+5,17,49,16481,
+11,35,37,16481,
+2,3,52,16481,
+18,32,37,16481,
+5,24,46,16481,
+13,28,42,16481,
+4,10,51,16481,
+14,35,36,16481,
+4,26,45,16481,
+21,26,40,16481,
+7,35,38,16481,
+11,14,49,16481,
+14,29,41,16481,
+27,30,33,16508,
+7,13,50,16508,
+6,9,51,16508,
+5,22,47,16508,
+19,26,41,16508,
+15,27,42,16508,
+0,4,52,16508,
+4,20,48,16508,
+0,28,44,16508,
+20,32,36,16508,
+5,14,50,16508,
+14,34,37,16508,
+8,16,49,16508,
+1,4,52,16508,
+11,34,38,16508,
+1,28,44,16508,
+16,23,44,16508,
+26,26,37,16508,
+11,22,46,16508,
+14,26,43,16508,
+16,28,41,16508,
+4,32,41,16508,
+10,11,50,16508,
+16,16,47,16508,
+24,25,39,16508,
+3,3,52,16508,
+0,11,51,16508,
+11,24,45,16508,
+12,27,43,16508,
+16,21,45,16508,
+1,11,51,16508,
+25,27,37,16514,
+9,31,41,16514,
+13,23,45,16514,
+19,29,39,16514,
+15,17,47,16514,
+26,32,32,16548,
+28,28,34,16548,
+10,32,40,16548,
+2,4,52,16548,
+16,32,38,16548,
+2,28,44,16548,
+14,15,48,16548,
+6,33,40,16548,
+0,18,49,16548,
+9,12,50,16548,
+0,15,50,16548,
+12,30,41,16548,
+0,31,42,16548,
+23,30,36,16548,
+15,30,40,16548,
+10,15,49,16548,
+9,23,46,16548,
+6,17,49,16548,
+5,10,51,16548,
+11,29,42,16548,
+7,34,39,16548,
+5,26,45,16548,
+1,31,42,16548,
+6,29,43,16548,
+2,11,51,16548,
+13,21,46,16548,
+1,15,50,16548,
+21,29,38,16548,
+26,31,33,16570,
+23,26,39,16570,
+1,18,49,16570,
+27,29,34,16570,
+8,30,42,16570,
+6,24,46,16570,
+10,18,48,16570,
+8,36,37,16570,
+3,28,44,16570,
+17,18,46,16570,
+17,26,42,16570,
+24,28,37,16570,
+14,18,47,16570,
+5,20,48,16570,
+20,27,40,16570,
+0,5,52,16570,
+14,33,38,16570,
+3,4,52,16570,
+2,15,50,16570,
+2,18,49,16570,
+8,19,48,16570,
+8,8,51,16570,
+22,33,34,16570,
+2,31,42,16570,
+13,16,48,16570,
+18,31,38,16570,
+6,22,47,16570,
+8,27,44,16570,
+16,25,43,16570,
+11,20,47,16570,
+1,5,52,16570,
+13,31,40,16570,
+5,32,41,16570,
+17,29,40,16570,
+20,31,37,16570,
+13,25,44,16570,
+9,21,47,16570,
+9,25,45,16570,
+3,11,51,16570,
+7,9,51,16570,
+21,21,43,16570,
+11,33,39,16570,
+26,30,34,16609,
+22,22,42,16609,
+6,14,50,16609,
+8,35,38,16609,
+22,32,35,16609,
+8,13,50,16609,
+10,28,43,16609,
+16,19,46,16609,
+20,22,43,16609,
+11,26,44,16609,
+2,5,52,16609,
+15,22,45,16609,
+18,27,41,16609,
+3,18,49,16609,
+21,23,42,16609,
+3,31,42,16609,
+3,15,50,16609,
+22,27,39,16609,
+12,36,36,16609,
+4,28,44,16609,
+20,20,44,16609,
+4,4,52,16609,
+6,26,45,16609,
+6,10,51,16609,
+12,17,48,16609,
+15,24,44,16609,
+7,33,40,16609,
+3,5,52,16609,
+12,35,37,16609,
+0,23,47,16609,
+25,32,33,16663,
+19,21,44,16663,
+0,37,37,16663,
+16,31,39,16663,
+27,28,35,16663,
+4,11,51,16663,
+9,16,49,16663,
+13,19,47,16663,
+7,29,43,16663,
+17,35,35,16663,
+13,13,49,16663,
+7,17,49,16663,
+23,29,37,16663,
+19,23,43,16663,
+1,23,47,16663,
+23,23,41,16663,
+1,37,37,16663,
+20,24,42,16663,
+6,20,48,16663,
+0,6,52,16663,
+0,36,38,16663,
+17,34,36,16663,
+8,34,39,16663,
+15,20,46,16663,
+22,24,41,16663,
+22,31,36,16663,
+14,32,39,16663,
+4,18,49,16663,
+4,31,42,16663,
+6,32,41,16663,
+7,24,46,16663,
+0,25,46,16663,
+1,6,52,16663,
+1,36,38,16663,
+12,14,49,16663,
+4,15,50,16663,
+11,11,50,16663,
+2,37,37,16663,
+2,23,47,16663,
+10,31,41,16663,
+7,22,47,16663,
+1,25,46,16663,
+25,31,34,16692,
+26,29,35,16692,
+19,34,35,16692,
+20,30,38,16692,
+10,12,50,16692,
+2,6,52,16692,
+12,22,46,16692,
+14,28,42,16692,
+12,34,38,16692,
+18,22,44,16692,
+2,36,38,16692,
+12,24,45,16692,
+11,32,40,16692,
+25,26,38,16692,
+19,28,40,16692,
+9,30,42,16692,
+0,12,51,16692,
+5,28,44,16692,
+7,14,50,16692,
+10,23,46,16692,
+2,25,46,16692,
+4,5,52,16692,
+18,30,39,16692,
+0,21,48,16692,
+19,33,36,16692,
+9,19,48,16692,
+21,28,39,16692,
+1,21,48,16692,
+8,9,51,16692,
+9,36,37,16692,
+1,12,51,16692,
+15,35,36,16692,
+9,27,44,16692,
+0,35,39,16692,
+5,11,51,16692,
+21,25,41,16692,
+3,23,47,16692,
+15,29,41,16692,
+1,35,39,16692,
+19,19,45,16692,
+13,27,43,16692,
+3,37,37,16692,
+11,15,49,16692,
+17,33,37,16692,
+12,29,42,16692,
+3,36,38,16692,
+18,24,43,16692,
+11,18,48,16692,
+2,21,48,16692,
+2,12,51,16692,
+24,27,38,16709,
+0,30,43,16709,
+18,20,45,16709,
+3,6,52,16709,
+16,27,42,16709,
+15,34,37,16709,
+1,30,43,16709,
+5,18,49,16709,
+13,30,41,16709,
+15,26,43,16709,
+7,26,45,16709,
+14,23,45,16709,
+5,15,50,16709,
+10,25,45,16709,
+9,13,50,16709,
+3,25,46,16709,
+7,10,51,16709,
+19,25,42,16709,
+9,35,38,16709,
+25,30,35,16735,
+2,35,39,16735,
+10,21,47,16735,
+5,31,42,16735,
+24,24,40,16735,
+2,30,43,16735,
+8,33,40,16735,
+7,20,48,16735,
+12,20,47,16735,
+14,21,46,16735,
+21,34,34,16735,
+0,7,52,16735,
+22,30,37,16735,
+4,37,37,16735,
+8,17,49,16735,
+4,23,47,16735,
+23,25,40,16735,
+15,15,48,16735,
+5,5,52,16735,
+11,28,43,16735,
+1,7,52,16735,
+7,32,41,16735,
+3,21,48,16735,
+24,33,33,16780,
+17,28,41,16780,
+17,23,44,16780,
+3,12,51,16780,
+0,27,45,16780,
+19,32,37,16780,
+12,33,39,16780,
+8,29,43,16780,
+16,17,47,16780,
+27,27,36,16780,
+21,33,35,16780,
+3,35,39,16780,
+17,21,45,16780,
+1,27,45,16780,
+14,16,48,16780,
+16,30,40,16780,
+8,24,46,16780,
+6,28,44,16780,
+26,28,36,16786,
+4,6,52,16786,
+4,36,38,16786,
+0,16,50,16786,
+12,26,44,16786,
+24,32,34,16786,
+0,34,40,16786,
+20,26,41,16786,
+1,16,50,16786,
+23,28,38,16786,
+14,31,40,16786,
+1,34,40,16786,
+10,16,49,16786,
+14,25,44,16786,
+8,22,47,16786,
+2,7,52,16786,
+17,32,38,16786,
+4,25,46,16786,
+15,33,38,16786,
+2,27,45,16786,
+9,34,39,16786,
+3,30,43,16786,
+6,11,51,16786,
+15,18,47,16786,
+8,14,50,16786,
+2,16,50,16786,
+22,26,40,16786,
+2,34,40,16786,
+6,15,50,16786,
+21,32,36,16798,
+6,31,42,16798,
+30,30,31,16861,
+13,36,36,16861,
+4,21,48,16861,
+6,18,49,16861,
+4,12,51,16861,
+3,7,52,16861,
+0,19,49,16861,
+13,17,48,16861,
+20,29,39,16861,
+4,35,39,16861,
+25,29,36,16861,
+24,31,35,16861,
+1,19,49,16861,
+11,31,41,16861,
+5,23,47,16861,
+13,35,37,16861,
+3,27,45,16861,
+9,9,51,16861,
+5,37,37,16861,
+17,25,43,16861,
+29,31,31,16874,
+18,26,42,16874,
+10,30,42,16874,
+18,18,46,16874,
+4,30,43,16874,
+18,29,40,16874,
+11,12,50,16874,
+8,26,45,16874,
+10,19,48,16874,
+8,10,51,16874,
+3,34,40,16874,
+5,36,38,16874,
+10,27,44,16874,
+5,6,52,16874,
+10,36,37,16874,
+29,30,32,16897,
+3,16,50,16897,
+16,22,45,16897,
+14,19,47,16897,
+2,19,49,16897,
+11,23,46,16897,
+13,14,49,16897,
+19,31,38,16897,
+17,19,46,16897,
+5,25,46,16897,
+12,32,40,16897,
+16,24,44,16897,
+8,20,48,16897,
+0,8,52,16897,
+10,35,38,16897,
+28,31,32,16920,
+7,28,44,16920,
+4,7,52,16920,
+10,13,50,16920,
+1,8,52,16920,
+13,34,38,16920,
+8,32,41,16920,
+13,22,46,16920,
+22,29,38,16920,
+5,12,51,16920,
+12,15,49,16920,
+9,33,40,16920,
+15,32,39,16920,
+21,27,40,16920,
+0,33,41,16920,
+0,13,51,16920,
+5,21,48,16920,
+4,27,45,16920,
+13,24,45,16920,
+21,31,37,16920,
+11,25,45,16920,
+19,27,41,16920,
+7,11,51,16920,
+9,29,43,16920,
+5,35,39,16920,
+29,29,33,16946,
+1,13,51,16946,
+25,25,39,16946,
+11,21,47,16946,
+3,19,49,16946,
+17,31,39,16946,
+1,33,41,16946,
+9,17,49,16946,
+16,20,46,16946,
+12,18,48,16946,
+2,8,52,16946,
+4,16,50,16946,
+24,30,36,16946,
+4,34,40,16946,
+15,28,42,16946,
+9,24,46,16946,
+24,26,39,16946,
+28,30,33,16970,
+7,18,49,16970,
+14,27,43,16970,
+7,31,42,16970,
+23,33,34,16970,
+7,15,50,16970,
+26,27,37,16970,
+2,33,41,16970,
+6,23,47,16970,
+21,22,43,16970,
+5,30,43,16970,
+2,13,51,16970,
+6,37,37,16970,
+13,29,42,16970,
+9,22,47,16970,
+18,35,35,16970,
+18,34,36,16970,
+6,36,38,16970,
+6,6,52,16970,
+6,25,46,16970,
+27,32,32,16998,
+20,21,44,16998,
+3,8,52,16998,
+22,23,42,16998,
+0,29,44,16998,
+9,14,50,16998,
+10,34,39,16998,
+14,30,41,16998,
+16,35,36,16998,
+12,28,43,16998,
+11,16,49,16998,
+20,23,43,16998,
+13,20,47,16998,
+16,29,41,16998,
+23,32,35,16998,
+4,19,49,16998,
+25,28,37,16998,
+5,7,52,16998,
+1,29,44,16998,
+3,13,51,16998,
+15,23,45,16998,
+23,27,39,16998,
+3,33,41,16998,
+13,33,39,16998,
+5,27,45,16998,
+27,31,33,17017,
+13,26,44,17017,
+20,34,35,17017,
+6,21,48,17017,
+16,34,37,17017,
+16,26,43,17017,
+6,12,51,17017,
+5,34,40,17017,
+5,16,50,17017,
+21,24,42,17017,
+19,22,44,17017,
+2,29,44,17017,
+28,29,34,17031,
+19,30,39,17031,
+6,35,39,17031,
+15,21,46,17031,
+17,27,42,17031,
+18,33,37,17031,
+9,10,51,17031,
+9,26,45,17031,
+20,28,40,17031,
+8,28,44,17031,
+4,8,52,17031,
+0,9,52,17031,
+9,20,48,17031,
+27,30,34,17061,
+6,30,43,17061,
+20,33,36,17061,
+21,30,38,17061,
+11,30,42,17061,
+15,16,48,17061,
+0,24,47,17061,
+24,29,37,17061,
+9,32,41,17061,
+11,36,37,17061,
+23,31,36,17061,
+8,11,51,17061,
+19,20,45,17061,
+11,19,48,17061,
+15,25,44,17061,
+11,27,44,17061,
+19,24,43,17061,
+1,9,52,17061,
+12,31,41,17061,
+15,31,40,17061,
+1,24,47,17061,
+4,33,41,17061,
+23,24,41,17061,
+3,29,44,17061,
+4,13,51,17061,
+5,19,49,17061,
+7,37,37,17061,
+17,17,47,17061,
+7,23,47,17061,
+0,22,48,17061,
+0,32,42,17061,
+12,12,50,17061,
+14,36,36,17061,
+16,18,47,17061,
+10,33,40,17061,
+2,9,52,17061,
+8,18,49,17061,
+18,23,44,17061,
+6,7,52,17061,
+20,25,42,17061,
+1,22,48,17061,
+7,36,38,17061,
+14,17,48,17061,
+8,31,42,17061,
+17,30,40,17061,
+0,17,50,17061,
+2,24,47,17061,
+8,15,50,17061,
+1,32,42,17061,
+16,33,38,17061,
+22,28,39,17061,
+18,28,41,17061,
+26,32,33,17084,
+12,23,46,17084,
+1,17,50,17084,
+18,21,45,17084,
+22,25,41,17084,
+7,25,46,17084,
+10,17,49,17084,
+11,13,50,17084,
+11,35,38,17084,
+14,35,37,17084,
+6,27,45,17084,
+10,29,43,17084,
+10,24,46,17084,
+6,34,40,17084,
+6,16,50,17084,
+2,22,48,17084,
+18,32,38,17084,
+2,32,42,17084,
+0,26,46,17084,
+13,32,40,17084,
+10,22,47,17084,
+2,17,50,17084,
+1,26,46,17084,
+5,8,52,17084,
+20,32,37,17084,
+26,31,34,17106,
+4,29,44,17106,
+28,28,35,17106,
+14,14,49,17106,
+3,9,52,17106,
+12,21,47,17106,
+7,21,48,17106,
+7,12,51,17106,
+12,25,45,17106,
+3,24,47,17106,
+13,15,49,17106,
+5,13,51,17106,
+15,19,47,17106,
+5,33,41,17106,
+7,35,39,17106,
+27,29,35,17132,
+22,34,34,17132,
+14,34,38,17132,
+10,14,50,17132,
+14,22,46,17132,
+26,26,38,17132,
+2,26,46,17132,
+13,18,48,17132,
+14,24,45,17132,
+0,14,51,17132,
+3,22,48,17132,
+3,32,42,17132,
+17,22,45,17132,
+23,30,37,17132,
+7,30,43,17132,
+1,14,51,17132,
+25,27,38,17132,
+21,26,41,17132,
+6,19,49,17132,
+18,25,43,17132,
+22,33,35,17132,
+3,17,50,17132,
+11,34,39,17132,
+9,28,44,17132,
+12,16,49,17132,
+4,24,47,17132,
+16,32,39,17132,
+10,26,45,17132,
+18,19,46,17132,
+24,25,40,17132,
+10,10,51,17132,
+0,20,49,17132,
+14,29,42,17132,
+3,26,46,17132,
+4,9,52,17132,
+2,14,51,17132,
+17,24,44,17132,
+26,30,35,17183,
+19,26,42,17183,
+5,29,44,17183,
+8,23,47,17183,
+19,29,40,17183,
+1,20,49,17183,
+8,37,37,17183,
+13,28,43,17183,
+7,7,52,17183,
+7,27,45,17183,
+25,33,33,17199,
+21,29,39,17199,
+9,11,51,17199,
+15,27,43,17199,
+0,10,52,17199,
+4,32,42,17199,
+22,32,36,17199,
+6,8,52,17199,
+16,28,42,17199,
+10,20,48,17199,
+8,36,38,17199,
+4,22,48,17199,
+24,28,38,17199,
+7,16,50,17199,
+7,34,40,17199,
+8,25,46,17199,
+17,20,46,17199,
+25,32,34,17215,
+1,10,52,17215,
+14,20,47,17215,
+10,32,41,17215,
+4,17,50,17215,
+23,26,40,17215,
+2,20,49,17215,
+20,31,38,17215,
+9,31,42,17215,
+3,14,51,17215,
+14,33,39,17215,
+6,13,51,17215,
+9,15,50,17215,
+9,18,49,17215,
+18,31,39,17215,
+6,33,41,17215,
+15,30,41,17215,
+2,10,52,17215,
+12,30,42,17215,
+14,26,44,17215,
+4,26,46,17215,
+0,0,53,17215,
+27,28,36,17241,
+12,36,37,17241,
+8,12,51,17241,
+8,21,48,17241,
+0,28,45,17241,
+12,27,44,17241,
+12,19,48,17241,
+17,35,36,17241,
+8,35,39,17241,
+0,31,43,17241,
+11,33,40,17241,
+5,24,47,17241,
+1,28,45,17241,
+20,27,41,17241,
+16,23,45,17241,
+3,20,49,17241,
+0,1,53,17241,
+5,9,52,17241,
+13,31,41,17241,
+1,1,53,17241,
+11,17,49,17241,
+7,19,49,17241,
+19,35,35,17241,
+17,29,41,17241,
+1,31,43,17241,
+25,31,35,17263,
+11,29,43,17263,
+19,34,36,17263,
+26,29,36,17284,
+12,13,50,17284,
+3,10,52,17284,
+0,37,38,17284,
+4,14,51,17284,
+0,2,53,17284,
+6,29,44,17284,
+2,28,45,17284,
+12,35,38,17284,
+5,32,42,17284,
+16,21,46,17284,
+5,22,48,17284,
+11,24,46,17284,
+22,27,40,17284,
+8,30,43,17284,
+23,29,38,17284,
+13,23,46,17284,
+2,31,43,17284,
+1,2,53,17284,
+11,22,47,17284,
+17,34,37,17284,
+17,26,43,17284,
+1,37,38,17284,
+22,31,37,17284,
+5,17,50,17284,
+16,16,48,17284,
+7,8,52,17284,
+2,2,53,17284,
+18,27,42,17284,
+2,37,38,17284,
+15,36,36,17284,
+22,22,43,17284,
+5,26,46,17284,
+4,20,49,17284,
+11,14,50,17284,
+16,31,40,17284,
+16,25,44,17284,
+0,36,39,17284,
+8,27,45,17284,
+21,21,44,17284,
+3,28,45,17284,
+15,17,48,17284,
+0,3,53,17284,
+1,36,39,17284,
+3,31,43,17284,
+9,23,47,17284,
+7,13,51,17284,
+7,33,41,17284,
+15,35,37,17284,
+19,33,37,17284,
+13,25,45,17284,
+13,21,47,17284,
+21,23,43,17284,
+1,3,53,17284,
+9,37,37,17284,
+8,34,40,17284,
+10,28,44,17284,
+8,16,50,17284,
+14,32,40,17284,
+20,22,44,17284,
+4,10,52,17284,
+12,34,39,17284,
+25,30,36,17343,
+24,33,34,17343,
+6,9,52,17343,
+9,36,38,17343,
+2,36,39,17343,
+6,24,47,17343,
+20,30,39,17343,
+5,14,51,17343,
+9,25,46,17343,
+2,3,53,17343,
+10,11,51,17343,
+25,26,39,17343,
+17,33,38,17343,
+21,34,35,17343,
+3,37,38,17343,
+11,26,45,17343,
+17,18,47,17343,
+30,31,31,17371,
+14,15,49,17371,
+23,23,42,17371,
+6,22,48,17371,
+30,30,32,17388,
+18,30,40,17388,
+0,18,50,17388,
+22,24,42,17388,
+14,18,48,17388,
+6,32,42,17388,
+15,34,38,17388,
+10,18,49,17388,
+0,11,52,17388,
+0,35,40,17388,
+11,20,48,17388,
+21,28,40,17388,
+20,24,43,17388,
+0,4,53,17388,
+24,32,35,17388,
+10,31,42,17388,
+4,28,45,17388,
+6,17,50,17388,
+15,22,46,17388,
+1,18,50,17388,
+10,15,50,17388,
+20,20,45,17388,
+13,16,49,17388,
+5,20,49,17388,
+1,35,40,17388,
+1,4,53,17388,
+1,11,52,17388,
+3,36,39,17388,
+21,33,36,17388,
+7,29,44,17388,
+0,15,51,17388,
+9,21,48,17388,
+24,27,39,17388,
+15,24,45,17388,
+29,31,32,17410,
+8,19,49,17410,
+11,32,41,17410,
+19,28,41,17410,
+4,31,43,17410,
+16,19,47,17410,
+19,23,44,17410,
+9,12,51,17410,
+3,3,53,17410,
+1,15,51,17410,
+19,21,45,17410,
+27,27,37,17410,
+9,35,39,17410,
+2,18,50,17410,
+22,30,38,17410,
+6,26,46,17410,
+26,28,37,17410,
+2,11,52,17410,
+4,37,38,17410,
+2,35,40,17410,
+5,10,52,17410,
+2,4,53,17410,
+19,32,38,17410,
+14,28,43,17410,
+21,25,42,17410,
+15,29,42,17410,
+9,30,43,17410,
+29,30,33,17443,
+2,15,51,17443,
+28,32,32,17457,
+8,8,52,17457,
+24,31,36,17457,
+4,36,39,17457,
+18,22,45,17457,
+24,24,41,17457,
+13,30,42,17457,
+6,14,51,17457,
+12,33,40,17457,
+0,23,48,17457,
+3,18,50,17457,
+7,9,52,17457,
+0,25,47,17457,
+15,20,47,17457,
+28,31,33,17476,
+13,36,37,17476,
+3,4,53,17476,
+8,33,41,17476,
+23,28,39,17476,
+8,13,51,17476,
+13,19,48,17476,
+13,27,44,17476,
+7,24,47,17476,
+21,32,37,17476,
+1,23,48,17476,
+12,29,43,17476,
+12,17,49,17476,
+3,35,40,17476,
+17,32,39,17476,
+0,5,53,17476,
+5,28,45,17476,
+3,11,52,17476,
+16,27,43,17476,
+23,25,41,17476,
+1,25,47,17476,
+25,29,37,17476,
+9,27,45,17476,
+19,25,43,17476,
+5,31,43,17476,
+3,15,51,17476,
+1,5,53,17476,
+15,33,39,17476,
+18,24,44,17476,
+12,24,46,17476,
+0,30,44,17476,
+6,20,49,17476,
+16,30,41,17476,
+1,30,44,17476,
+17,28,42,17476,
+12,22,47,17476,
+7,22,48,17476,
+7,32,42,17476,
+9,16,50,17476,
+2,23,48,17476,
+15,26,44,17476,
+9,34,40,17476,
+0,34,41,17476,
+2,5,53,17476,
+10,37,37,17476,
+29,29,34,17500,
+19,19,46,17500,
+13,13,50,17500,
+13,35,38,17500,
+14,31,41,17500,
+5,37,38,17500,
+10,23,47,17500,
+1,34,41,17500,
+2,25,47,17500,
+7,17,50,17500,
+2,30,44,17500,
+18,20,46,17500,
+12,14,50,17500,
+10,36,38,17500,
+28,30,34,17514,
+6,10,52,17514,
+4,18,50,17514,
+20,26,42,17514,
+4,35,40,17514,
+14,23,46,17514,
+23,34,34,17514,
+8,29,44,17514,
+22,26,41,17514,
+10,25,46,17514,
+7,26,46,17514,
+4,4,53,17514,
+11,28,44,17514,
+2,34,41,17514,
+4,11,52,17514,
+20,29,40,17514,
+5,36,39,17514,
+0,21,49,17514,
+3,23,48,17514,
+27,32,33,17539,
+4,15,51,17539,
+3,25,47,17539,
+17,23,45,17539,
+19,31,39,17539,
+9,19,49,17539,
+3,5,53,17539,
+23,33,35,17539,
+11,11,51,17539,
+1,21,49,17539,
+0,27,46,17539,
+0,6,53,17539,
+10,12,51,17539,
+6,28,45,17539,
+12,26,45,17539,
+24,30,37,17539,
+18,35,36,17539,
+10,21,48,17539,
+3,30,44,17539,
+1,6,53,17539,
+13,34,39,17539,
+18,29,41,17539,
+27,31,34,17572,
+7,14,51,17572,
+14,21,47,17572,
+6,31,43,17572,
+11,31,42,17572,
+1,27,46,17572,
+11,15,50,17572,
+3,34,41,17572,
+11,18,49,17572,
+21,31,38,17572,
+2,21,49,17572,
+17,21,46,17572,
+22,29,39,17572,
+14,25,45,17572,
+10,35,39,17572,
+12,20,48,17572,
+16,36,36,17572,
+0,12,52,17572,
+2,27,46,17572,
+18,34,37,17572,
+1,12,52,17572,
+8,24,47,17572,
+23,32,36,17572,
+8,9,52,17572,
+5,18,50,17572,
+6,37,38,17572,
+10,30,43,17572,
+2,6,53,17572,
+26,27,38,17572,
+16,17,48,17572,
+15,32,40,17572,
+12,32,41,17572,
+4,23,48,17572,
+18,26,43,17572,
+28,29,35,17606,
+17,31,40,17606,
+5,11,52,17606,
+5,35,40,17606,
+20,35,35,17606,
+17,25,44,17606,
+4,25,47,17606,
+16,35,37,17606,
+4,5,53,17606,
+25,25,40,17606,
+7,20,49,17606,
+9,13,51,17606,
+3,21,49,17606,
+9,33,41,17606,
+5,15,51,17606,
+15,15,49,17606,
+21,27,41,17606,
+20,34,36,17606,
+2,12,52,17606,
+8,22,48,17606,
+8,32,42,17606,
+4,30,44,17606,
+24,26,40,17606,
+15,18,48,17606,
+4,34,41,17606,
+0,33,42,17606,
+14,16,49,17606,
+8,17,50,17606,
+7,10,52,17606,
+6,36,39,17606,
+25,28,38,17606,
+3,27,46,17606,
+3,6,53,17606,
+1,33,42,17606,
+26,33,33,17638,
+27,30,35,17638,
+10,27,45,17638,
+19,27,42,17638,
+10,34,40,17638,
+16,22,46,17638,
+10,16,50,17638,
+26,32,34,17650,
+8,26,46,17650,
+16,34,38,17650,
+18,18,47,17650,
+2,33,42,17650,
+0,16,51,17650,
+3,12,52,17650,
+18,33,38,17650,
+16,24,45,17650,
+15,28,43,17650,
+5,23,48,17650,
+1,16,51,17650,
+13,33,40,17650,
+20,33,37,17650,
+23,27,40,17650,
+7,28,45,17650,
+0,7,53,17650,
+9,29,44,17650,
+4,21,49,17650,
+1,7,53,17650,
+11,37,37,17650,
+11,23,47,17650,
+5,25,47,17650,
+5,5,53,17650,
+13,29,43,17650,
+7,31,43,17650,
+13,17,49,17650,
+17,19,47,17650,
+23,31,37,17650,
+6,18,50,17650,
+14,30,42,17650,
+11,36,38,17650,
+6,35,40,17650,
+14,19,48,17650,
+16,29,42,17650,
+0,19,50,17650,
+2,16,51,17650,
+6,11,52,17650,
+4,6,53,17650,
+8,14,51,17650,
+13,24,46,17650,
+19,30,40,17650,
+21,22,44,17650,
+14,27,44,17650,
+4,27,46,17650,
+24,29,38,17658,
+14,36,37,17658,
+5,30,44,17658,
+21,30,39,17658,
+10,19,49,17658,
+2,7,53,17658,
+5,34,41,17658,
+11,25,46,17658,
+7,37,38,17658,
+3,33,42,17658,
+6,15,51,17658,
+1,19,50,17658,
+13,22,47,17658,
+26,31,35,17693,
+22,23,43,17693,
+4,12,52,17693,
+28,28,36,17701,
+12,28,44,17701,
+20,28,41,17701,
+13,14,50,17701,
+2,19,50,17701,
+22,34,35,17701,
+20,23,44,17701,
+16,20,47,17701,
+8,20,49,17701,
+14,35,38,17701,
+20,21,45,17701,
+3,16,51,17701,
+11,21,48,17701,
+9,9,52,17701,
+9,24,47,17701,
+7,36,39,17701,
+27,29,36,17726,
+21,24,43,17726,
+16,33,39,17726,
+0,29,45,17726,
+11,12,51,17726,
+11,35,39,17726,
+5,21,49,17726,
+1,29,45,17726,
+17,27,43,17726,
+15,31,41,17726,
+3,7,53,17726,
+22,28,40,17726,
+8,10,52,17726,
+20,32,38,17726,
+16,26,44,17726,
+9,22,48,17726,
+18,32,39,17726,
+9,32,42,17726,
+12,15,50,17726,
+22,33,36,17726,
+4,33,42,17726,
+23,24,42,17726,
+12,18,49,17726,
+6,23,48,17726,
+12,31,42,17726,
+25,33,34,17752,
+5,27,46,17752,
+9,17,50,17752,
+6,25,47,17752,
+11,30,43,17752,
+13,26,45,17752,
+5,6,53,17752,
+19,22,45,17752,
+3,19,50,17752,
+10,33,41,17752,
+17,30,41,17752,
+15,23,46,17752,
+2,29,45,17752,
+10,13,51,17752,
+18,28,42,17752,
+26,30,36,17771,
+6,30,44,17771,
+26,26,39,17771,
+7,18,50,17771,
+22,25,42,17771,
+6,34,41,17771,
+0,13,52,17771,
+14,34,39,17771,
+4,16,51,17771,
+0,8,53,17771,
+9,26,46,17771,
+0,32,43,17771,
+5,12,52,17771,
+13,20,48,17771,
+19,24,44,17771,
+8,28,45,17771,
+23,30,38,17771,
+20,25,43,17771,
+7,11,52,17771,
+4,7,53,17771,
+8,31,43,17771,
+7,35,40,17771,
+1,32,43,17771,
+25,32,35,17800,
+1,13,52,17800,
+1,8,53,17800,
+13,32,41,17800,
+15,25,45,17800,
+15,21,47,17800,
+25,27,39,17800,
+11,27,45,17800,
+3,29,45,17800,
+7,15,51,17800,
+4,19,50,17800,
+2,32,43,17800,
+11,34,40,17800,
+2,13,52,17800,
+19,20,46,17800,
+8,37,38,17800,
+22,32,37,17800,
+11,16,50,17800,
+2,8,53,17800,
+10,29,44,17800,
+5,33,42,17800,
+18,23,45,17800,
+6,21,49,17800,
+9,14,51,17800,
+16,32,40,17800,
+0,24,48,17800,
+6,27,46,17800,
+21,26,42,17800,
+18,21,46,17800,
+8,36,39,17800,
+17,36,36,17800,
+24,28,39,17813,
+1,24,48,17813,
+6,6,53,17813,
+12,23,47,17813,
+20,31,39,17813,
+27,28,37,17851,
+3,13,52,17851,
+19,35,36,17851,
+17,17,48,17851,
+21,29,40,17851,
+5,16,51,17851,
+25,31,36,17851,
+12,37,37,17851,
+3,32,43,17851,
+15,16,49,17851,
+24,25,41,17851,
+3,8,53,17851,
+9,20,49,17851,
+4,29,45,17851,
+7,23,48,17851,
+11,19,49,17851,
+7,25,47,17851,
+5,7,53,17851,
+17,35,37,17851,
+31,31,31,17890,
+19,29,41,17890,
+2,24,48,17890,
+12,36,38,17890,
+6,12,52,17890,
+16,18,48,17890,
+7,30,44,17890,
+10,24,47,17890,
+14,33,40,17890,
+30,31,32,17909,
+9,10,52,17909,
+12,25,46,17909,
+0,26,47,17909,
+0,22,49,17909,
+18,25,44,17909,
+18,31,40,17909,
+1,22,49,17909,
+7,34,41,17909,
+19,34,37,17909,
+5,19,50,17909,
+14,29,43,17909,
+19,26,43,17909,
+14,17,49,17909,
+23,26,41,17909,
+1,26,47,17909,
+26,29,37,17909,
+8,18,50,17909,
+0,38,38,17909,
+10,32,42,17909,
+10,22,48,17909,
+24,34,34,17909,
+14,24,46,17909,
+15,30,42,17909,
+12,12,51,17909,
+30,30,33,17933,
+17,34,38,17933,
+4,8,53,17933,
+6,33,42,17933,
+29,32,32,17933,
+8,11,52,17933,
+3,24,48,17933,
+17,22,46,17933,
+10,17,50,17933,
+8,35,40,17933,
+12,21,48,17933,
+22,31,38,17933,
+4,32,43,17933,
+2,26,47,17933,
+4,13,52,17933,
+13,28,44,17933,
+14,22,47,17933,
+1,38,38,17933,
+2,22,49,17933,
+16,28,43,17933,
+17,24,45,17933,
+15,19,48,17933,
+15,27,44,17933,
+12,35,39,17933,
+0,17,51,17933,
+24,33,35,17933,
+8,15,51,17933,
+0,9,53,17933,
+9,28,45,17933,
+15,36,37,17933,
+0,37,39,17933,
+9,31,43,17933,
+1,17,51,17933,
+23,29,39,17933,
+7,21,49,17933,
+29,31,33,17954,
+1,37,39,17954,
+21,35,35,17954,
+1,9,53,17954,
+5,29,45,17954,
+11,13,51,17954,
+11,33,41,17954,
+10,26,46,17954,
+2,38,38,17954,
+14,14,50,17954,
+20,27,42,17954,
+21,34,36,17954,
+12,30,43,17954,
+6,16,51,17954,
+13,18,49,17954,
+2,37,39,17954,
+2,17,51,17954,
+22,27,41,17954,
+13,31,42,17954,
+18,19,47,17954,
+3,22,49,17954,
+7,27,46,17954,
+13,15,50,17954,
+15,35,38,17954,
+17,29,42,17954,
+19,33,38,17954,
+6,7,53,17954,
+3,26,47,17954,
+2,9,53,17954,
+25,30,37,17954,
+9,37,38,17954,
+24,32,36,17959,
+0,36,40,17959,
+4,24,48,17959,
+29,30,34,18001,
+14,26,45,18001,
+6,19,50,18001,
+0,31,44,18001,
+1,36,40,18001,
+10,14,51,18001,
+28,32,33,18001,
+7,12,52,18001,
+3,38,38,18001,
+8,23,48,18001,
+11,29,44,18001,
+5,13,52,18001,
+12,27,45,18001,
+5,32,43,18001,
+1,31,44,18001,
+9,36,39,18001,
+5,8,53,18001,
+16,31,41,18001,
+17,20,47,18001,
+8,25,47,18001,
+3,17,51,18001,
+3,37,39,18001,
+21,33,37,18001,
+3,9,53,18001,
+17,33,39,18001,
+14,20,48,18001,
+0,20,50,18001,
+8,30,44,18001,
+20,30,40,18001,
+0,14,52,18001,
+12,34,40,18001,
+2,36,40,18001,
+0,28,46,18001,
+12,16,50,18001,
+4,26,47,18001,
+17,26,44,18001,
+10,20,49,18001,
+1,20,50,18001,
+1,28,46,18001,
+2,31,44,18001,
+4,22,49,18001,
+14,32,41,18001,
+16,23,46,18001,
+28,31,34,18041,
+25,26,40,18041,
+1,14,52,18041,
+8,34,41,18041,
+7,33,42,18041,
+27,27,38,18041,
+15,34,39,18041,
+6,29,45,18041,
+18,27,43,18041,
+2,20,50,18041,
+22,22,44,18041,
+26,28,38,18041,
+10,10,52,18041,
+4,38,38,18041,
+2,28,46,18041,
+2,14,52,18041,
+24,27,40,18041,
+18,30,41,18041,
+22,30,39,18041,
+3,36,40,18041,
+5,24,48,18041,
+9,18,50,18041,
+12,19,49,18041,
+4,17,51,18041,
+19,32,39,18041,
+16,25,45,18041,
+9,35,40,18041,
+4,37,39,18041,
+3,31,44,18041,
+9,11,52,18041,
+21,28,41,18041,
+0,35,41,18041,
+4,9,53,18041,
+8,21,49,18041,
+21,23,44,18041,
+24,31,37,18054,
+7,16,51,18054,
+11,24,47,18054,
+16,21,47,18054,
+29,29,35,18094,
+21,21,45,18094,
+1,35,41,18094,
+13,37,37,18094,
+13,23,47,18094,
+9,15,51,18094,
+7,7,53,18094,
+23,23,43,18094,
+27,33,33,18094,
+20,22,45,18094,
+8,27,46,18094,
+22,24,43,18094,
+11,22,48,18094,
+11,32,42,18094,
+28,30,35,18106,
+3,28,46,18106,
+21,32,38,18106,
+6,32,43,18106,
+13,36,38,18106,
+3,14,52,18106,
+19,28,42,18106,
+10,28,45,18106,
+27,32,34,18106,
+3,20,50,18106,
+6,8,53,18106,
+0,10,53,18106,
+6,13,52,18106,
+25,29,38,18106,
+1,10,53,18106,
+23,34,35,18106,
+7,19,50,18106,
+13,25,46,18106,
+11,17,50,18106,
+5,26,47,18106,
+5,22,49,18106,
+10,31,43,18106,
+2,35,41,18106,
+20,24,44,18106,
+4,36,40,18106,
+8,12,52,18106,
+23,28,40,18106,
+17,32,40,18106,
+10,37,38,18106,
+5,38,38,18106,
+4,31,44,18106,
+11,26,46,18106,
+2,10,53,18106,
+16,16,49,18106,
+13,21,48,18106,
+9,23,48,18106,
+15,33,40,18106,
+23,33,36,18118,
+12,13,51,18118,
+12,33,41,18118,
+3,35,41,18118,
+7,29,45,18118,
+21,25,43,18118,
+19,23,45,18118,
+9,25,47,18118,
+5,9,53,18118,
+13,35,39,18118,
+15,29,43,18118,
+15,17,49,18118,
+5,17,51,18118,
+27,31,35,18153,
+5,37,39,18153,
+20,20,46,18153,
+4,20,50,18153,
+0,0,54,18153,
+4,28,46,18153,
+4,14,52,18153,
+18,36,36,18153,
+24,24,42,18153,
+6,24,48,18153,
+14,28,44,18153,
+9,30,44,18153,
+15,24,46,18153,
+0,1,54,18153,
+17,18,48,18153,
+10,36,39,18153,
+8,33,42,18153,
+18,35,37,18153,
+11,14,51,18153,
+23,25,42,18153,
+9,34,41,18153,
+3,10,53,18153,
+19,21,46,18153,
+13,30,43,18153,
+1,1,54,18153,
+15,22,47,18153,
+0,34,42,18153,
+24,30,38,18161,
+0,2,54,18161,
+16,30,42,18161,
+16,27,44,18161,
+6,26,47,18161,
+16,36,37,18161,
+14,15,50,18161,
+1,34,42,18161,
+16,19,48,18161,
+20,35,36,18161,
+14,18,49,18161,
+28,29,36,18202,
+6,22,49,18202,
+26,33,34,18202,
+5,36,40,18202,
+1,2,54,18202,
+8,16,51,18202,
+14,31,42,18202,
+12,29,44,18202,
+17,28,43,18202,
+23,32,37,18202,
+5,31,44,18202,
+11,20,49,18202,
+19,31,40,18202,
+7,32,43,18202,
+20,29,41,18202,
+19,25,44,18202,
+7,8,53,18202,
+7,13,52,18202,
+4,35,41,18202,
+13,27,45,18202,
+9,21,49,18202,
+21,31,39,18202,
+18,22,46,18202,
+18,34,38,18202,
+22,26,42,18202,
+2,34,42,18202,
+10,18,50,18202,
+6,38,38,18202,
+2,2,54,18202,
+0,30,45,18202,
+5,28,46,18202,
+27,30,36,18235,
+10,35,40,18235,
+0,18,51,18235,
+22,29,40,18235,
+18,24,45,18235,
+16,35,38,18235,
+0,3,54,18235,
+13,16,50,18235,
+26,32,35,18235,
+13,34,40,18235,
+20,34,37,18235,
+4,10,53,18235,
+10,11,52,18235,
+8,19,50,18235,
+5,20,50,18235,
+5,14,52,18235,
+20,26,43,18235,
+1,30,45,18235,
+1,3,54,18235,
+6,17,51,18235,
+15,26,45,18235,
+6,9,53,18235,
+6,37,39,18235,
+10,15,51,18235,
+1,18,51,18235,
+26,27,39,18235,
+9,27,46,18235,
+15,20,48,18235,
+0,25,48,18235,
+9,12,52,18235,
+2,3,54,18235,
+3,34,42,18235,
+0,15,52,18235,
+2,30,45,18235,
+18,29,42,18235,
+12,24,47,18235,
+2,18,51,18235,
+7,24,48,18235,
+1,25,48,18235,
+25,28,39,18244,
+0,23,49,18244,
+11,28,45,18244,
+15,32,41,18244,
+0,11,53,18244,
+1,15,52,18244,
+8,29,45,18244,
+1,11,53,18244,
+17,31,41,18244,
+11,31,43,18244,
+13,19,49,18244,
+25,25,41,18244,
+19,19,47,18244,
+5,35,41,18244,
+1,23,49,18244,
+12,22,48,18244,
+12,32,42,18244,
+6,36,40,18244,
+0,4,54,18244,
+18,20,47,18244,
+24,26,41,18244,
+2,25,48,18244,
+12,17,50,18244,
+26,31,36,18297,
+1,4,54,18297,
+16,34,39,18297,
+2,15,52,18297,
+6,31,44,18297,
+20,33,38,18297,
+10,23,48,18297,
+14,23,47,18297,
+3,18,51,18297,
+10,25,47,18297,
+5,10,53,18297,
+3,30,45,18297,
+18,33,39,18297,
+17,23,46,18297,
+14,37,37,18297,
+21,27,42,18297,
+2,11,53,18297,
+2,23,49,18297,
+23,31,38,18297,
+22,35,35,18297,
+11,37,38,18297,
+9,33,42,18297,
+7,22,49,18297,
+3,3,54,18297,
+7,26,47,18297,
+10,30,44,18297,
+22,34,36,18297,
+14,36,38,18297,
+6,14,52,18297,
+6,20,50,18297,
+2,4,54,18297,
+18,26,44,18297,
+12,26,46,18297,
+6,28,46,18297,
+4,34,42,18297,
+10,34,41,18297,
+14,25,46,18297,
+28,28,37,18331,
+8,32,43,18331,
+8,8,53,18331,
+25,34,34,18331,
+7,38,38,18331,
+8,13,52,18331,
+3,25,48,18331,
+24,29,39,18331,
+3,15,52,18331,
+0,33,43,18331,
+11,36,39,18331,
+9,16,51,18331,
+0,27,47,18331,
+13,13,51,18331,
+3,11,53,18331,
+17,21,47,18331,
+19,27,43,18331,
+13,33,41,18331,
+17,25,45,18331,
+7,17,51,18331,
+3,23,49,18331,
+1,33,43,18331,
+27,29,37,18344,
+7,37,39,18344,
+7,9,53,18344,
+23,27,41,18344,
+25,33,35,18344,
+1,27,47,18344,
+0,21,50,18344,
+12,14,51,18344,
+3,4,54,18344,
+21,30,40,18344,
+0,5,54,18344,
+4,30,45,18344,
+14,21,48,18344,
+4,18,51,18344,
+6,35,41,18344,
+2,27,47,18344,
+10,21,49,18344,
+1,5,54,18344,
+22,33,37,18344,
+19,30,41,18344,
+14,35,39,18344,
+1,21,50,18344,
+9,19,50,18344,
+2,33,43,18344,
+8,24,48,18344,
+26,30,37,18384,
+2,21,50,18384,
+7,36,40,18384,
+2,5,54,18384,
+4,25,48,18384,
+20,32,39,18384,
+10,27,46,18384,
+25,32,36,18384,
+15,28,44,18384,
+6,10,53,18384,
+12,20,49,18384,
+11,18,50,18384,
+4,15,52,18384,
+16,33,40,18384,
+14,30,43,18384,
+5,34,42,18384,
+16,29,43,18384,
+11,35,40,18384,
+31,31,32,18432,
+4,11,53,18432,
+4,23,49,18432,
+11,11,52,18432,
+13,29,44,18432,
+16,17,49,18432,
+7,31,44,18432,
+3,33,43,18432,
+3,27,47,18432,
+11,15,51,18432,
+9,29,45,18432,
+18,32,40,18432,
+4,4,54,18432,
+10,12,52,18432,
+20,28,42,18432,
+30,32,32,18437,
+16,24,46,18437,
+7,14,52,18437,
+16,22,47,18437,
+7,20,50,18437,
+7,28,46,18437,
+8,26,47,18437,
+22,23,44,18437,
+8,22,49,18437,
+22,28,41,18437,
+5,30,45,18437,
+21,22,45,18437,
+30,31,33,18456,
+15,15,50,18456,
+14,27,45,18456,
+23,30,39,18456,
+5,18,51,18456,
+15,18,49,18456,
+3,5,54,18456,
+15,31,42,18456,
+3,21,50,18456,
+22,32,38,18456,
+14,34,40,18456,
+26,26,40,18456,
+8,38,38,18456,
+18,18,48,18456,
+0,6,54,18456,
+14,16,50,18456,
+12,28,45,18456,
+10,33,42,18456,
+0,12,53,18456,
+17,30,42,18456,
+1,6,54,18456,
+21,24,44,18456,
+19,36,36,18456,
+8,37,39,18456,
+5,25,48,18456,
+11,23,48,18456,
+23,24,43,18456,
+5,15,52,18456,
+8,9,53,18456,
+9,13,52,18456,
+4,27,47,18456,
+29,32,33,18499,
+9,32,43,18499,
+20,23,45,18499,
+13,24,47,18499,
+8,17,51,18499,
+25,27,40,18499,
+17,27,44,18499,
+4,33,43,18499,
+12,31,43,18499,
+1,12,53,18499,
+17,36,37,18499,
+17,19,48,18499,
+25,31,37,18499,
+11,25,47,18499,
+19,35,37,18499,
+7,35,41,18499,
+5,11,53,18499,
+5,23,49,18499,
+6,34,42,18499,
+30,30,34,18505,
+2,6,54,18505,
+4,5,54,18505,
+13,22,48,18505,
+18,28,43,18505,
+12,37,38,18505,
+11,30,44,18505,
+4,21,50,18505,
+20,21,46,18505,
+13,32,42,18505,
+27,28,38,18505,
+0,29,46,18505,
+24,34,35,18505,
+16,26,45,18505,
+2,12,53,18505,
+10,16,51,18505,
+17,35,38,18505,
+11,34,41,18505,
+14,19,49,18505,
+13,17,50,18505,
+29,31,34,18525,
+1,29,46,18525,
+22,25,43,18525,
+7,10,53,18525,
+0,16,52,18525,
+16,20,48,18525,
+24,28,40,18525,
+0,32,44,18525,
+8,36,40,18525,
+24,33,36,18525,
+10,19,50,18525,
+26,29,38,18525,
+1,16,52,18525,
+16,32,41,18525,
+20,25,44,18525,
+19,22,46,18525,
+19,34,38,18525,
+9,24,48,18525,
+3,6,54,18525,
+13,26,46,18525,
+12,36,39,18525,
+1,32,44,18525,
+20,31,40,18525,
+6,30,45,18525,
+8,31,44,18525,
+2,29,46,18525,
+6,18,51,18525,
+0,19,51,18525,
+21,35,36,18525,
+19,24,45,18525,
+3,12,53,18525,
+28,33,33,18561,
+21,29,41,18561,
+11,21,49,18561,
+15,37,37,18561,
+15,23,47,18561,
+1,19,51,18561,
+5,33,43,18561,
+5,27,47,18561,
+2,16,52,18561,
+8,14,52,18561,
+2,32,44,18561,
+8,20,50,18561,
+8,28,46,18561,
+28,32,34,18565,
+6,15,52,18565,
+0,7,54,18565,
+6,25,48,18565,
+15,36,38,18565,
+24,25,42,18565,
+0,38,39,18565,
+19,29,42,18565,
+2,19,51,18565,
+5,21,50,18565,
+18,31,41,18565,
+1,38,39,18565,
+9,22,49,18565,
+3,29,46,18565,
+29,30,35,18587,
+9,26,47,18587,
+1,7,54,18587,
+21,34,37,18587,
+10,29,45,18587,
+17,34,39,18587,
+6,11,53,18587,
+11,27,46,18587,
+6,23,49,18587,
+15,25,46,18587,
+21,26,43,18587,
+13,14,51,18587,
+14,33,41,18587,
+22,31,39,18587,
+5,5,54,18587,
+4,6,54,18587,
+12,18,50,18587,
+9,38,38,18587,
+4,12,53,18587,
+24,32,37,18587,
+0,37,40,18587,
+3,16,52,18587,
+25,30,38,18587,
+2,7,54,18587,
+23,26,42,18587,
+7,34,42,18587,
+11,12,52,18587,
+3,32,44,18587,
+2,38,39,18587,
+12,35,40,18587,
+18,23,46,18587,
+8,35,41,18587,
+12,15,51,18587,
+28,31,35,18612,
+13,20,49,18612,
+19,20,47,18612,
+15,21,48,18612,
+23,29,40,18612,
+1,37,40,18612,
+9,9,53,18612,
+9,37,39,18612,
+3,19,51,18612,
+15,35,39,18612,
+9,17,51,18612,
+19,33,39,18612,
+10,32,43,18612,
+10,13,52,18612,
+19,26,44,18612,
+8,10,53,18612,
+14,29,44,18612,
+4,29,46,18612,
+2,37,40,18612,
+21,33,38,18612,
+7,18,51,18612,
+3,7,54,18612,
+11,33,42,18612,
+3,38,39,18612,
+6,33,43,18612,
+18,21,47,18612,
+18,25,45,18612,
+27,33,34,18633,
+7,30,45,18633,
+15,30,43,18633,
+6,27,47,18633,
+16,28,44,18633,
+4,32,44,18633,
+4,16,52,18633,
+22,27,42,18633,
+5,6,54,18633,
+0,24,49,18633,
+0,36,41,18633,
+6,21,50,18633,
+12,23,48,18633,
+9,36,40,18633,
+27,32,35,18692,
+17,33,40,18692,
+5,12,53,18692,
+9,31,44,18692,
+11,16,51,18692,
+1,24,49,18692,
+0,13,53,18692,
+1,36,41,18692,
+4,19,51,18692,
+29,29,36,18692,
+13,28,45,18692,
+20,27,43,18692,
+12,25,47,18692,
+3,37,40,18692,
+7,15,52,18692,
+7,25,48,18692,
+13,31,43,18692,
+7,23,49,18692,
+1,13,53,18692,
+17,29,43,18692,
+15,27,45,18692,
+7,11,53,18692,
+17,17,49,18692,
+27,27,39,18692,
+23,35,35,18692,
+0,26,48,18692,
+0,8,54,18692,
+28,30,36,18699,
+12,30,44,18699,
+10,24,48,18699,
+20,30,41,18699,
+9,14,52,18699,
+14,24,47,18699,
+2,36,41,18699,
+23,34,36,18699,
+9,28,46,18699,
+1,8,54,18699,
+15,34,40,18699,
+17,24,46,18699,
+26,28,39,18699,
+9,20,50,18699,
+1,26,48,18699,
+24,31,38,18699,
+4,7,54,18699,
+16,18,49,18699,
+12,34,41,18699,
+16,31,42,18699,
+2,24,49,18699,
+4,38,39,18699,
+15,16,50,18699,
+5,29,46,18699,
+2,13,53,18699,
+25,26,41,18699,
+17,22,47,18699,
+13,37,38,18699,
+11,19,50,18699,
+2,26,48,18699,
+2,8,54,18699,
+14,22,48,18699,
+0,22,50,18699,
+22,30,40,18699,
+14,32,42,18699,
+8,34,42,18699,
+14,17,50,18699,
+5,32,44,18699,
+4,37,40,18699,
+19,32,40,18699,
+1,22,50,18699,
+5,16,52,18699,
+10,22,49,18699,
+10,26,47,18699,
+0,31,45,18699,
+3,36,41,18699,
+27,31,36,18757,
+12,21,49,18757,
+24,27,41,18757,
+21,32,39,18757,
+3,24,49,18757,
+13,36,39,18757,
+23,33,37,18757,
+7,33,43,18757,
+25,29,39,18757,
+15,19,49,18757,
+11,29,45,18757,
+3,13,53,18757,
+7,27,47,18757,
+5,19,51,18757,
+1,31,45,18757,
+9,35,41,18757,
+14,26,46,18757,
+6,6,54,18757,
+18,30,42,18757,
+26,34,34,18759,
+10,38,38,18759,
+2,22,50,18759,
+18,36,37,18759,
+3,26,48,18759,
+12,27,46,18759,
+0,35,42,18759,
+21,28,42,18759,
+18,27,44,18759,
+3,8,54,18759,
+8,30,45,18759,
+6,12,53,18759,
+8,18,51,18759,
+18,19,48,18759,
+5,7,54,18759,
+7,21,50,18759,
+2,31,45,18759,
+17,26,45,18759,
+26,33,35,18784,
+10,17,51,18784,
+1,35,42,18784,
+9,10,53,18784,
+10,37,39,18784,
+5,38,39,18784,
+12,12,52,18784,
+20,36,36,18784,
+8,15,52,18784,
+2,35,42,18784,
+22,22,45,18784,
+14,14,51,18784,
+0,28,47,18784,
+8,25,48,18784,
+17,20,48,18784,
+4,36,41,18784,
+6,29,46,18784,
+3,22,50,18784,
+4,24,49,18784,
+18,35,38,18784,
+0,17,52,18784,
+13,18,50,18784,
+19,28,43,18784,
+1,17,52,18784,
+5,37,40,18784,
+28,29,37,18821,
+17,32,41,18821,
+8,11,53,18821,
+11,32,43,18821,
+4,13,53,18821,
+1,28,47,18821,
+11,13,52,18821,
+16,37,37,18821,
+16,23,47,18821,
+13,35,40,18821,
+23,28,41,18821,
+8,23,49,18821,
+20,35,37,18821,
+23,23,44,18821,
+15,33,41,18821,
+13,15,51,18821,
+21,23,45,18821,
+3,31,45,18821,
+16,36,38,18821,
+6,16,52,18821,
+26,32,36,18831,
+4,26,48,18831,
+6,32,44,18831,
+10,36,40,18831,
+4,8,54,18831,
+22,24,44,18831,
+23,32,38,18831,
+24,30,39,18831,
+12,33,42,18831,
+0,9,54,18831,
+10,31,44,18831,
+14,20,49,18831,
+16,25,46,18831,
+2,28,47,18831,
+2,17,52,18831,
+6,19,51,18831,
+3,35,42,18831,
+27,30,37,18855,
+21,21,46,18855,
+1,9,54,18855,
+4,22,50,18855,
+10,28,46,18855,
+10,14,52,18855,
+10,20,50,18855,
+20,34,38,18855,
+20,22,46,18855,
+2,9,54,18855,
+12,16,51,18855,
+16,21,48,18855,
+6,7,54,18855,
+9,34,42,18855,
+6,38,39,18855,
+18,34,39,18855,
+11,24,48,18855,
+24,24,43,18855,
+20,24,45,18855,
+0,20,51,18855,
+21,25,44,18855,
+13,23,48,18855,
+3,28,47,18855,
+3,17,52,18855,
+5,24,49,18855,
+1,20,51,18855,
+4,31,45,18855,
+5,36,41,18855,
+7,12,53,18855,
+8,27,47,18855,
+21,31,40,18855,
+16,35,39,18855,
+8,33,43,18855,
+15,29,44,18855,
+19,31,41,18855,
+13,25,47,18855,
+5,13,53,18855,
+23,25,43,18855,
+12,19,50,18855,
+2,20,51,18855,
+6,37,40,18855,
+8,21,50,18855,
+5,8,54,18855,
+16,30,43,18855,
+13,30,44,18855,
+0,14,53,18855,
+5,26,48,18855,
+20,29,42,18855,
+0,34,43,18855,
+26,27,40,18875,
+22,35,36,18875,
+14,28,45,18875,
+4,35,42,18875,
+9,30,45,18875,
+26,31,37,18912,
+3,9,54,18912,
+7,29,46,18912,
+1,14,53,18912,
+25,34,35,18912,
+9,18,51,18912,
+13,34,41,18912,
+14,31,43,18912,
+1,34,43,18912,
+10,35,41,18912,
+19,23,46,18912,
+11,26,47,18912,
+22,29,41,18912,
+11,22,49,18912,
+22,34,37,18912,
+7,32,44,18912,
+2,14,53,18912,
+4,28,47,18912,
+22,26,43,18912,
+10,10,53,18912,
+17,28,44,18912,
+25,28,40,18912,
+20,20,47,18912,
+4,17,52,18912,
+7,16,52,18912,
+5,22,50,18912,
+31,32,32,18981,
+14,37,38,18981,
+2,34,43,18981,
+11,38,38,18981,
+9,15,52,18981,
+20,33,39,18981,
+3,20,51,18981,
+16,27,45,18981,
+15,24,47,18981,
+25,33,36,18981,
+9,25,48,18981,
+12,29,45,18981,
+11,17,51,18981,
+13,21,49,18981,
+23,31,39,18981,
+31,31,33,18999,
+7,19,51,18999,
+5,31,45,18999,
+19,21,47,18999,
+19,25,45,18999,
+11,37,39,18999,
+9,11,53,18999,
+9,23,49,18999,
+16,16,50,18999,
+20,26,44,18999,
+16,34,40,18999,
+28,28,38,18999,
+6,36,41,18999,
+6,24,49,18999,
+18,33,40,18999,
+14,36,39,18999,
+30,32,33,19016,
+15,22,48,19016,
+15,32,42,19016,
+4,9,54,19016,
+7,7,54,19016,
+3,34,43,19016,
+25,25,42,19016,
+3,14,53,19016,
+27,29,38,19016,
+13,27,46,19016,
+7,38,39,19016,
+17,18,49,19016,
+18,29,43,19016,
+6,13,53,19016,
+17,31,42,19016,
+15,17,50,19016,
+5,35,42,19016,
+24,26,42,19016,
+6,26,48,19016,
+0,10,54,19016,
+18,24,46,19016,
+6,8,54,19016,
+0,30,46,19016,
+8,12,53,19016,
+1,10,54,19016,
+12,32,43,19016,
+24,29,40,19016,
+4,20,51,19016,
+18,22,47,19016,
+11,36,40,19016,
+30,31,34,19037,
+15,26,46,19037,
+12,13,52,19037,
+1,30,46,19037,
+22,33,38,19037,
+5,28,47,19037,
+11,31,44,19037,
+7,37,40,19037,
+25,32,37,19037,
+16,19,49,19037,
+5,17,52,19037,
+9,27,47,19037,
+9,33,43,19037,
+21,27,43,19037,
+29,33,33,19056,
+2,10,54,19056,
+2,30,46,19056,
+6,22,50,19056,
+10,34,42,19056,
+26,30,38,19056,
+14,18,50,19056,
+11,14,52,19056,
+29,32,34,19070,
+11,28,46,19070,
+4,14,53,19070,
+8,29,46,19070,
+14,35,40,19070,
+4,34,43,19070,
+11,20,50,19070,
+6,31,45,19070,
+9,21,50,19070,
+5,9,54,19070,
+21,30,41,19070,
+14,15,51,19070,
+23,27,42,19070,
+13,33,42,19070,
+20,32,40,19070,
+12,24,48,19070,
+8,32,44,19070,
+8,16,52,19070,
+6,35,42,19070,
+3,10,54,19070,
+19,30,42,19070,
+10,30,45,19070,
+3,30,46,19070,
+30,30,35,19101,
+10,18,51,19101,
+0,0,55,19101,
+18,26,45,19101,
+0,33,44,19101,
+16,33,41,19101,
+19,19,48,19101,
+0,1,55,19101,
+0,25,49,19101,
+7,24,49,19101,
+24,35,35,19101,
+7,36,41,19101,
+19,36,37,19101,
+15,20,49,19101,
+5,20,51,19101,
+8,19,51,19101,
+19,27,44,19101,
+1,33,44,19101,
+13,16,51,19101,
+1,1,55,19101,
+1,25,49,19101,
+7,13,53,19101,
+17,37,37,19101,
+11,35,41,19101,
+29,31,35,19121,
+17,23,47,19121,
+18,20,48,19121,
+0,18,52,19121,
+24,34,36,19121,
+2,33,44,19121,
+12,22,49,19121,
+22,32,39,19121,
+14,23,48,19121,
+0,23,50,19121,
+6,28,47,19121,
+12,26,47,19121,
+17,36,38,19121,
+1,18,52,19121,
+7,26,48,19121,
+23,30,40,19121,
+0,2,55,19121,
+18,32,41,19121,
+6,17,52,19121,
+8,38,39,19121,
+28,33,34,19132,
+10,25,48,19132,
+7,8,54,19132,
+10,15,52,19132,
+1,2,55,19132,
+17,25,46,19132,
+1,23,50,19132,
+10,11,53,19132,
+13,19,50,19132,
+2,25,49,19132,
+19,35,38,19132,
+14,25,47,19132,
+5,34,43,19132,
+25,31,38,19132,
+10,23,49,19132,
+5,14,53,19132,
+4,10,54,19132,
+22,28,42,19132,
+4,30,46,19132,
+12,38,38,19132,
+2,18,52,19132,
+14,30,44,19132,
+2,2,55,19132,
+8,37,40,19132,
+28,32,35,19163,
+20,28,43,19163,
+16,29,44,19163,
+14,34,41,19163,
+26,26,41,19163,
+6,9,54,19163,
+7,22,50,19163,
+0,27,48,19163,
+2,23,50,19163,
+21,36,36,19163,
+12,37,39,19163,
+17,21,48,19163,
+1,27,48,19163,
+12,17,51,19163,
+24,33,37,19163,
+3,33,44,19163,
+0,15,53,19163,
+0,3,55,19163,
+9,12,53,19163,
+27,28,39,19163,
+15,28,45,19163,
+3,25,49,19163,
+17,35,39,19163,
+7,31,45,19163,
+15,31,43,19163,
+25,27,41,19163,
+1,15,53,19163,
+13,29,45,19163,
+1,3,55,19163,
+21,35,37,19163,
+3,18,52,19163,
+2,27,48,19163,
+0,11,54,19163,
+29,30,36,19208,
+6,20,51,19208,
+10,33,43,19208,
+1,11,54,19208,
+19,34,39,19208,
+3,23,50,19208,
+14,21,49,19208,
+26,29,39,19208,
+2,15,53,19208,
+9,29,46,19208,
+22,23,45,19208,
+2,3,55,19208,
+15,37,38,19208,
+7,35,42,19208,
+17,30,43,19208,
+10,27,47,19208,
+12,36,40,19208,
+9,32,44,19208,
+5,30,46,19208,
+21,22,46,19208,
+9,16,52,19208,
+23,24,44,19208,
+8,24,49,19208,
+28,31,36,19227,
+12,31,44,19227,
+5,10,54,19227,
+8,36,41,19227,
+16,24,47,19227,
+6,14,53,19227,
+4,33,44,19227,
+10,21,50,19227,
+21,34,38,19227,
+27,34,34,19227,
+6,34,43,19227,
+24,28,41,19227,
+14,27,46,19227,
+11,34,42,19227,
+2,11,54,19227,
+0,4,55,19227,
+13,13,52,19227,
+0,21,51,19227,
+15,36,39,19227,
+7,17,52,19227,
+13,32,43,19227,
+1,4,55,19227,
+0,39,39,19227,
+4,25,49,19227,
+21,24,45,19227,
+3,27,48,19227,
+7,28,47,19227,
+20,31,41,19227,
+8,13,53,19227,
+3,3,55,19227,
+1,39,39,19227,
+17,27,45,19227,
+3,15,53,19227,
+27,33,35,19254,
+9,19,51,19254,
+1,21,51,19254,
+12,28,46,19254,
+12,20,50,19254,
+24,32,38,19254,
+4,18,52,19254,
+16,22,48,19254,
+16,32,42,19254,
+12,14,52,19254,
+8,26,48,19254,
+0,38,40,19254,
+8,8,54,19254,
+18,28,44,19254,
+20,23,46,19254,
+22,25,44,19254,
+4,23,50,19254,
+17,34,40,19254,
+22,31,40,19254,
+1,38,40,19254,
+2,4,55,19254,
+16,17,50,19254,
+11,18,51,19254,
+21,29,42,19254,
+3,11,54,19254,
+25,30,39,19254,
+7,9,54,19254,
+2,21,51,19254,
+2,39,39,19254,
+11,30,45,19254,
+9,38,39,19254,
+16,26,46,19254,
+2,38,40,19254,
+8,22,50,19254,
+27,32,36,19286,
+4,27,48,19286,
+14,33,42,19286,
+13,24,48,19286,
+15,18,50,19286,
+0,32,45,19286,
+18,31,42,19286,
+18,18,49,19286,
+23,35,36,19286,
+5,33,44,19286,
+20,25,45,19286,
+20,21,47,19286,
+3,4,55,19286,
+4,15,53,19286,
+24,25,43,19286,
+1,32,45,19286,
+11,25,48,19286,
+19,33,40,19286,
+0,29,47,19286,
+0,5,55,19286,
+0,37,41,19286,
+8,31,45,19286,
+11,15,52,19286,
+15,35,40,19286,
+7,20,51,19286,
+12,35,41,19286,
+9,37,40,19286,
+3,39,39,19286,
+1,37,41,19286,
+5,25,49,19286,
+11,11,53,19286,
+23,29,41,19286,
+1,29,47,19286,
+1,5,55,19286,
+29,29,37,19306,
+11,23,49,19306,
+21,33,39,19306,
+17,19,49,19306,
+15,15,51,19306,
+19,29,43,19306,
+3,21,51,19306,
+6,10,54,19306,
+6,30,46,19306,
+28,30,37,19320,
+3,38,40,19320,
+10,12,53,19320,
+5,18,52,19320,
+14,16,51,19320,
+8,35,42,19320,
+19,24,46,19320,
+21,26,44,19320,
+2,32,45,19320,
+4,11,54,19320,
+2,5,55,19320,
+13,22,49,19320,
+5,23,50,19320,
+23,34,37,19320,
+7,34,43,19320,
+23,26,43,19320,
+13,26,47,19320,
+7,14,53,19320,
+19,22,47,19320,
+2,29,47,19320,
+2,37,41,19320,
+13,38,38,19320,
+26,34,35,19363,
+16,20,49,19363,
+4,4,55,19363,
+14,19,50,19363,
+8,17,52,19363,
+10,29,46,19363,
+8,28,47,19363,
+4,39,39,19363,
+27,27,40,19363,
+15,23,48,19363,
+24,31,39,19363,
+4,21,51,19363,
+9,24,49,19363,
+3,32,45,19363,
+9,36,41,19363,
+5,27,48,19363,
+3,29,47,19363,
+17,33,41,19363,
+11,33,43,19363,
+27,31,37,19383,
+3,37,41,19383,
+15,25,47,19383,
+9,13,53,19383,
+5,15,53,19383,
+11,27,47,19383,
+3,5,55,19383,
+13,17,51,19383,
+13,37,39,19383,
+4,38,40,19383,
+26,28,40,19383,
+10,16,52,19383,
+0,36,42,19383,
+0,12,54,19383,
+10,32,44,19383,
+1,36,42,19383,
+1,12,54,19383,
+15,30,44,19383,
+8,9,54,19383,
+6,33,44,19383,
+9,26,48,19383,
+26,33,36,19391,
+0,6,55,19391,
+11,21,50,19391,
+1,6,55,19391,
+15,34,41,19391,
+5,11,54,19391,
+18,23,47,19391,
+18,37,37,19391,
+14,29,45,19391,
+22,27,43,19391,
+23,33,38,19391,
+10,19,51,19391,
+19,26,45,19391,
+6,25,49,19391,
+6,18,52,19391,
+2,12,54,19391,
+18,36,38,19391,
+12,34,42,19391,
+2,36,42,19391,
+20,30,42,19391,
+21,32,40,19391,
+25,26,42,19391,
+2,6,55,19391,
+0,16,53,19391,
+10,38,39,19391,
+22,30,41,19391,
+19,20,48,19391,
+18,25,46,19391,
+9,22,50,19391,
+0,19,52,19391,
+20,36,37,19391,
+13,36,40,19391,
+6,23,50,19391,
+8,20,51,19391,
+16,28,45,19391,
+7,30,46,19391,
+20,27,44,19391,
+4,32,45,19391,
+7,10,54,19391,
+4,37,41,19391,
+25,29,40,19402,
+1,19,52,19402,
+4,29,47,19402,
+4,5,55,19402,
+17,29,44,19402,
+16,31,43,19402,
+19,32,41,19402,
+1,16,53,19402,
+13,31,44,19402,
+5,21,51,19402,
+5,39,39,19402,
+15,21,49,19402,
+9,31,45,19402,
+13,28,46,19402,
+6,27,48,19402,
+8,34,43,19402,
+3,12,54,19402,
+24,27,42,19402,
+26,32,37,19459,
+12,30,45,19459,
+8,14,53,19459,
+12,18,51,19459,
+3,36,42,19459,
+28,29,38,19459,
+10,37,40,19459,
+14,32,43,19459,
+20,35,38,19459,
+13,20,50,19459,
+13,14,52,19459,
+5,38,40,19459,
+18,21,48,19459,
+2,19,52,19459,
+2,16,53,19459,
+16,37,38,19459,
+9,35,42,19459,
+6,15,53,19459,
+3,6,55,19459,
+15,27,46,19459,
+18,35,39,19459,
+32,32,32,19512,
+12,15,52,19512,
+12,25,48,19512,
+6,11,54,19512,
+18,30,43,19512,
+16,36,39,19512,
+27,30,38,19512,
+21,28,43,19512,
+3,16,53,19512,
+12,23,49,19512,
+0,7,55,19512,
+23,32,39,19512,
+17,24,47,19512,
+9,17,52,19512,
+3,19,52,19512,
+5,32,45,19512,
+9,28,47,19512,
+31,32,33,19539,
+11,12,53,19539,
+7,33,44,19539,
+0,35,43,19539,
+7,25,49,19539,
+1,7,55,19539,
+25,35,35,19539,
+1,35,43,19539,
+13,35,41,19539,
+5,37,41,19539,
+5,29,47,19539,
+5,5,55,19539,
+0,24,50,19539,
+4,36,42,19539,
+24,30,40,19539,
+14,24,48,19539,
+4,12,54,19539,
+22,36,36,19539,
+20,34,39,19539,
+1,24,50,19539,
+0,31,46,19539,
+17,22,48,19539,
+10,36,41,19539,
+25,34,36,19539,
+4,6,55,19539,
+7,18,52,19539,
+23,28,42,19539,
+17,32,42,19539,
+0,26,49,19539,
+10,24,49,19539,
+15,33,42,19539,
+6,39,39,19539,
+17,17,50,19539,
+7,23,50,19539,
+22,35,37,19539,
+18,27,45,19539,
+6,21,51,19539,
+30,33,33,19568,
+1,31,46,19568,
+31,31,34,19568,
+10,13,53,19568,
+11,29,46,19568,
+9,9,54,19568,
+2,7,55,19568,
+2,35,43,19568,
+1,26,49,19568,
+2,24,50,19568,
+10,26,48,19568,
+30,32,34,19584,
+6,38,40,19584,
+18,34,40,19584,
+8,10,54,19584,
+8,30,46,19584,
+16,18,50,19584,
+4,19,52,19584,
+19,28,44,19584,
+11,32,44,19584,
+2,31,46,19584,
+26,31,38,19584,
+17,26,46,19584,
+14,22,49,19584,
+11,16,52,19584,
+16,35,40,19584,
+2,26,49,19584,
+4,16,53,19584,
+14,26,47,19584,
+7,27,48,19584,
+12,33,43,19584,
+15,16,51,19584,
+9,20,51,19584,
+12,27,47,19584,
+21,31,41,19584,
+3,35,43,19584,
+25,33,37,19584,
+7,15,53,19584,
+23,23,45,19584,
+3,7,55,19584,
+11,19,51,19584,
+10,22,50,19584,
+22,34,38,19584,
+14,38,38,19584,
+22,22,46,19584,
+12,21,50,19584,
+5,36,42,19584,
+6,32,45,19584,
+22,24,45,19584,
+0,22,51,19584,
+3,24,50,19584,
+0,13,54,19584,
+5,12,54,19584,
+1,13,54,19584,
+29,33,34,19623,
+26,27,41,19623,
+9,14,53,19623,
+30,31,35,19623,
+5,6,55,19623,
+6,37,41,19623,
+7,11,54,19623,
+10,31,45,19623,
+1,22,51,19623,
+19,31,42,19623,
+14,17,51,19623,
+6,29,47,19623,
+21,23,46,19623,
+9,34,43,19623,
+18,19,49,19623,
+15,19,50,19623,
+3,26,49,19623,
+11,38,39,19623,
+14,37,39,19623,
+3,31,46,19623,
+0,28,48,19623,
+24,24,44,19623,
+0,8,55,19623,
+10,35,42,19623,
+2,22,51,19623,
+8,33,44,19623,
+2,13,54,19623,
+22,29,42,19623,
+16,23,48,19623,
+28,28,39,19623,
+20,33,40,19623,
+1,28,48,19623,
+13,34,42,19623,
+23,31,40,19623,
+11,37,40,19623,
+20,29,43,19623,
+5,16,53,19623,
+17,20,49,19623,
+5,19,52,19623,
+23,25,44,19623,
+8,25,49,19623,
+4,7,55,19623,
+4,35,43,19623,
+1,8,55,19623,
+25,28,41,19623,
+16,25,47,19623,
+29,32,35,19666,
+27,29,39,19666,
+7,21,51,19666,
+7,39,39,19666,
+21,25,45,19666,
+21,21,47,19666,
+15,29,45,19666,
+16,30,44,19666,
+4,24,50,19666,
+20,24,46,19666,
+2,28,48,19666,
+14,36,40,19666,
+0,34,44,19666,
+8,18,52,19666,
+4,31,46,19666,
+10,17,52,19666,
+4,26,49,19666,
+25,32,38,19666,
+16,34,41,19666,
+2,8,55,19666,
+7,38,40,19666,
+10,28,47,19666,
+14,31,44,19666,
+20,22,47,19666,
+1,34,44,19666,
+8,23,50,19666,
+3,22,51,19666,
+13,30,45,19666,
+18,33,41,19666,
+13,18,51,19666,
+3,13,54,19666,
+22,33,39,19666,
+28,34,34,19712,
+14,14,52,19712,
+30,30,36,19712,
+6,12,54,19712,
+14,28,46,19712,
+6,36,42,19712,
+2,34,44,19712,
+14,20,50,19712,
+22,26,44,19712,
+8,27,48,19712,
+3,28,48,19712,
+9,30,46,19712,
+9,10,54,19712,
+6,6,55,19712,
+24,35,36,19712,
+12,12,53,19712,
+26,30,39,19712,
+11,24,49,19712,
+13,25,48,19712,
+8,15,53,19712,
+17,28,45,19712,
+7,32,45,19712,
+16,21,49,19712,
+0,17,53,19712,
+28,33,35,19740,
+29,31,36,19740,
+15,32,43,19740,
+11,36,41,19740,
+3,8,55,19740,
+13,15,52,19740,
+24,29,41,19740,
+1,17,53,19740,
+7,29,47,19740,
+13,23,49,19740,
+11,13,53,19740,
+5,7,55,19740,
+17,31,43,19740,
+25,25,43,19740,
+19,23,47,19740,
+5,35,43,19740,
+19,37,37,19740,
+7,37,41,19740,
+6,19,52,19740,
+4,13,54,19740,
+19,36,38,19740,
+11,26,48,19740,
+10,20,51,19740,
+8,11,54,19740,
+24,26,43,19740,
+5,24,50,19740,
+24,34,37,19740,
+20,26,45,19740,
+6,16,53,19740,
+12,29,46,19740,
+18,29,44,19740,
+3,34,44,19740,
+4,22,51,19740,
+16,27,46,19740,
+14,35,41,19740,
+2,17,53,19740,
+17,37,38,19740,
+19,25,46,19740,
+5,26,49,19740,
+5,31,46,19740,
+4,28,48,19740,
+12,32,44,19740,
+0,20,52,19740,
+12,16,52,19740,
+20,20,48,19740,
+28,32,36,19776,
+15,24,48,19776,
+11,22,50,19776,
+1,20,52,19776,
+10,14,53,19776,
+20,32,41,19776,
+10,34,43,19776,
+4,8,55,19776,
+21,30,42,19776,
+8,21,51,19776,
+0,9,55,19776,
+17,36,39,19776,
+8,39,39,19776,
+21,27,44,19776,
+21,36,37,19776,
+12,19,51,19776,
+9,33,44,19776,
+19,21,48,19776,
+19,35,39,19776,
+1,9,55,19776,
+25,31,39,19776,
+13,27,47,19776,
+11,31,45,19776,
+9,25,49,19776,
+13,33,43,19776,
+23,27,43,19776,
+3,17,53,19776,
+4,34,44,19776,
+22,32,40,19776,
+8,38,40,19776,
+2,20,52,19776,
+12,38,39,19776,
+7,36,42,19776,
+24,33,38,19793,
+16,33,42,19793,
+0,30,47,19793,
+9,18,52,19793,
+18,24,47,19793,
+7,12,54,19793,
+6,35,43,19793,
+15,22,49,19793,
+1,30,47,19793,
+13,21,50,19793,
+5,22,51,19793,
+9,23,50,19793,
+5,13,54,19793,
+6,7,55,19793,
+27,34,35,19836,
+15,26,47,19836,
+23,30,41,19836,
+21,35,38,19836,
+2,9,55,19836,
+19,30,43,19836,
+29,30,37,19836,
+11,35,42,19836,
+0,14,54,19836,
+6,24,50,19836,
+18,32,42,19836,
+18,22,48,19836,
+5,28,48,19836,
+1,14,54,19836,
+3,20,52,19836,
+6,26,49,19836,
+16,16,51,19836,
+12,37,40,19836,
+6,31,46,19836,
+17,18,50,19836,
+15,38,38,19836,
+2,30,47,19836,
+8,32,45,19836,
+27,28,40,19836,
+9,27,48,19836,
+0,33,45,19836,
+4,17,53,19836,
+7,16,53,19836,
+11,17,52,19836,
+5,8,55,19836,
+28,31,37,19876,
+27,33,36,19876,
+8,37,41,19876,
+17,35,40,19876,
+11,28,47,19876,
+8,29,47,19876,
+7,19,52,19876,
+15,37,39,19876,
+3,9,55,19876,
+19,27,45,19876,
+15,17,51,19876,
+9,15,53,19876,
+1,33,45,19876,
+10,10,54,19876,
+18,26,46,19876,
+26,26,42,19876,
+10,30,46,19876,
+14,34,42,19876,
+2,14,54,19876,
+16,19,50,19876,
+22,28,43,19876,
+19,34,40,19876,
+26,29,40,19876,
+5,34,44,19876,
+2,33,45,19876,
+21,34,39,19876,
+3,30,47,19876,
+25,27,42,19876,
+9,11,54,19876,
+20,28,44,19876,
+4,20,52,19876,
+6,22,51,19876,
+15,36,40,19876,
+12,24,49,19876,
+3,14,54,19876,
+24,32,39,19891,
+14,30,45,19891,
+0,39,40,19891,
+12,36,41,19891,
+14,18,51,19891,
+6,13,54,19891,
+23,36,36,19891,
+11,20,51,19891,
+12,13,53,19891,
+4,9,55,19891,
+27,32,37,19930,
+17,23,48,19930,
+1,39,40,19930,
+16,29,45,19930,
+15,31,44,19930,
+3,33,45,19930,
+9,39,39,19930,
+23,35,37,19930,
+19,19,49,19930,
+7,7,55,19930,
+5,17,53,19930,
+7,35,43,19930,
+9,21,51,19930,
+17,25,47,19930,
+6,28,48,19930,
+8,12,54,19930,
+24,28,42,19930,
+12,26,48,19930,
+8,36,42,19930,
+2,39,40,19930,
+15,28,46,19930,
+6,8,55,19930,
+0,10,55,19930,
+10,33,44,19930,
+7,24,50,19930,
+20,31,42,19930,
+0,38,41,19930,
+18,20,49,19930,
+15,20,50,19930,
+4,30,47,19930,
+14,15,52,19930,
+17,30,44,19930,
+0,25,50,19930,
+25,30,40,19930,
+9,38,40,19930,
+14,25,48,19930,
+17,34,41,19930,
+7,26,49,19930,
+1,38,41,19930,
+13,29,46,19930,
+26,35,35,19953,
+1,10,55,19953,
+1,25,50,19953,
+7,31,46,19953,
+14,23,49,19953,
+22,31,41,19953,
+29,29,38,19953,
+11,34,43,19953,
+11,14,53,19953,
+10,25,49,19953,
+6,34,44,19953,
+26,34,36,19967,
+4,14,54,19967,
+10,18,52,19967,
+28,30,38,19967,
+12,22,50,19967,
+13,16,52,19967,
+5,20,52,19967,
+2,38,41,19967,
+2,25,50,19967,
+16,32,43,19967,
+2,10,55,19967,
+23,34,38,19967,
+13,32,44,19967,
+8,16,53,19967,
+10,23,50,19967,
+22,23,46,19967,
+8,19,52,19967,
+4,33,45,19967,
+23,24,45,19967,
+0,27,49,19967,
+0,23,51,19967,
+3,39,40,19967,
+12,31,45,19967,
+9,32,45,19967,
+21,33,40,19967,
+13,19,51,19967,
+21,29,43,19967,
+9,37,41,19967,
+17,21,49,19967,
+5,9,55,19967,
+19,33,41,19967,
+15,35,41,19967,
+1,23,51,19967,
+1,27,49,19967,
+9,29,47,19967,
+12,35,42,19967,
+18,28,45,19967,
+0,18,53,19967,
+0,37,42,19967,
+21,24,46,19967,
+10,27,48,19967,
+1,37,42,19967,
+21,22,47,19967,
+14,33,43,19967,
+2,27,49,19967,
+27,31,38,20020,
+13,38,39,20020,
+17,27,46,20020,
+26,33,37,20020,
+3,25,50,20020,
+3,38,41,20020,
+10,15,53,20020,
+18,31,43,20020,
+22,25,45,20020,
+1,18,53,20020,
+3,10,55,20020,
+7,22,51,20020,
+5,30,47,20020,
+23,29,42,20020,
+7,13,54,20020,
+2,23,51,20020,
+6,17,53,20020,
+14,27,47,20020,
+0,0,56,20020,
+16,24,48,20020,
+14,21,50,20020,
+2,37,42,20020,
+24,31,40,20020,
+24,25,44,20020,
+32,32,33,20083,
+18,37,38,20083,
+11,30,46,20083,
+2,18,53,20083,
+12,28,47,20083,
+4,39,40,20083,
+5,14,54,20083,
+12,17,52,20083,
+10,11,54,20083,
+7,28,48,20083,
+0,1,56,20083,
+20,23,47,20083,
+8,35,43,20083,
+7,8,55,20083,
+20,37,37,20083,
+19,29,44,20083,
+1,1,56,20083,
+13,37,40,20083,
+27,27,41,20083,
+5,33,45,20083,
+3,27,49,20083,
+31,33,33,20103,
+23,33,39,20103,
+3,23,51,20103,
+6,20,52,20103,
+20,36,38,20103,
+0,32,46,20103,
+0,2,56,20103,
+8,24,50,20103,
+31,32,34,20119,
+1,32,46,20119,
+4,25,50,20119,
+16,22,49,20119,
+7,34,44,20119,
+20,25,46,20119,
+0,15,54,20119,
+1,2,56,20119,
+8,26,49,20119,
+26,28,41,20119,
+9,36,42,20119,
+8,31,46,20119,
+16,26,47,20119,
+4,10,55,20119,
+4,38,41,20119,
+18,36,39,20119,
+9,12,54,20119,
+23,26,44,20119,
+17,33,42,20119,
+10,39,39,20119,
+6,9,55,20119,
+3,37,42,20119,
+10,21,51,20119,
+1,15,54,20119,
+3,18,53,20119,
+21,26,45,20119,
+16,38,38,20119,
+2,2,56,20119,
+10,38,40,20119,
+26,32,38,20119,
+2,32,46,20119,
+15,34,42,20119,
+12,20,51,20119,
+20,21,48,20119,
+0,36,43,20119,
+30,33,34,20155,
+2,15,54,20155,
+0,21,52,20155,
+0,3,56,20155,
+6,30,47,20155,
+0,29,48,20155,
+1,3,56,20155,
+9,19,52,20155,
+9,16,53,20155,
+4,23,51,20155,
+13,36,41,20155,
+1,36,43,20155,
+4,27,49,20155,
+28,29,39,20155,
+21,32,41,20155,
+13,24,49,20155,
+1,29,48,20155,
+5,39,40,20155,
+20,35,39,20155,
+25,35,36,20155,
+1,21,52,20155,
+16,17,51,20155,
+0,11,55,20155,
+16,37,39,20155,
+11,33,44,20155,
+19,24,47,20155,
+7,17,53,20155,
+25,29,41,20155,
+13,13,53,20155,
+11,25,49,20155,
+1,11,55,20155,
+31,31,35,20173,
+6,14,54,20173,
+22,30,42,20173,
+18,18,50,20173,
+10,32,45,20173,
+8,13,54,20173,
+2,3,56,20173,
+19,22,48,20173,
+13,26,48,20173,
+2,29,48,20173,
+18,35,40,20173,
+3,32,46,20173,
+4,37,42,20173,
+4,18,53,20173,
+2,36,43,20173,
+30,32,35,20188,
+20,30,43,20188,
+22,36,37,20188,
+12,34,43,20188,
+11,18,52,20188,
+12,14,53,20188,
+2,21,52,20188,
+19,32,42,20188,
+22,27,44,20188,
+8,22,51,20188,
+2,11,55,20188,
+17,19,50,20188,
+5,25,50,20188,
+10,29,47,20188,
+5,10,55,20188,
+6,33,45,20188,
+3,15,54,20188,
+10,37,41,20188,
+11,23,50,20188,
+25,26,43,20188,
+5,38,41,20188,
+25,34,37,20188,
+15,30,45,20188,
+27,30,39,20188,
+15,18,51,20188,
+0,4,56,20188,
+8,28,48,20188,
+16,36,40,20188,
+7,20,52,20188,
+19,26,46,20188,
+8,8,55,20188,
+1,4,56,20188,
+23,32,40,20188,
+16,31,44,20188,
+29,34,34,20206,
+13,22,50,20206,
+22,35,38,20206,
+14,29,46,20206,
+3,36,43,20206,
+3,21,52,20206,
+3,29,48,20206,
+24,27,43,20206,
+15,25,48,20206,
+20,27,45,20206,
+15,15,52,20206,
+3,3,56,20206,
+11,27,48,20206,
+29,33,35,20237,
+9,35,43,20237,
+13,31,45,20237,
+17,29,45,20237,
+5,23,51,20237,
+15,23,49,20237,
+5,27,49,20237,
+11,15,53,20237,
+7,9,55,20237,
+3,11,55,20237,
+2,4,56,20237,
+4,32,46,20237,
+14,32,44,20237,
+20,34,40,20237,
+14,16,52,20237,
+8,34,44,20237,
+16,20,50,20237,
+16,28,46,20237,
+24,30,41,20237,
+6,39,40,20237,
+4,15,54,20237,
+9,24,50,20237,
+30,31,36,20250,
+18,23,48,20250,
+25,33,38,20250,
+5,18,53,20250,
+26,31,39,20250,
+18,25,47,20250,
+11,11,54,20250,
+13,35,42,20250,
+14,19,51,20250,
+5,37,42,20250,
+9,26,49,20250,
+9,31,46,20250,
+7,30,47,20250,
+12,30,46,20250,
+10,12,54,20250,
+18,30,44,20250,
+10,36,42,20250,
+7,14,54,20250,
+21,28,44,20250,
+6,10,55,20250,
+3,4,56,20250,
+4,21,52,20250,
+0,5,56,20250,
+18,34,41,20250,
+4,36,43,20250,
+6,25,50,20250,
+14,38,39,20250,
+29,32,36,20285,
+4,29,48,20285,
+6,38,41,20285,
+0,35,44,20285,
+22,34,39,20285,
+16,35,41,20285,
+8,17,53,20285,
+1,35,44,20285,
+13,17,52,20285,
+1,5,56,20285,
+13,28,47,20285,
+4,11,55,20285,
+19,20,49,20285,
+23,28,43,20285,
+17,32,43,20285,
+7,33,45,20285,
+11,39,39,20285,
+15,33,43,20285,
+15,27,47,20285,
+11,21,51,20285,
+10,19,52,20285,
+2,5,56,20285,
+2,35,44,20285,
+28,34,35,20317,
+5,32,46,20317,
+10,16,53,20317,
+14,37,40,20317,
+11,38,40,20317,
+18,21,49,20317,
+9,13,54,20317,
+15,21,50,20317,
+5,15,54,20317,
+6,23,51,20317,
+6,27,49,20317,
+9,22,51,20317,
+21,31,42,20317,
+8,20,52,20317,
+24,36,36,20317,
+4,4,56,20317,
+28,28,40,20317,
+6,37,42,20317,
+17,24,48,20317,
+28,33,36,20360,
+6,18,53,20360,
+12,33,44,20360,
+9,28,48,20360,
+30,30,37,20360,
+26,27,42,20360,
+18,27,46,20360,
+0,12,55,20360,
+5,21,52,20360,
+25,32,39,20360,
+20,33,41,20360,
+5,36,43,20360,
+19,28,45,20360,
+5,29,48,20360,
+0,31,47,20360,
+24,35,37,20360,
+27,29,40,20360,
+8,9,55,20360,
+3,35,44,20360,
+3,5,56,20360,
+12,25,49,20360,
+0,19,53,20360,
+7,39,40,20360,
+11,32,45,20360,
+13,20,51,20360,
+1,12,55,20360,
+5,11,55,20360,
+23,31,41,20360,
+11,37,41,20360,
+1,19,53,20360,
+29,31,37,20376,
+19,31,43,20376,
+11,29,47,20376,
+1,31,47,20376,
+0,6,56,20376,
+12,18,52,20376,
+0,16,54,20376,
+14,36,41,20376,
+9,34,44,20376,
+1,6,56,20376,
+2,12,55,20376,
+8,30,47,20376,
+25,28,42,20376,
+22,33,40,20376,
+1,16,54,20376,
+14,24,49,20376,
+12,23,50,20376,
+17,22,49,20376,
+10,35,43,20376,
+23,23,46,20376,
+22,29,43,20376,
+7,38,41,20376,
+19,37,38,20376,
+7,25,50,20376,
+2,31,47,20376,
+17,26,47,20376,
+13,34,43,20376,
+2,19,53,20376,
+7,10,55,20376,
+13,14,53,20376,
+14,26,48,20376,
+22,24,46,20376,
+24,34,38,20383,
+2,6,56,20383,
+2,16,54,20383,
+10,24,50,20383,
+26,30,40,20383,
+6,32,46,20383,
+0,26,50,20383,
+16,34,42,20383,
+8,14,54,20383,
+28,32,37,20416,
+12,27,48,20416,
+18,33,42,20416,
+6,15,54,20416,
+4,5,56,20416,
+4,35,44,20416,
+20,29,44,20416,
+17,38,38,20416,
+22,22,47,20416,
+1,26,50,20416,
+10,26,49,20416,
+0,24,51,20416,
+24,24,45,20416,
+10,31,46,20416,
+19,36,39,20416,
+3,12,55,20416,
+1,24,51,20416,
+12,15,53,20416,
+8,33,45,20416,
+23,25,45,20416,
+3,19,53,20416,
+7,27,49,20416,
+21,37,37,20416,
+21,23,47,20416,
+7,23,51,20416,
+27,35,35,20434,
+17,37,39,20434,
+3,31,47,20434,
+17,17,51,20434,
+9,17,53,20434,
+14,22,50,20434,
+2,26,50,20434,
+11,12,54,20434,
+6,29,48,20434,
+16,30,45,20434,
+11,36,42,20434,
+2,24,51,20434,
+27,34,36,20447,
+6,36,43,20447,
+3,16,54,20447,
+16,18,51,20447,
+3,6,56,20447,
+0,34,45,20447,
+21,36,38,20447,
+6,21,52,20447,
+24,29,42,20447,
+21,25,46,20447,
+7,37,42,20447,
+14,31,45,20447,
+6,11,55,20447,
+1,34,45,20447,
+15,29,46,20447,
+7,18,53,20447,
+20,24,47,20447,
+13,30,46,20447,
+4,12,55,20447,
+0,28,49,20447,
+15,32,44,20447,
+18,19,50,20447,
+29,30,38,20475,
+3,26,50,20475,
+14,35,42,20475,
+16,25,48,20475,
+2,34,45,20475,
+22,26,45,20475,
+10,22,51,20475,
+8,39,40,20475,
+9,20,52,20475,
+17,36,40,20475,
+10,13,54,20475,
+0,7,56,20475,
+15,16,52,20475,
+25,31,40,20475,
+12,21,51,20475,
+3,24,51,20475,
+11,16,53,20475,
+19,35,40,20475,
+5,5,56,20475,
+24,33,39,20475,
+5,35,44,20475,
+12,39,39,20475,
+11,19,52,20475,
+16,23,49,20475,
+4,19,53,20475,
+21,21,48,20475,
+17,31,44,20475,
+1,7,56,20475,
+4,31,47,20475,
+1,28,49,20475,
+25,25,44,20475,
+9,9,55,20475,
+15,19,51,20475,
+21,35,39,20475,
+27,33,37,20496,
+4,6,56,20496,
+12,38,40,20496,
+4,16,54,20496,
+10,28,48,20496,
+20,22,48,20496,
+24,26,44,20496,
+20,32,42,20496,
+0,22,52,20496,
+28,31,38,20512,
+2,7,56,20512,
+8,10,55,20512,
+2,28,49,20512,
+14,28,47,20512,
+22,32,41,20512,
+7,32,46,20512,
+8,25,50,20512,
+14,17,52,20512,
+17,20,50,20512,
+8,38,41,20512,
+1,22,52,20512,
+17,28,46,20512,
+18,29,45,20512,
+9,30,47,20512,
+21,30,43,20512,
+15,38,39,20512,
+7,15,54,20512,
+3,34,45,20512,
+4,26,50,20512,
+20,26,46,20512,
+2,22,52,20512,
+10,34,44,20512,
+12,32,45,20512,
+23,30,42,20512,
+4,24,51,20512,
+9,14,54,20512,
+7,29,48,20512,
+3,28,49,20512,
+13,33,44,20512,
+7,36,43,20512,
+23,27,44,20512,
+15,37,40,20512,
+5,12,55,20512,
+16,33,43,20512,
+8,23,51,20512,
+16,27,47,20512,
+23,36,37,20526,
+3,7,56,20526,
+12,37,41,20526,
+27,28,41,20526,
+0,13,55,20526,
+7,21,52,20526,
+19,23,48,20526,
+8,27,49,20526,
+12,29,47,20526,
+21,27,45,20526,
+7,11,55,20526,
+5,19,53,20526,
+17,35,41,20526,
+9,33,45,20526,
+13,25,49,20526,
+11,35,43,20526,
+1,13,55,20526,
+5,31,47,20526,
+19,25,47,20526,
+18,32,43,20526,
+5,16,54,20526,
+4,34,45,20526,
+26,35,36,20574,
+5,6,56,20574,
+14,20,51,20574,
+16,21,50,20574,
+11,24,50,20574,
+27,32,38,20574,
+21,34,40,20574,
+8,37,42,20574,
+6,35,44,20574,
+3,22,52,20574,
+8,18,53,20574,
+13,18,52,20574,
+19,30,44,20574,
+26,29,41,20574,
+11,31,46,20574,
+13,23,50,20574,
+23,35,38,20574,
+10,17,53,20574,
+2,13,55,20574,
+11,26,49,20574,
+19,34,41,20574,
+0,8,56,20574,
+24,32,40,20574,
+0,40,40,20574,
+4,7,56,20574,
+5,26,50,20574,
+1,40,40,20574,
+26,26,43,20574,
+26,34,37,20596,
+1,8,56,20596,
+4,28,49,20596,
+20,20,49,20596,
+14,34,43,20596,
+14,14,53,20596,
+5,24,51,20596,
+15,36,41,20596,
+15,24,49,20596,
+0,39,41,20596,
+9,39,40,20596,
+32,33,33,20654,
+13,27,48,20654,
+29,29,39,20654,
+25,27,43,20654,
+3,13,55,20654,
+1,39,41,20654,
+19,21,49,20654,
+13,15,53,20654,
+32,32,34,20662,
+22,28,44,20662,
+4,22,52,20662,
+12,36,42,20662,
+12,12,54,20662,
+2,8,56,20662,
+0,30,48,20662,
+8,32,46,20662,
+10,20,52,20662,
+18,24,48,20662,
+2,40,40,20662,
+8,15,54,20662,
+1,30,48,20662,
+15,26,48,20662,
+0,17,54,20662,
+6,12,55,20662,
+28,30,39,20662,
+0,33,46,20662,
+9,38,41,20662,
+31,33,34,20689,
+9,10,55,20689,
+5,34,45,20689,
+23,34,39,20689,
+6,31,47,20689,
+11,13,54,20689,
+9,25,50,20689,
+1,17,54,20689,
+6,19,53,20689,
+1,33,46,20689,
+19,27,46,20689,
+2,39,41,20689,
+11,22,51,20689,
+25,30,41,20689,
+0,38,42,20689,
+2,30,48,20689,
+6,16,54,20689,
+6,6,56,20689,
+22,31,42,20689,
+2,17,54,20689,
+20,28,45,20689,
+18,22,49,20689,
+26,33,38,20689,
+17,34,42,20689,
+0,20,53,20689,
+1,38,42,20689,
+15,22,50,20689,
+3,40,40,20689,
+12,19,52,20689,
+8,29,48,20689,
+8,36,43,20689,
+10,30,47,20689,
+12,16,53,20689,
+2,33,46,20689,
+8,21,52,20689,
+11,28,48,20689,
+18,26,47,20689,
+3,8,56,20689,
+24,28,43,20689,
+5,28,49,20689,
+8,11,55,20689,
+1,20,53,20689,
+20,31,43,20689,
+5,7,56,20689,
+31,32,35,20724,
+7,35,44,20724,
+4,13,55,20724,
+9,23,51,20724,
+13,21,51,20724,
+21,33,41,20724,
+15,31,45,20724,
+3,39,41,20724,
+9,27,49,20724,
+13,39,39,20724,
+27,31,39,20724,
+2,38,42,20724,
+14,30,46,20724,
+10,14,54,20724,
+18,38,38,20724,
+30,34,34,20727,
+6,26,50,20727,
+2,20,53,20727,
+11,34,44,20727,
+6,24,51,20727,
+5,22,52,20727,
+20,37,38,20727,
+13,38,40,20727,
+16,29,46,20727,
+3,30,48,20727,
+18,37,39,20727,
+3,17,54,20727,
+17,18,51,20727,
+17,30,45,20727,
+10,33,45,20727,
+15,35,42,20727,
+3,33,46,20727,
+9,37,42,20727,
+9,18,53,20727,
+30,33,35,20761,
+19,33,42,20761,
+16,16,52,20761,
+4,8,56,20761,
+4,40,40,20761,
+16,32,44,20761,
+20,36,39,20761,
+3,38,42,20761,
+0,9,56,20761,
+25,36,36,20761,
+6,34,45,20761,
+12,35,43,20761,
+17,25,48,20761,
+13,32,45,20761,
+31,31,36,20791,
+16,19,51,20791,
+1,9,56,20791,
+23,33,40,20791,
+7,12,55,20791,
+24,31,41,20791,
+15,17,52,20791,
+3,20,53,20791,
+4,39,41,20791,
+21,29,44,20791,
+15,28,47,20791,
+0,37,43,20791,
+25,35,37,20791,
+7,31,47,20791,
+7,19,53,20791,
+1,37,43,20791,
+13,37,41,20791,
+5,13,55,20791,
+11,17,53,20791,
+23,29,43,20791,
+17,23,49,20791,
+13,29,47,20791,
+4,30,48,20791,
+12,24,50,20791,
+18,36,40,20791,
+30,32,36,20798,
+4,33,46,20798,
+18,31,44,20798,
+10,39,40,20798,
+23,24,46,20798,
+9,32,46,20798,
+0,14,55,20798,
+7,16,54,20798,
+16,38,39,20798,
+14,33,44,20798,
+12,26,49,20798,
+4,17,54,20798,
+26,32,39,20798,
+6,28,49,20798,
+12,31,46,20798,
+6,7,56,20798,
+2,9,56,20798,
+9,15,54,20798,
+14,25,49,20798,
+22,37,37,20798,
+29,34,35,20835,
+2,37,43,20835,
+27,27,42,20835,
+19,19,50,20835,
+1,14,55,20835,
+22,23,47,20835,
+14,18,52,20835,
+4,38,42,20835,
+26,28,42,20835,
+18,28,46,20835,
+6,22,52,20835,
+18,20,50,20835,
+22,36,38,20835,
+11,20,52,20835,
+5,40,40,20835,
+4,20,53,20835,
+8,35,44,20835,
+10,25,50,20835,
+7,26,50,20835,
+5,8,56,20835,
+20,35,40,20835,
+10,38,41,20835,
+14,23,50,20835,
+2,14,55,20835,
+25,34,38,20835,
+22,25,46,20835,
+16,37,40,20835,
+28,29,40,20835,
+10,10,55,20835,
+9,36,43,20835,
+9,29,48,20835,
+9,21,52,20835,
+7,24,51,20835,
+15,20,51,20835,
+0,25,51,20835,
+29,33,36,20876,
+24,25,45,20876,
+3,9,56,20876,
+21,24,47,20876,
+5,39,41,20876,
+17,33,43,20876,
+9,11,55,20876,
+1,25,51,20876,
+3,37,43,20876,
+17,27,47,20876,
+19,29,45,20876,
+0,27,50,20876,
+21,22,48,20876,
+5,30,48,20876,
+12,13,54,20876,
+27,30,40,20876,
+21,32,42,20876,
+12,22,51,20876,
+13,36,42,20876,
+14,27,48,20876,
+25,29,42,20876,
+5,17,54,20876,
+3,14,55,20876,
+5,33,46,20876,
+10,27,49,20876,
+10,23,51,20876,
+6,13,55,20876,
+30,31,37,20891,
+18,35,41,20891,
+7,34,45,20891,
+11,30,47,20891,
+23,26,45,20891,
+2,25,51,20891,
+17,21,50,20891,
+14,15,53,20891,
+1,27,50,20891,
+22,35,39,20891,
+15,34,43,20891,
+0,36,44,20891,
+12,28,48,20891,
+5,38,42,20891,
+20,23,48,20891,
+16,36,41,20891,
+22,30,43,20891,
+1,36,44,20891,
+10,18,53,20891,
+21,26,46,20891,
+16,24,49,20891,
+11,14,54,20891,
+2,27,50,20891,
+0,23,52,20891,
+10,37,42,20891,
+4,9,56,20891,
+8,12,55,20891,
+0,32,47,20891,
+13,19,52,20891,
+5,20,53,20891,
+8,19,53,20891,
+1,32,47,20891,
+20,25,47,20891,
+23,32,41,20891,
+19,32,43,20891,
+1,23,52,20891,
+4,37,43,20891,
+28,35,35,20929,
+8,31,47,20929,
+7,7,56,20929,
+29,32,37,20929,
+13,16,53,20929,
+7,28,49,20929,
+25,33,39,20929,
+3,25,51,20929,
+11,33,45,20929,
+2,36,44,20929,
+8,16,54,20929,
+0,10,56,20929,
+28,34,36,20933,
+6,40,40,20933,
+20,30,44,20933,
+16,26,48,20933,
+6,8,56,20933,
+12,34,44,20933,
+1,10,56,20933,
+2,23,52,20933,
+20,34,41,20933,
+4,14,55,20933,
+7,22,52,20933,
+26,31,40,20933,
+2,32,47,20933,
+25,26,44,20933,
+3,27,50,20933,
+22,27,45,20933,
+14,21,51,20933,
+14,39,39,20933,
+6,39,41,20933,
+16,22,50,20933,
+0,18,54,20933,
+22,34,40,20933,
+8,26,50,20933,
+14,38,40,20933,
+10,32,46,20933,
+24,30,42,20933,
+6,30,48,20933,
+2,10,56,20933,
+3,36,44,20933,
+15,30,46,20933,
+8,24,51,20933,
+6,17,54,20933,
+19,24,48,20933,
+1,18,54,20933,
+10,15,54,20933,
+6,33,46,20933,
+24,27,44,20933,
+24,36,37,20953,
+11,39,40,20953,
+9,35,44,20953,
+20,21,49,20953,
+12,17,53,20953,
+3,23,52,20953,
+0,29,49,20953,
+28,33,37,20987,
+5,9,56,20987,
+16,31,45,20987,
+4,25,51,20987,
+3,32,47,20987,
+1,29,49,20987,
+13,35,43,20987,
+5,37,43,20987,
+7,13,55,20987,
+30,30,38,20989,
+2,18,54,20989,
+6,38,42,20989,
+18,34,42,20989,
+16,35,42,20989,
+6,20,53,20989,
+4,27,50,20989,
+20,27,46,20989,
+24,35,38,20989,
+10,21,52,20989,
+3,10,56,20989,
+10,36,43,20989,
+13,24,50,20989,
+8,34,45,20989,
+14,32,45,20989,
+10,29,48,20989,
+11,25,50,20989,
+13,31,46,20989,
+17,29,46,20989,
+14,37,41,20989,
+19,22,49,20989,
+10,11,55,20989,
+11,38,41,20989,
+14,29,47,20989,
+19,26,47,20989,
+5,14,55,20989,
+29,31,38,21023,
+2,29,49,21023,
+13,26,49,21023,
+12,20,52,21023,
+4,36,44,21023,
+16,28,47,21023,
+19,38,38,21023,
+17,32,44,21023,
+28,28,41,21023,
+25,32,40,21023,
+7,8,56,21023,
+4,32,47,21023,
+3,18,54,21023,
+8,28,49,21023,
+18,18,51,21023,
+23,28,44,21023,
+0,0,57,21023,
+18,30,45,21023,
+16,17,52,21023,
+7,40,40,21023,
+4,23,52,21023,
+0,21,53,21023,
+0,1,57,21023,
+15,33,44,21023,
+0,15,55,21023,
+9,12,55,21023,
+27,35,36,21073,
+0,35,45,21073,
+21,28,45,21073,
+1,35,45,21073,
+5,25,51,21073,
+15,25,49,21073,
+1,15,55,21073,
+17,19,51,21073,
+21,31,43,21073,
+9,19,53,21073,
+27,29,41,21073,
+11,27,49,21073,
+1,1,57,21073,
+7,39,41,21073,
+1,21,53,21073,
+19,37,39,21073,
+11,23,51,21073,
+9,31,47,21073,
+3,29,49,21073,
+8,22,52,21073,
+28,32,38,21083,
+4,10,56,21083,
+24,34,39,21083,
+20,33,42,21083,
+12,30,47,21083,
+7,30,48,21083,
+6,9,56,21083,
+18,25,48,21083,
+0,2,57,21083,
+9,16,54,21083,
+15,18,52,21083,
+23,31,42,21083,
+11,18,53,21083,
+11,37,42,21083,
+2,15,55,21083,
+5,27,50,21083,
+6,37,43,21083,
+7,33,46,21083,
+2,21,53,21083,
+18,23,49,21083,
+13,13,54,21083,
+27,34,37,21099,
+1,2,57,21099,
+21,37,38,21099,
+2,35,45,21099,
+17,38,39,21099,
+7,17,54,21099,
+13,22,51,21099,
+22,33,41,21099,
+26,27,43,21099,
+15,23,50,21099,
+12,14,54,21099,
+14,36,42,21099,
+4,18,54,21099,
+0,11,56,21099,
+5,36,44,21099,
+26,30,41,21099,
+2,2,57,21099,
+7,38,42,21099,
+6,14,55,21099,
+13,28,48,21099,
+9,26,50,21099,
+19,36,40,21099,
+16,20,51,21099,
+17,37,40,21099,
+9,24,51,21099,
+0,3,57,21099,
+21,36,39,21099,
+19,31,44,21099,
+25,28,43,21099,
+8,13,55,21099,
+5,32,47,21099,
+15,27,48,21099,
+1,11,56,21099,
+7,20,53,21099,
+5,23,52,21099,
+12,33,45,21099,
+4,29,49,21099,
+1,3,57,21099,
+3,21,53,21099,
+3,35,45,21099,
+15,15,53,21099,
+3,15,55,21099,
+14,16,53,21099,
+16,34,43,21099,
+2,11,56,21099,
+5,10,56,21099,
+19,20,50,21099,
+14,19,52,21099,
+13,34,44,21099,
+11,32,46,21099,
+22,29,44,21099,
+10,35,44,21099,
+19,28,46,21099,
+9,34,45,21099,
+2,3,57,21099,
+27,33,38,21166,
+18,33,43,21166,
+18,27,47,21166,
+29,30,39,21166,
+6,25,51,21166,
+11,15,54,21166,
+8,8,56,21166,
+8,40,40,21166,
+24,33,40,21166,
+5,18,54,21166,
+0,31,48,21166,
+18,21,50,21166,
+6,27,50,21166,
+12,39,40,21166,
+0,4,57,21166,
+1,4,57,21166,
+28,31,39,21198,
+11,36,43,21198,
+11,21,52,21198,
+11,29,48,21198,
+1,31,48,21198,
+8,39,41,21198,
+24,29,43,21198,
+9,28,49,21198,
+4,21,53,21198,
+4,35,45,21198,
+21,35,40,21198,
+4,15,55,21198,
+20,29,45,21198,
+7,9,56,21198,
+3,11,56,21198,
+17,36,41,21198,
+17,24,49,21198,
+13,17,53,21198,
+23,37,37,21198,
+23,23,47,21198,
+33,33,33,21243,
+11,11,55,21243,
+3,3,57,21243,
+25,31,41,21243,
+15,39,39,21243,
+15,21,51,21243,
+5,29,49,21243,
+19,35,41,21243,
+7,37,43,21243,
+24,24,46,21243,
+8,30,48,21243,
+26,36,36,21243,
+6,36,44,21243,
+22,24,47,21243,
+6,23,52,21243,
+32,33,34,21252,
+9,22,52,21252,
+2,31,48,21252,
+15,38,40,21252,
+6,32,47,21252,
+12,38,41,21252,
+12,25,50,21252,
+2,4,57,21252,
+8,33,46,21252,
+17,26,48,21252,
+23,36,38,21252,
+8,17,54,21252,
+10,12,55,21252,
+26,35,37,21252,
+10,19,53,21252,
+14,35,43,21252,
+23,25,46,21252,
+10,31,47,21252,
+7,14,55,21252,
+8,38,42,21252,
+22,32,42,21252,
+0,34,46,21252,
+14,24,50,21252,
+10,16,54,21252,
+6,10,56,21252,
+16,30,46,21252,
+22,22,48,21252,
+14,26,49,21252,
+8,20,53,21252,
+4,11,56,21252,
+32,32,35,21286,
+20,32,43,21286,
+31,34,34,21286,
+13,20,52,21286,
+1,34,46,21286,
+17,22,50,21286,
+14,31,46,21286,
+3,4,57,21286,
+3,31,48,21286,
+12,27,49,21286,
+12,23,51,21286,
+21,23,48,21286,
+27,32,39,21286,
+0,5,57,21286,
+15,32,45,21286,
+5,15,55,21286,
+15,29,47,21286,
+5,35,45,21286,
+31,33,35,21299,
+21,25,47,21299,
+15,37,41,21299,
+9,13,55,21299,
+7,25,51,21299,
+25,25,45,21299,
+23,35,39,21299,
+5,21,53,21299,
+17,31,45,21299,
+1,5,57,21299,
+10,26,50,21299,
+26,34,38,21299,
+2,34,46,21299,
+6,18,54,21299,
+22,26,46,21299,
+10,24,51,21299,
+12,18,53,21299,
+12,37,42,21299,
+24,26,45,21299,
+21,30,44,21299,
+0,26,51,21299,
+0,19,54,21299,
+27,28,42,21299,
+13,30,47,21299,
+17,35,42,21299,
+1,26,51,21299,
+2,5,57,21299,
+21,34,41,21299,
+1,19,54,21299,
+6,29,49,21299,
+7,27,50,21299,
+23,30,43,21299,
+20,24,48,21299,
+0,12,56,21299,
+0,24,52,21299,
+7,36,44,21299,
+4,4,57,21299,
+19,34,42,21299,
+0,16,55,21299,
+10,34,45,21299,
+0,40,41,21299,
+16,33,44,21299,
+4,31,48,21299,
+24,32,41,21299,
+18,29,46,21299,
+9,40,40,21299,
+1,12,56,21299,
+14,22,51,21299,
+26,29,42,21299,
+2,26,51,21299,
+3,34,46,21299,
+13,14,54,21299,
+31,32,36,21352,
+2,19,54,21352,
+8,9,56,21352,
+30,34,35,21352,
+1,24,52,21352,
+29,29,40,21352,
+17,28,47,21352,
+17,17,52,21352,
+11,35,44,21352,
+1,40,41,21352,
+5,11,56,21352,
+7,32,47,21352,
+16,25,49,21352,
+7,23,52,21352,
+1,16,55,21352,
+8,37,43,21352,
+13,33,45,21352,
+9,39,41,21352,
+23,27,45,21352,
+3,5,57,21352,
+21,21,49,21352,
+18,32,44,21352,
+0,28,50,21352,
+28,30,40,21352,
+2,24,52,21352,
+12,32,46,21352,
+14,28,48,21352,
+2,12,56,21352,
+16,18,52,21352,
+8,14,55,21352,
+15,36,42,21352,
+0,39,42,21352,
+20,26,47,21352,
+16,23,50,21352,
+2,16,55,21352,
+23,34,40,21352,
+7,10,56,21352,
+9,30,48,21352,
+1,28,50,21352,
+20,22,49,21352,
+2,40,41,21352,
+12,15,54,21352,
+30,33,36,21384,
+10,28,49,21384,
+0,6,57,21384,
+9,17,54,21384,
+9,33,46,21384,
+26,33,39,21384,
+6,21,53,21384,
+18,19,51,21384,
+19,30,45,21384,
+3,26,51,21384,
+6,15,55,21384,
+1,39,42,21384,
+6,35,45,21384,
+3,19,54,21384,
+21,27,46,21384,
+1,6,57,21384,
+26,26,44,21384,
+20,38,38,21384,
+14,34,44,21384,
+10,22,52,21384,
+4,34,46,21384,
+2,28,50,21384,
+25,30,42,21384,
+2,6,57,21384,
+18,38,39,21384,
+3,12,56,21384,
+2,39,42,21384,
+3,24,52,21384,
+12,36,43,21384,
+12,21,52,21384,
+7,18,54,21384,
+9,38,42,21384,
+12,29,48,21384,
+16,27,48,21384,
+27,31,40,21393,
+25,27,44,21393,
+17,20,51,21393,
+3,40,41,21393,
+3,16,55,21393,
+9,20,53,21393,
+8,25,51,21393,
+25,36,37,21393,
+15,19,52,21393,
+13,39,40,21393,
+20,37,39,21393,
+19,25,48,21393,
+15,16,53,21393,
+11,12,55,21393,
+4,5,57,21393,
+5,31,48,21393,
+7,29,49,21393,
+29,35,35,21425,
+31,31,37,21425,
+11,19,53,21425,
+19,23,49,21425,
+11,31,47,21425,
+8,27,50,21425,
+18,37,40,21425,
+22,28,45,21425,
+30,32,37,21453,
+3,28,50,21453,
+4,19,54,21453,
+0,38,43,21453,
+0,22,53,21453,
+29,34,36,21453,
+6,11,56,21453,
+11,16,54,21453,
+4,26,51,21453,
+3,39,42,21453,
+1,38,43,21453,
+17,34,43,21453,
+3,6,57,21453,
+10,13,55,21453,
+21,33,42,21453,
+13,38,41,21453,
+25,35,38,21453,
+14,17,53,21453,
+22,31,43,21453,
+13,25,50,21453,
+1,22,53,21453,
+20,36,40,21453,
+8,36,44,21453,
+4,12,56,21453,
+24,28,44,21453,
+4,24,52,21453,
+8,32,47,21453,
+11,26,50,21453,
+4,16,55,21453,
+2,38,43,21453,
+5,34,46,21453,
+22,37,38,21453,
+4,40,41,21453,
+2,22,53,21453,
+8,23,52,21453,
+20,31,44,21453,
+11,24,51,21453,
+16,39,39,21453,
+9,9,56,21453,
+0,7,57,21453,
+16,21,51,21453,
+0,33,47,21453,
+1,33,47,21453,
+7,35,45,21453,
+7,21,53,21453,
+29,33,37,21505,
+1,7,57,21505,
+5,5,57,21505,
+7,15,55,21505,
+19,27,47,21505,
+9,37,43,21505,
+23,33,41,21505,
+13,27,49,21505,
+15,35,43,21505,
+19,33,43,21505,
+13,23,51,21505,
+10,40,40,21505,
+4,28,50,21505,
+16,38,40,21505,
+26,32,40,21505,
+20,20,50,21505,
+14,20,52,21505,
+8,10,56,21505,
+20,28,46,21505,
+18,24,49,21505,
+0,30,49,21505,
+22,36,39,21505,
+6,31,48,21505,
+24,31,42,21505,
+18,36,41,21505,
+4,39,42,21505,
+4,6,57,21505,
+15,24,50,21505,
+13,18,53,21505,
+3,38,43,21505,
+3,22,53,21505,
+10,39,41,21505,
+5,26,51,21505,
+5,19,54,21505,
+9,14,55,21505,
+2,33,47,21505,
+19,21,50,21505,
+1,30,49,21505,
+11,34,45,21505,
+15,26,49,21505,
+25,34,39,21505,
+15,31,46,21505,
+2,7,57,21505,
+13,37,42,21505,
+18,26,48,21505,
+10,30,48,21505,
+8,18,54,21505,
+0,13,56,21505,
+2,30,49,21505,
+10,33,46,21505,
+5,12,56,21505,
+10,17,54,21505,
+28,35,36,21547,
+30,31,38,21547,
+16,32,45,21547,
+17,30,46,21547,
+5,24,52,21547,
+14,30,47,21547,
+12,35,44,21547,
+0,37,44,21547,
+7,11,56,21547,
+11,28,49,21547,
+1,13,56,21547,
+16,37,41,21547,
+23,29,44,21547,
+1,37,44,21547,
+28,29,41,21547,
+20,35,41,21547,
+8,29,49,21547,
+5,40,41,21547,
+5,16,55,21547,
+16,29,47,21547,
+27,27,43,21547,
+9,25,51,21547,
+21,29,45,21547,
+3,33,47,21547,
+3,7,57,21547,
+10,38,42,21547,
+14,14,54,21547,
+18,22,50,21547,
+6,34,46,21547,
+4,38,43,21547,
+29,32,38,21592,
+5,28,50,21592,
+4,22,53,21592,
+11,22,52,21592,
+10,20,53,21592,
+22,35,40,21592,
+13,32,46,21592,
+2,13,56,21592,
+28,34,37,21592,
+2,37,44,21592,
+26,28,43,21592,
+9,27,50,21592,
+14,33,45,21592,
+15,22,51,21592,
+27,30,41,21592,
+3,30,49,21592,
+5,6,57,21592,
+18,31,45,21592,
+5,39,42,21592,
+13,15,54,21592,
+6,19,54,21592,
+15,28,48,21592,
+12,12,55,21592,
+0,8,57,21592,
+18,35,42,21592,
+9,36,44,21592,
+6,26,51,21592,
+25,33,40,21599,
+9,23,52,21599,
+3,37,44,21599,
+4,7,57,21599,
+13,29,48,21599,
+13,36,43,21599,
+8,21,53,21599,
+3,13,56,21599,
+4,33,47,21599,
+8,35,45,21599,
+21,32,43,21599,
+13,21,52,21599,
+9,32,47,21599,
+7,31,48,21599,
+8,15,55,21599,
+24,37,37,21599,
+12,19,53,21599,
+12,31,47,21599,
+23,24,47,21599,
+0,17,55,21599,
+1,8,57,21599,
+17,33,44,21599,
+25,29,43,21599,
+17,25,49,21599,
+1,17,55,21599,
+11,13,55,21599,
+16,36,42,21599,
+24,36,38,21605,
+0,20,54,21605,
+6,24,52,21605,
+6,12,56,21605,
+12,16,54,21605,
+4,30,49,21605,
+9,10,56,21605,
+24,25,46,21605,
+22,23,48,21605,
+28,33,38,21659,
+1,20,54,21659,
+6,40,41,21659,
+17,18,52,21659,
+18,28,47,21659,
+14,39,40,21659,
+23,32,42,21659,
+6,16,55,21659,
+2,8,57,21659,
+15,34,44,21659,
+5,38,43,21659,
+5,22,53,21659,
+17,23,50,21659,
+10,37,43,21659,
+2,17,55,21659,
+19,29,46,21659,
+22,25,47,21659,
+26,31,41,21659,
+22,30,44,21659,
+20,34,42,21659,
+12,26,50,21659,
+6,28,50,21659,
+2,20,54,21659,
+16,19,52,21659,
+9,18,54,21659,
+23,26,46,21659,
+27,36,36,21692,
+14,25,50,21692,
+4,13,56,21692,
+11,40,40,21692,
+30,30,39,21692,
+4,37,44,21692,
+21,24,48,21692,
+6,39,42,21692,
+6,6,57,21692,
+12,24,51,21692,
+10,14,55,21692,
+8,11,56,21692,
+22,34,41,21692,
+7,34,46,21692,
+14,38,41,21692,
+19,32,44,21692,
+16,16,53,21692,
+0,36,45,21692,
+3,8,57,21692,
+17,27,48,21692,
+1,36,45,21692,
+24,35,39,21692,
+29,31,39,21714,
+15,17,53,21714,
+3,17,55,21714,
+19,19,51,21714,
+27,35,37,21714,
+11,39,41,21714,
+9,29,49,21714,
+5,7,57,21714,
+5,33,47,21714,
+12,34,45,21714,
+3,20,54,21714,
+11,30,48,21714,
+18,20,51,21714,
+20,30,45,21714,
+24,30,43,21714,
+2,36,45,21714,
+21,26,47,21714,
+19,38,39,21714,
+10,25,51,21714,
+11,17,54,21714,
+11,33,46,21714,
+14,23,51,21714,
+7,19,54,21714,
+7,26,51,21714,
+25,26,45,21714,
+21,22,49,21714,
+14,27,49,21714,
+5,30,49,21714,
+0,32,48,21714,
+1,32,48,21714,
+10,27,50,21714,
+28,32,39,21768,
+8,31,48,21768,
+7,12,56,21768,
+7,24,52,21768,
+12,28,49,21768,
+11,38,42,21768,
+6,38,43,21768,
+22,27,46,21768,
+21,38,38,21768,
+18,34,43,21768,
+27,34,38,21768,
+4,8,57,21768,
+15,20,52,21768,
+14,37,42,21768,
+0,25,52,21768,
+20,25,48,21768,
+14,18,53,21768,
+6,22,53,21768,
+16,35,43,21768,
+13,35,44,21768,
+19,37,40,21768,
+7,16,55,21768,
+1,25,52,21768,
+0,27,51,21768,
+4,17,55,21768,
+20,23,49,21768,
+11,20,53,21768,
+7,40,41,21768,
+24,27,45,21768,
+3,36,45,21768,
+0,9,57,21768,
+5,37,44,21768,
+25,32,41,21768,
+5,13,56,21768,
+21,37,39,21768,
+17,21,51,21768,
+9,21,53,21768,
+17,39,39,21768,
+9,15,55,21768,
+1,9,57,21768,
+9,35,45,21768,
+1,27,51,21768,
+2,32,48,21768,
+24,34,40,21768,
+12,22,52,21768,
+0,14,56,21768,
+4,20,54,21768,
+16,24,50,21768,
+10,36,44,21768,
+28,28,42,21768,
+2,25,52,21768,
+1,14,56,21768,
+7,28,50,21768,
+10,32,47,21768,
+16,31,46,21768,
+17,38,40,21768,
+16,26,49,21768,
+10,23,52,21768,
+6,33,47,21768,
+7,39,42,21768,
+2,27,51,21768,
+15,30,47,21768,
+6,7,57,21768,
+33,33,34,21833,
+27,29,42,21833,
+2,9,57,21833,
+8,34,46,21833,
+10,10,56,21833,
+14,32,46,21833,
+32,34,34,21846,
+2,14,56,21846,
+14,15,54,21846,
+22,33,42,21846,
+21,36,40,21846,
+3,32,48,21846,
+6,30,49,21846,
+4,36,45,21846,
+12,13,55,21846,
+9,11,56,21846,
+23,28,45,21846,
+17,32,45,21846,
+19,36,41,21846,
+5,8,57,21846,
+0,23,53,21846,
+20,27,47,21846,
+19,24,49,21846,
+21,31,44,21846,
+3,25,52,21846,
+32,33,35,21873,
+20,33,43,21873,
+3,27,51,21873,
+23,31,43,21873,
+13,31,47,21873,
+13,19,53,21873,
+17,29,47,21873,
+3,9,57,21873,
+11,37,43,21873,
+5,17,55,21873,
+17,37,41,21873,
+1,23,53,21873,
+27,33,39,21873,
+15,33,45,21873,
+18,30,46,21873,
+26,30,42,21873,
+10,18,54,21873,
+21,28,46,21873,
+14,36,43,21873,
+14,29,48,21873,
+26,36,37,21873,
+5,20,54,21873,
+16,22,51,21873,
+29,30,40,21873,
+6,37,44,21873,
+19,26,48,21873,
+13,16,54,21873,
+26,27,44,21873,
+20,21,50,21873,
+8,19,54,21873,
+14,21,52,21873,
+0,29,50,21873,
+8,26,51,21873,
+0,35,46,21873,
+3,14,56,21873,
+6,13,56,21873,
+7,38,43,21873,
+1,35,46,21873,
+2,23,53,21873,
+7,22,53,21873,
+10,29,49,21873,
+31,34,35,21900,
+1,29,50,21900,
+23,37,38,21900,
+11,14,55,21900,
+8,12,56,21900,
+8,24,52,21900,
+4,32,48,21900,
+12,40,40,21900,
+32,32,36,21915,
+16,28,48,21915,
+25,28,44,21915,
+28,31,40,21915,
+19,22,50,21915,
+4,25,52,21915,
+2,29,50,21915,
+8,40,41,21915,
+13,26,50,21915,
+2,35,46,21915,
+26,35,38,21915,
+8,16,55,21915,
+4,9,57,21915,
+23,36,39,21915,
+12,39,41,21915,
+13,24,51,21915,
+15,39,40,21915,
+5,36,45,21915,
+4,27,51,21915,
+24,33,41,21915,
+9,31,48,21915,
+31,33,36,21942,
+21,35,41,21942,
+7,33,47,21942,
+7,7,57,21942,
+11,25,51,21942,
+19,31,45,21942,
+3,23,53,21942,
+16,34,44,21942,
+8,28,50,21942,
+12,30,48,21942,
+4,14,56,21942,
+0,18,55,21942,
+17,36,42,21942,
+12,17,54,21942,
+0,10,57,21942,
+6,8,57,21942,
+12,33,46,21942,
+8,39,42,21942,
+18,33,44,21942,
+7,30,49,21942,
+13,34,45,21942,
+11,27,50,21942,
+18,25,49,21942,
+3,35,46,21942,
+1,18,55,21942,
+10,15,55,21942,
+25,31,42,21942,
+15,38,41,21942,
+1,10,57,21942,
+15,25,50,21942,
+6,17,55,21942,
+3,29,50,21942,
+10,21,53,21942,
+10,35,45,21942,
+22,29,45,21942,
+19,35,42,21942,
+30,35,35,21977,
+6,20,54,21977,
+30,34,36,21992,
+12,38,42,21992,
+18,18,52,21992,
+12,20,53,21992,
+27,32,40,21992,
+2,18,55,21992,
+5,32,48,21992,
+26,34,39,21992,
+11,36,44,21992,
+9,34,46,21992,
+2,10,57,21992,
+18,23,50,21992,
+24,29,44,21992,
+16,17,53,21992,
+13,28,49,21992,
+7,37,44,21992,
+4,23,53,21992,
+11,32,47,21992,
+7,13,56,21992,
+5,25,52,21992,
+17,19,52,21992,
+23,35,40,21992,
+31,32,37,22011,
+19,28,47,22011,
+11,23,52,22011,
+15,23,51,22011,
+5,9,57,22011,
+5,27,51,22011,
+15,27,49,22011,
+0,21,54,22011,
+4,35,46,22011,
+22,32,43,22011,
+5,14,56,22011,
+18,27,48,22011,
+14,35,44,22011,
+8,38,43,22011,
+4,29,50,22011,
+20,29,46,22011,
+13,22,52,22011,
+10,11,56,22011,
+6,36,45,22011,
+8,22,53,22011,
+3,18,55,22011,
+9,19,54,22011,
+30,33,37,22047,
+15,37,42,22047,
+3,10,57,22047,
+1,21,54,22047,
+9,26,51,22047,
+15,18,53,22047,
+16,20,52,22047,
+20,32,44,22047,
+2,21,54,22047,
+0,15,56,22047,
+11,18,54,22047,
+24,24,47,22047,
+9,24,52,22047,
+21,34,42,22047,
+9,12,56,22047,
+19,20,51,22047,
+8,33,47,22047,
+29,35,36,22090,
+0,31,49,22090,
+0,41,41,22090,
+12,37,43,22090,
+9,40,41,22090,
+7,8,57,22090,
+1,15,56,22090,
+27,28,43,22090,
+9,16,55,22090,
+23,23,48,22090,
+17,35,43,22090,
+29,29,41,22090,
+7,17,55,22090,
+5,23,53,22090,
+1,41,41,22090,
+23,25,47,22090,
+11,29,49,22090,
+1,31,49,22090,
+25,37,37,22090,
+13,13,55,22090,
+0,40,42,22090,
+22,24,48,22090,
+24,32,42,22090,
+0,0,58,22090,
+6,32,48,22090,
+23,30,44,22090,
+25,36,38,22090,
+1,40,42,22090,
+4,18,55,22090,
+4,10,57,22090,
+2,15,56,22090,
+8,30,49,22090,
+12,14,55,22090,
+0,1,58,22090,
+28,30,41,22090,
+17,24,50,22090,
+20,38,39,22090,
+15,32,46,22090,
+16,30,47,22090,
+0,34,47,22090,
+26,33,40,22090,
+9,28,50,22090,
+6,25,52,22090,
+7,20,54,22090,
+10,31,48,22090,
+23,34,41,22090,
+9,39,42,22090,
+18,39,39,22090,
+19,34,43,22090,
+14,19,53,22090,
+21,30,45,22090,
+17,26,49,22090,
+5,35,46,22090,
+25,25,46,22090,
+2,41,41,22090,
+6,27,51,22090,
+14,31,47,22090,
+1,34,47,22090,
+31,31,38,22107,
+6,9,57,22107,
+26,29,43,22107,
+18,21,51,22107,
+1,1,58,22107,
+2,31,49,22107,
+29,34,37,22107,
+15,15,54,22107,
+17,31,46,22107,
+3,21,54,22107,
+5,29,50,22107,
+2,40,42,22107,
+6,14,56,22107,
+30,32,38,22131,
+24,26,46,22131,
+18,38,40,22131,
+14,16,54,22131,
+0,2,58,22131,
+1,2,58,22131,
+2,34,47,22131,
+8,13,56,22131,
+20,37,40,22131,
+22,22,49,22131,
+8,37,44,22131,
+22,26,47,22131,
+13,40,40,22131,
+15,29,48,22131,
+21,25,48,22131,
+0,39,43,22131,
+0,11,57,22131,
+16,33,45,22131,
+15,21,52,22131,
+3,15,56,22131,
+15,36,43,22131,
+7,36,45,22131,
+12,25,51,22131,
+11,15,55,22131,
+21,23,49,22131,
+11,21,53,22131,
+3,31,49,22131,
+1,11,57,22131,
+27,31,41,22131,
+1,39,43,22131,
+3,41,41,22131,
+25,35,39,22131,
+11,35,45,22131,
+13,39,41,22131,
+10,34,46,22131,
+14,26,50,22131,
+2,2,58,22131,
+22,38,38,22131,
+14,24,51,22131,
+18,32,45,22131,
+12,27,50,22131,
+0,3,58,22131,
+3,40,42,22131,
+4,21,54,22131,
+13,30,48,22131,
+29,33,38,22184,
+18,37,41,22184,
+9,38,43,22184,
+25,30,43,22184,
+22,37,39,22184,
+13,33,46,22184,
+23,27,46,22184,
+2,11,57,22184,
+17,22,51,22184,
+6,23,53,22184,
+13,17,54,22184,
+5,18,55,22184,
+2,39,43,22184,
+1,3,58,22184,
+5,10,57,22184,
+9,22,53,22184,
+18,29,47,22184,
+3,34,47,22184,
+12,36,44,22184,
+28,36,36,22191,
+6,29,50,22191,
+14,34,45,22191,
+12,23,52,22191,
+2,3,58,22191,
+10,19,54,22191,
+7,32,48,22191,
+6,35,46,22191,
+12,32,47,22191,
+20,36,41,22191,
+10,26,51,22191,
+8,8,57,22191,
+17,28,48,22191,
+20,24,49,22191,
+4,15,56,22191,
+19,30,46,22191,
+26,26,45,22191,
+16,39,40,22191,
+13,38,42,22191,
+4,41,41,22191,
+8,17,55,22191,
+7,25,52,22191,
+13,20,53,22191,
+11,11,56,22191,
+4,31,49,22191,
+28,35,37,22213,
+25,27,45,22213,
+21,33,43,22213,
+3,11,57,22213,
+21,27,47,22213,
+3,39,43,22213,
+7,27,51,22213,
+9,33,47,22213,
+7,9,57,22213,
+0,4,58,22213,
+8,20,54,22213,
+22,36,40,22213,
+10,24,52,22213,
+10,12,56,22213,
+0,26,52,22213,
+20,26,48,22213,
+4,40,42,22213,
+0,38,44,22213,
+22,31,44,22213,
+14,28,49,22213,
+26,32,41,22213,
+16,25,50,22213,
+17,34,44,22213,
+1,38,44,22213,
+1,4,58,22213,
+4,34,47,22213,
+1,26,52,22213,
+10,16,55,22213,
+25,34,40,22213,
+16,38,41,22213,
+7,14,56,22213,
+10,40,41,22213,
+9,30,49,22213,
+3,3,58,22213,
+21,21,50,22213,
+5,21,54,22213,
+30,31,39,22246,
+23,33,42,22246,
+2,26,52,22246,
+14,22,52,22246,
+28,34,38,22258,
+2,4,58,22258,
+10,28,50,22258,
+22,28,46,22258,
+20,22,50,22258,
+2,38,44,22258,
+12,18,54,22258,
+18,36,42,22258,
+6,10,57,22258,
+10,39,42,22258,
+8,36,45,22258,
+0,28,51,22258,
+0,24,53,22258,
+6,18,55,22258,
+24,28,45,22258,
+9,13,56,22258,
+5,15,56,22258,
+9,37,44,22258,
+15,35,44,22258,
+4,39,43,22258,
+4,11,57,22258,
+1,24,53,22258,
+1,28,51,22258,
+20,31,45,22258,
+19,33,44,22258,
+29,32,39,22282,
+11,31,48,22282,
+16,27,49,22282,
+24,31,43,22282,
+16,23,51,22282,
+0,19,55,22282,
+12,29,49,22282,
+13,37,43,22282,
+5,41,41,22282,
+7,23,53,22282,
+17,17,53,22282,
+5,31,49,22282,
+1,19,55,22282,
+19,25,49,22282,
+16,37,42,22282,
+3,38,44,22282,
+16,18,53,22282,
+5,40,42,22282,
+28,29,42,22282,
+2,24,53,22282,
+18,19,52,22282,
+3,4,58,22282,
+2,28,51,22282,
+0,5,58,22282,
+24,37,38,22282,
+3,26,52,22282,
+20,35,42,22282,
+22,35,41,22282,
+2,19,55,22282,
+7,29,50,22282,
+13,14,55,22282,
+7,35,46,22282,
+1,5,58,22282,
+19,23,50,22282,
+5,34,47,22282,
+8,32,48,22282,
+0,16,56,22282,
+17,20,52,22282,
+11,34,46,22282,
+0,12,57,22282,
+20,28,47,22282,
+8,25,52,22282,
+2,5,58,22282,
+6,21,54,22282,
+0,33,48,22282,
+24,36,39,22303,
+27,30,42,22303,
+1,16,56,22303,
+10,22,53,22303,
+10,38,43,22303,
+27,27,44,22303,
+27,36,37,22351,
+8,27,51,22351,
+28,33,39,22351,
+1,12,57,22351,
+12,21,53,22351,
+8,9,57,22351,
+3,24,53,22351,
+12,35,45,22351,
+19,27,48,22351,
+1,33,48,22351,
+12,15,55,22351,
+0,37,45,22351,
+3,28,51,22351,
+1,37,45,22351,
+5,39,43,22351,
+15,19,53,22351,
+5,11,57,22351,
+9,17,55,22351,
+25,33,41,22351,
+13,25,51,22351,
+15,31,47,22351,
+3,19,55,22351,
+23,29,45,22351,
+4,38,44,22351,
+4,4,58,22351,
+8,14,56,22351,
+4,26,52,22351,
+14,40,40,22351,
+16,32,46,22351,
+2,16,56,22351,
+26,28,44,22351,
+6,15,56,22351,
+2,33,48,22351,
+9,20,54,22351,
+15,16,54,22351,
+2,12,57,22351,
+7,18,55,22351,
+27,35,38,22380,
+13,27,50,22380,
+11,19,54,22380,
+17,30,47,22380,
+7,10,57,22380,
+18,35,43,22380,
+10,33,47,22380,
+11,26,51,22380,
+14,39,41,22380,
+6,41,41,22380,
+21,29,46,22380,
+2,37,45,22380,
+3,5,58,22380,
+6,31,49,22380,
+0,22,54,22380,
+0,30,50,22380,
+18,24,50,22380,
+30,30,40,22394,
+6,40,42,22394,
+0,6,58,22394,
+14,30,48,22394,
+20,20,51,22394,
+4,24,53,22394,
+14,33,46,22394,
+11,12,56,22394,
+21,32,44,22394,
+1,6,58,22394,
+26,31,42,22394,
+1,30,50,22394,
+14,17,54,22394,
+24,35,40,22394,
+6,34,47,22394,
+3,16,56,22394,
+11,24,52,22394,
+33,34,34,22430,
+18,26,49,22430,
+16,21,52,22430,
+18,31,46,22430,
+16,36,43,22430,
+13,36,44,22430,
+4,28,51,22430,
+15,26,50,22430,
+16,29,48,22430,
+10,30,49,22430,
+1,22,54,22430,
+3,12,57,22430,
+8,23,53,22430,
+3,33,48,22430,
+25,29,44,22430,
+9,36,45,22430,
+4,19,55,22430,
+13,23,52,22430,
+13,32,47,22430,
+11,40,41,22430,
+11,16,55,22430,
+23,32,43,22430,
+15,24,51,22430,
+29,31,40,22430,
+17,33,45,22430,
+33,33,35,22455,
+19,39,39,22455,
+19,21,51,22455,
+3,37,45,22455,
+2,6,58,22455,
+22,34,42,22455,
+2,30,50,22455,
+2,22,54,22455,
+14,38,42,22455,
+14,20,53,22455,
+8,29,50,22455,
+11,28,50,22455,
+32,34,35,22481,
+4,5,58,22481,
+5,26,52,22481,
+19,38,40,22481,
+8,35,46,22481,
+20,34,43,22481,
+10,37,44,22481,
+5,38,44,22481,
+10,13,56,22481,
+11,39,42,22481,
+15,34,45,22481,
+21,38,39,22481,
+6,11,57,22481,
+27,34,39,22481,
+6,39,43,22481,
+7,21,54,22481,
+28,32,40,22481,
+4,16,56,22481,
+3,22,54,22481,
+3,6,58,22481,
+22,30,45,22481,
+4,12,57,22481,
+18,22,51,22481,
+9,32,48,22481,
+32,33,36,22514,
+23,24,48,22514,
+4,33,48,22514,
+13,18,54,22514,
+3,30,50,22514,
+12,31,48,22514,
+15,28,49,22514,
+4,37,45,22514,
+24,25,47,22514,
+19,32,45,22514,
+21,37,40,22514,
+7,15,56,22514,
+5,24,53,22514,
+17,39,40,22514,
+9,25,52,22514,
+5,28,51,22514,
+7,41,41,22514,
+5,19,55,22514,
+31,35,35,22535,
+9,27,51,22535,
+13,29,49,22535,
+9,9,57,22535,
+19,29,47,22535,
+19,37,41,22535,
+7,31,49,22535,
+0,36,46,22535,
+24,30,44,22535,
+18,28,48,22535,
+8,10,57,22535,
+24,34,41,22535,
+9,14,56,22535,
+15,22,52,22535,
+31,34,36,22549,
+7,40,42,22549,
+8,18,55,22549,
+22,25,48,22549,
+1,36,46,22549,
+25,32,42,22549,
+0,7,58,22549,
+1,7,58,22549,
+7,34,47,22549,
+23,26,47,22549,
+17,38,41,22549,
+5,5,58,22549,
+14,37,43,22549,
+26,37,37,22549,
+11,38,43,22549,
+22,23,49,22549,
+11,22,53,22549,
+10,17,55,22549,
+17,25,50,22549,
+10,20,54,22549,
+4,6,58,22549,
+12,34,46,22549,
+26,36,38,22549,
+20,30,46,22549,
+6,38,44,22549,
+4,22,54,22549,
+18,34,44,22549,
+4,30,50,22549,
+2,36,46,22549,
+6,26,52,22549,
+32,32,37,22576,
+28,28,43,22576,
+16,35,44,22576,
+23,38,38,22576,
+14,14,55,22576,
+25,26,46,22576,
+5,16,56,22576,
+2,7,58,22576,
+5,12,57,22576,
+5,33,48,22576,
+21,36,41,22576,
+27,33,40,22576,
+0,13,57,22576,
+21,24,49,22576,
+17,27,49,22576,
+13,15,55,22576,
+23,37,39,22576,
+31,33,37,22606,
+13,21,53,22606,
+27,29,43,22606,
+7,39,43,22606,
+17,23,51,22606,
+1,13,57,22606,
+13,35,45,22606,
+5,37,45,22606,
+7,11,57,22606,
+11,33,47,22606,
+9,23,53,22606,
+12,19,54,22606,
+21,26,48,22606,
+10,36,45,22606,
+6,24,53,22606,
+6,28,51,22606,
+24,27,46,22606,
+30,35,36,22613,
+3,36,46,22613,
+12,26,51,22613,
+19,36,42,22613,
+8,21,54,22613,
+14,25,51,22613,
+29,30,41,22613,
+22,33,43,22613,
+2,13,57,22613,
+17,37,42,22613,
+9,35,46,22613,
+3,7,58,22613,
+6,19,55,22613,
+22,27,47,22613,
+17,18,53,22613,
+11,30,49,22613,
+26,35,39,22613,
+9,29,50,22613,
+12,24,52,22613,
+12,12,56,22613,
+12,16,55,22613,
+5,30,50,22613,
+26,30,43,22613,
+23,36,40,22613,
+30,34,37,22632,
+8,15,56,22632,
+12,40,41,22632,
+20,33,44,22632,
+15,40,40,22632,
+5,22,54,22632,
+0,32,49,22632,
+0,17,56,22632,
+14,27,50,22632,
+21,22,50,22632,
+0,20,55,22632,
+5,6,58,22632,
+28,31,41,22632,
+11,13,56,22632,
+1,32,49,22632,
+20,25,49,22632,
+16,31,47,22632,
+1,20,55,22632,
+8,41,41,22632,
+23,31,44,22632,
+1,17,56,22632,
+19,19,52,22632,
+11,37,44,22632,
+8,31,49,22632,
+16,19,53,22632,
+3,13,57,22632,
+15,39,41,22632,
+21,31,45,22632,
+12,28,50,22632,
+6,16,56,22632,
+14,36,44,22632,
+8,40,42,22632,
+0,8,58,22632,
+16,16,54,22632,
+18,20,52,22632,
+4,36,46,22632,
+10,32,48,22632,
+31,32,38,22669,
+8,34,47,22669,
+12,39,42,22669,
+24,33,42,22669,
+10,25,52,22669,
+7,38,44,22669,
+6,33,48,22669,
+2,32,49,22669,
+2,20,55,22669,
+4,7,58,22669,
+7,26,52,22669,
+23,28,46,22669,
+14,32,47,22669,
+17,32,46,22669,
+20,23,50,22669,
+2,17,56,22669,
+15,30,48,22669,
+1,8,58,22669,
+14,23,52,22669,
+6,12,57,22669,
+15,17,54,22669,
+15,33,46,22669,
+26,27,45,22669,
+9,10,57,22669,
+6,37,45,22669,
+21,35,42,22669,
+10,27,51,22669,
+9,18,55,22669,
+16,26,50,22669,
+10,14,56,22669,
+26,34,40,22669,
+2,8,58,22669,
+0,27,52,22669,
+29,36,36,22711,
+18,30,47,22711,
+15,38,42,22711,
+16,24,51,22711,
+20,27,48,22711,
+30,33,38,22711,
+17,21,52,22711,
+15,20,53,22711,
+4,13,57,22711,
+7,24,53,22711,
+3,20,55,22711,
+27,32,41,22711,
+3,32,49,22711,
+3,17,56,22711,
+0,35,47,22711,
+7,28,51,22711,
+17,29,48,22711,
+17,36,43,22711,
+0,25,53,22711,
+21,28,47,22711,
+8,39,43,22711,
+8,11,57,22711,
+1,27,52,22711,
+25,28,45,22711,
+13,31,48,22711,
+7,19,55,22711,
+1,25,53,22711,
+25,31,43,22711,
+1,35,47,22711,
+23,35,41,22711,
+29,35,37,22734,
+11,17,55,22734,
+19,35,43,22734,
+6,30,50,22734,
+6,22,54,22734,
+14,18,54,22734,
+6,6,58,22734,
+11,20,54,22734,
+2,27,52,22734,
+5,36,46,22734,
+12,22,53,22734,
+3,8,58,22734,
+19,24,50,22734,
+12,38,43,22734,
+16,34,45,22734,
+25,37,38,22734,
+2,25,53,22734,
+5,7,58,22734,
+14,29,49,22734,
+19,26,49,22734,
+19,31,46,22734,
+10,23,53,22734,
+2,35,47,22734,
+18,33,45,22734,
+9,21,54,22734,
+4,20,55,22734,
+29,34,38,22777,
+13,34,46,22777,
+4,32,49,22777,
+7,16,56,22777,
+10,29,50,22777,
+4,17,56,22777,
+10,35,46,22777,
+22,29,46,22777,
+16,28,49,22777,
+20,21,51,22777,
+25,36,39,22777,
+20,39,39,22777,
+7,33,48,22777,
+12,33,47,22777,
+11,36,45,22777,
+7,12,57,22777,
+0,29,51,22777,
+9,15,56,22777,
+24,29,45,22777,
+3,27,52,22777,
+5,13,57,22777,
+1,29,51,22777,
+31,31,39,22794,
+3,25,53,22794,
+9,41,41,22794,
+3,35,47,22794,
+15,37,43,22794,
+7,37,45,22794,
+9,31,49,22794,
+20,38,40,22794,
+8,26,52,22794,
+4,8,58,22794,
+22,32,44,22794,
+8,38,44,22794,
+16,22,52,22794,
+30,32,39,22822,
+0,41,42,22822,
+0,9,58,22822,
+18,39,40,22822,
+0,23,54,22822,
+12,30,49,22822,
+0,14,57,22822,
+9,40,42,22822,
+14,35,45,22822,
+13,26,51,22822,
+21,34,43,22822,
+19,22,51,22822,
+13,19,54,22822,
+14,21,53,22822,
+1,14,57,22822,
+26,33,41,22822,
+1,23,54,22822,
+1,9,58,22822,
+29,29,42,22822,
+1,41,42,22822,
+9,34,47,22822,
+14,15,55,22822,
+2,29,51,22822,
+28,30,42,22822,
+6,36,46,22822,
+7,22,54,22822,
+12,37,44,22822,
+2,23,54,22822,
+23,34,42,22822,
+11,32,48,22822,
+8,28,51,22822,
+22,38,39,22822,
+6,7,58,22822,
+2,14,57,22822,
+10,10,57,22822,
+10,18,55,22822,
+4,27,52,22822,
+2,41,42,22822,
+7,30,50,22822,
+18,38,41,22822,
+13,24,52,22822,
+28,36,37,22842,
+19,28,48,22842,
+8,24,53,22842,
+27,28,44,22842,
+24,32,43,22842,
+20,32,45,22842,
+12,13,56,22842,
+0,40,43,22842,
+18,25,50,22842,
+2,9,58,22842,
+5,20,55,22842,
+25,35,40,22842,
+13,40,41,22842,
+11,25,52,22842,
+5,32,49,22842,
+17,35,44,22842,
+8,19,55,22842,
+4,35,47,22842,
+13,16,55,22842,
+1,40,43,22842,
+5,17,56,22842,
+20,37,41,22842,
+4,25,53,22842,
+20,29,47,22842,
+3,29,51,22842,
+9,11,57,22842,
+15,25,51,22842,
+9,39,43,22842,
+29,33,39,22862,
+11,27,51,22862,
+11,14,56,22862,
+28,35,38,22886,
+19,34,44,22886,
+13,28,50,22886,
+26,29,44,22886,
+22,37,40,22886,
+5,8,58,22886,
+2,40,43,22886,
+13,39,42,22886,
+3,9,58,22886,
+27,31,42,22886,
+3,14,57,22886,
+6,13,57,22886,
+15,27,50,22886,
+3,23,54,22886,
+3,41,42,22886,
+23,30,45,22886,
+18,27,49,22886,
+18,23,51,22886,
+16,40,40,22886,
+24,24,48,22886,
+8,16,56,22886,
+18,37,42,22886,
+18,18,53,22886,
+8,12,57,22886,
+15,36,44,22886,
+0,39,44,22886,
+8,33,48,22886,
+10,21,54,22886,
+21,30,46,22886,
+8,37,45,22886,
+16,39,41,22886,
+3,40,43,22886,
+15,32,47,22886,
+5,27,52,22886,
+12,17,55,22886,
+1,39,44,22886,
+4,29,51,22886,
+23,25,48,22886,
+15,23,52,22886,
+17,19,53,22886,
+23,23,49,22886,
+5,25,53,22886,
+17,31,47,22886,
+11,23,53,22886,
+25,25,47,22886,
+5,35,47,22886,
+0,18,56,22886,
+0,34,48,22886,
+16,30,48,22886,
+20,36,42,22886,
+12,20,54,22886,
+9,38,44,22886,
+1,34,48,22886,
+22,24,49,22886,
+6,17,56,22886,
+6,20,55,22886,
+14,31,48,22886,
+22,36,41,22886,
+4,9,58,22886,
+10,15,56,22886,
+1,18,56,22886,
+4,14,57,22886,
+28,34,39,22955,
+24,26,47,22955,
+16,17,54,22955,
+4,41,42,22955,
+16,33,46,22955,
+6,32,49,22955,
+7,36,46,22955,
+2,39,44,22955,
+9,26,52,22955,
+30,31,40,22955,
+25,30,44,22955,
+0,31,50,22955,
+4,23,54,22955,
+1,31,50,22955,
+11,29,50,22955,
+25,34,41,22955,
+13,38,43,22955,
+10,41,41,22955,
+11,35,46,22955,
+10,31,49,22955,
+13,22,53,22955,
+7,7,58,22955,
+8,30,50,22955,
+16,38,42,22955,
+2,34,48,22955,
+2,18,56,22955,
+26,32,42,22955,
+22,26,48,22955,
+24,38,38,22955,
+0,10,58,22955,
+18,32,46,22955,
+10,40,42,22955,
+8,22,54,22955,
+6,8,58,22955,
+17,26,50,22955,
+1,10,58,22955,
+4,40,43,22955,
+29,32,40,22996,
+12,36,45,22996,
+19,20,52,22996,
+10,34,47,22996,
+16,20,53,22996,
+2,31,50,22996,
+15,18,54,22996,
+17,24,51,22996,
+0,21,55,22996,
+3,39,44,22996,
+21,33,44,22996,
+24,37,39,22996,
+9,28,51,22996,
+9,24,53,22996,
+15,29,49,22996,
+1,21,55,22996,
+23,27,47,22996,
+7,13,57,22996,
+5,29,51,22996,
+23,33,43,22996,
+13,33,47,22996,
+9,19,55,22996,
+27,37,37,23007,
+21,25,49,23007,
+34,34,34,23040,
+22,22,50,23040,
+2,10,58,23040,
+14,34,46,23040,
+26,26,46,23040,
+6,27,52,23040,
+3,34,48,23040,
+18,29,48,23040,
+18,21,52,23040,
+18,36,43,23040,
+3,18,56,23040,
+27,36,38,23040,
+0,38,45,23040,
+10,39,43,23040,
+5,9,58,23040,
+5,41,42,23040,
+3,31,50,23040,
+19,30,47,23040,
+6,25,53,23040,
+5,23,54,23040,
+6,35,47,23040,
+5,14,57,23040,
+17,34,45,23040,
+21,23,50,23040,
+2,21,55,23040,
+10,11,57,23040,
+11,18,55,23040,
+13,30,49,23040,
+1,38,45,23040,
+33,34,35,23072,
+25,27,46,23072,
+22,31,45,23072,
+24,36,40,23072,
+12,32,48,23072,
+9,16,56,23072,
+2,38,45,23072,
+14,19,54,23072,
+12,25,52,23072,
+3,10,58,23072,
+22,35,42,23072,
+24,31,44,23072,
+4,39,44,23072,
+14,26,51,23072,
+28,33,40,23072,
+7,20,55,23072,
+0,15,57,23072,
+16,37,43,23072,
+9,12,57,23072,
+13,37,44,23072,
+28,29,43,23072,
+33,33,36,23113,
+17,28,49,23113,
+13,13,56,23113,
+21,27,48,23113,
+32,35,35,23113,
+12,27,51,23113,
+20,35,43,23113,
+7,17,56,23113,
+5,40,43,23113,
+9,33,48,23113,
+7,32,49,23113,
+27,35,39,23113,
+15,15,55,23113,
+1,15,57,23113,
+15,35,45,23113,
+3,21,55,23113,
+9,37,45,23113,
+15,21,53,23113,
+19,33,45,23113,
+4,34,48,23113,
+32,34,36,23122,
+4,18,56,23122,
+20,24,50,23122,
+12,14,56,23122,
+8,36,46,23122,
+24,28,46,23122,
+14,24,52,23122,
+22,28,47,23122,
+14,16,55,23122,
+17,22,52,23122,
+14,40,41,23122,
+20,31,46,23122,
+4,31,50,23122,
+7,8,58,23122,
+20,26,49,23122,
+27,30,43,23122,
+25,33,42,23122,
+6,29,51,23122,
+2,15,57,23122,
+3,38,45,23122,
+11,21,54,23122,
+10,38,44,23122,
+14,28,50,23122,
+10,26,52,23122,
+4,10,58,23122,
+6,41,42,23122,
+9,22,54,23122,
+30,30,41,23139,
+6,23,54,23139,
+6,9,58,23139,
+14,39,42,23139,
+6,14,57,23139,
+9,30,50,23139,
+0,0,59,23139,
+24,35,41,23139,
+11,15,56,23139,
+19,39,40,23139,
+12,23,53,23139,
+4,21,55,23139,
+16,25,51,23139,
+32,33,37,23184,
+5,39,44,23184,
+7,27,52,23184,
+0,1,59,23184,
+31,35,36,23184,
+8,13,57,23184,
+1,1,59,23184,
+21,39,39,23184,
+7,35,47,23184,
+11,41,41,23184,
+27,27,45,23184,
+21,21,51,23184,
+11,31,49,23184,
+7,25,53,23184,
+29,31,41,23184,
+13,17,55,23184,
+3,15,57,23184,
+18,35,44,23184,
+12,35,46,23184,
+12,29,50,23184,
+0,37,46,23184,
+6,40,43,23184,
+16,27,50,23184,
+0,11,58,23184,
+4,38,45,23184,
+0,26,53,23184,
+5,18,56,23184,
+10,24,53,23184,
+21,38,40,23184,
+0,2,59,23184,
+27,34,40,23184,
+13,20,54,23184,
+20,22,51,23184,
+10,28,51,23184,
+5,34,48,23184,
+11,40,42,23184,
+26,28,45,23184,
+31,34,37,23220,
+1,26,53,23220,
+1,2,59,23220,
+5,31,50,23220,
+19,38,41,23220,
+10,19,55,23220,
+23,29,46,23220,
+1,11,58,23220,
+19,25,50,23220,
+26,31,43,23220,
+11,34,47,23220,
+1,37,46,23220,
+16,36,44,23220,
+20,28,48,23220,
+0,28,52,23220,
+28,32,41,23220,
+16,32,47,23220,
+2,37,46,23220,
+2,2,59,23220,
+8,20,55,23220,
+8,32,49,23220,
+14,22,53,23220,
+5,10,58,23220,
+26,37,38,23220,
+8,17,56,23220,
+14,38,43,23220,
+2,26,53,23220,
+16,23,52,23220,
+17,40,40,23220,
+23,32,44,23220,
+22,34,43,23220,
+2,11,58,23220,
+1,28,52,23220,
+21,32,45,23220,
+15,31,48,23220,
+4,15,57,23220,
+0,3,59,23220,
+0,33,49,23220,
+13,36,45,23220,
+21,29,47,23220,
+5,21,55,23220,
+11,11,57,23220,
+19,23,51,23220,
+7,29,51,23220,
+1,33,49,23220,
+25,29,45,23220,
+11,39,43,23220,
+17,39,41,23220,
+1,3,59,23220,
+19,27,49,23220,
+21,37,41,23220,
+30,36,36,23260,
+2,28,52,23260,
+20,34,44,23260,
+8,8,58,23260,
+10,16,56,23260,
+32,32,38,23260,
+0,24,54,23260,
+26,36,39,23260,
+17,30,48,23260,
+10,33,48,23260,
+10,12,57,23260,
+9,36,46,23260,
+6,39,44,23260,
+12,18,55,23260,
+1,24,54,23260,
+3,11,58,23260,
+23,38,39,23260,
+3,26,53,23260,
+5,38,45,23260,
+17,17,54,23260,
+7,14,57,23260,
+2,33,49,23260,
+18,19,53,23260,
+3,37,46,23260,
+7,41,42,23260,
+31,33,38,23282,
+2,3,59,23282,
+17,33,46,23282,
+19,37,42,23282,
+10,37,45,23282,
+14,33,47,23282,
+7,9,58,23282,
+30,35,37,23282,
+18,31,47,23282,
+7,23,54,23282,
+16,18,54,23282,
+2,24,54,23282,
+6,18,56,23282,
+24,34,42,23282,
+6,34,48,23282,
+8,27,52,23282,
+14,30,49,23282,
+0,19,56,23282,
+0,4,59,23282,
+3,28,52,23282,
+13,32,48,23282,
+17,38,42,23282,
+6,31,50,23282,
+15,34,46,23282,
+17,20,53,23282,
+23,37,40,23282,
+16,29,49,23282,
+25,32,43,23282,
+8,35,47,23282,
+1,4,59,23282,
+8,25,53,23282,
+1,19,56,23282,
+7,40,43,23282,
+13,25,52,23282,
+3,3,59,23282,
+9,13,57,23282,
+27,33,41,23290,
+5,15,57,23290,
+3,33,49,23290,
+13,27,51,23290,
+10,22,54,23290,
+30,34,38,23321,
+18,26,50,23321,
+6,10,58,23321,
+10,30,50,23321,
+22,30,46,23321,
+24,30,45,23321,
+0,30,51,23321,
+14,37,44,23321,
+2,19,56,23321,
+26,35,40,23321,
+3,24,54,23321,
+11,26,52,23321,
+11,38,44,23321,
+4,11,58,23321,
+19,32,46,23321,
+13,14,56,23321,
+4,37,46,23321,
+21,36,42,23321,
+4,26,53,23321,
+2,4,59,23321,
+18,24,51,23321,
+12,21,54,23321,
+6,21,55,23321,
+15,26,51,23321,
+15,19,54,23321,
+1,30,51,23321,
+4,28,52,23321,
+28,28,44,23321,
+20,20,52,23321,
+24,25,48,23321,
+0,16,57,23321,
+2,30,51,23321,
+18,34,45,23321,
+6,38,45,23321,
+12,15,56,23321,
+29,30,42,23331,
+15,24,52,23331,
+0,36,47,23331,
+3,4,59,23331,
+11,28,51,23331,
+19,21,52,23331,
+31,32,39,23394,
+11,24,53,23394,
+12,31,49,23394,
+9,20,55,23394,
+1,36,47,23394,
+19,36,43,23394,
+15,40,41,23394,
+16,21,53,23394,
+4,33,49,23394,
+23,36,41,23394,
+9,17,56,23394,
+8,29,51,23394,
+1,16,57,23394,
+0,5,59,23394,
+16,35,45,23394,
+9,32,49,23394,
+3,19,56,23394,
+7,39,44,23394,
+19,29,48,23394,
+29,36,37,23394,
+27,29,44,23394,
+23,24,49,23394,
+15,16,55,23394,
+12,41,41,23394,
+13,23,53,23394,
+11,19,55,23394,
+17,37,43,23394,
+1,5,59,23394,
+0,12,58,23394,
+4,24,54,23394,
+12,40,42,23394,
+15,28,50,23394,
+20,30,47,23394,
+22,33,44,23394,
+18,28,49,23394,
+2,16,57,23394,
+7,34,48,23394,
+23,26,48,23394,
+28,31,42,23394,
+7,18,56,23394,
+8,14,57,23394,
+12,34,47,23394,
+2,36,47,23394,
+1,12,58,23394,
+8,41,42,23394,
+8,23,54,23394,
+8,9,58,23394,
+0,22,55,23394,
+29,35,38,23430,
+14,17,55,23430,
+5,26,53,23430,
+13,29,50,23430,
+2,5,59,23430,
+13,35,46,23430,
+22,25,49,23430,
+6,15,57,23430,
+15,39,42,23430,
+5,37,46,23430,
+7,31,50,23430,
+5,11,58,23430,
+3,30,51,23430,
+30,33,39,23430,
+25,26,47,23430,
+1,22,55,23430,
+10,36,46,23430,
+14,20,54,23430,
+26,30,44,23430,
+2,12,58,23430,
+18,22,52,23430,
+5,28,52,23430,
+25,38,38,23430,
+26,34,41,23430,
+4,19,56,23430,
+11,16,56,23430,
+4,4,59,23430,
+8,40,43,23430,
+22,23,50,23430,
+2,22,55,23430,
+7,10,58,23430,
+11,12,57,23430,
+24,33,43,23430,
+3,36,47,23430,
+12,39,43,23430,
+11,33,48,23430,
+20,33,45,23430,
+24,27,47,23430,
+3,16,57,23430,
+9,27,52,23430,
+7,21,55,23430,
+25,37,39,23436,
+23,31,45,23436,
+3,5,59,23436,
+21,35,43,23436,
+17,25,51,23436,
+5,33,49,23436,
+9,25,53,23436,
+9,35,47,23436,
+11,37,45,23436,
+5,24,54,23436,
+21,24,50,23436,
+4,30,51,23436,
+27,32,42,23451,
+22,27,48,23451,
+3,12,58,23451,
+0,6,59,23451,
+14,36,45,23451,
+13,18,55,23451,
+21,31,46,23451,
+21,26,49,23451,
+17,27,50,23451,
+10,13,57,23451,
+23,35,42,23451,
+3,22,55,23451,
+15,22,53,23451,
+1,6,59,23451,
+15,38,43,23451,
+7,38,45,23451,
+29,34,39,23482,
+17,36,44,23482,
+6,37,46,23482,
+16,31,48,23482,
+26,27,46,23482,
+11,22,54,23482,
+20,39,40,23482,
+25,36,40,23482,
+4,16,57,23482,
+6,11,58,23482,
+8,39,44,23482,
+11,30,50,23482,
+2,6,59,23482,
+6,26,53,23482,
+4,36,47,23482,
+25,31,44,23482,
+23,28,47,23482,
+17,32,47,23482,
+4,5,59,23482,
+17,23,52,23482,
+28,37,37,23522,
+31,31,40,23522,
+19,35,44,23522,
+5,19,56,23522,
+9,29,51,23522,
+15,33,47,23522,
+7,15,57,23522,
+8,34,48,23522,
+18,40,40,23522,
+0,32,50,23522,
+8,18,56,23522,
+6,28,52,23522,
+12,38,44,23522,
+4,12,58,23522,
+28,36,38,23534,
+12,26,52,23534,
+14,32,48,23534,
+30,32,40,23534,
+10,17,56,23534,
+1,32,50,23534,
+8,31,50,23534,
+4,22,55,23534,
+10,20,55,23534,
+14,25,52,23534,
+20,38,41,23534,
+25,28,46,23534,
+20,25,50,23534,
+10,32,49,23534,
+14,27,51,23534,
+5,30,51,23534,
+21,22,51,23534,
+9,23,54,23534,
+9,9,58,23534,
+18,39,41,23534,
+22,39,39,23534,
+15,30,49,23534,
+9,41,42,23534,
+3,6,59,23534,
+13,21,54,23534,
+9,14,57,23534,
+6,33,49,23534,
+22,38,40,23534,
+18,30,48,23534,
+6,24,54,23534,
+8,10,58,23534,
+0,42,42,23534,
+2,32,50,23534,
+16,34,46,23534,
+14,14,56,23534,
+12,28,51,23534,
+17,18,54,23534,
+18,33,46,23534,
+0,35,48,23534,
+21,28,48,23534,
+1,42,42,23534,
+26,33,42,23544,
+12,24,53,23544,
+13,15,56,23544,
+20,23,51,23544,
+29,33,40,23592,
+0,41,43,23592,
+20,27,49,23592,
+5,36,47,23592,
+28,35,39,23592,
+5,16,57,23592,
+0,7,59,23592,
+12,19,55,23592,
+9,40,43,23592,
+15,37,44,23592,
+1,35,48,23592,
+8,21,55,23592,
+1,41,43,23592,
+29,29,43,23592,
+5,5,59,23592,
+19,19,53,23592,
+19,31,47,23592,
+17,29,49,23592,
+25,35,41,23592,
+13,31,49,23592,
+13,41,41,23592,
+1,7,59,23592,
+2,42,42,23592,
+18,38,42,23592,
+20,37,42,23592,
+2,35,48,23592,
+22,32,45,23592,
+24,29,46,23592,
+16,26,51,23592,
+28,30,43,23592,
+3,32,50,23592,
+5,12,58,23592,
+11,36,46,23592,
+6,19,56,23592,
+4,6,59,23592,
+16,19,54,23592,
+21,34,44,23592,
+18,20,53,23592,
+10,27,52,23592,
+0,13,58,23592,
+13,40,42,23592,
+8,38,45,23592,
+7,37,46,23592,
+22,37,41,23592,
+7,11,58,23592,
+14,23,53,23592,
+10,25,53,23592,
+2,41,43,23592,
+2,7,59,23592,
+22,29,47,23592,
+1,13,58,23592,
+13,34,47,23592,
+23,34,43,23592,
+7,26,53,23592,
+5,22,55,23592,
+10,35,47,23592,
+0,40,44,23592,
+12,16,56,23592,
+24,32,44,23592,
+0,20,56,23592,
+16,24,52,23592,
+19,26,50,23592,
+14,29,50,23592,
+3,42,42,23592,
+12,12,57,23592,
+1,20,56,23592,
+12,33,48,23592,
+1,40,44,23592,
+7,28,52,23592,
+16,16,55,23592,
+2,13,58,23592,
+14,35,46,23592,
+6,30,51,23592,
+16,40,41,23592,
+34,34,35,23671,
+8,15,57,23671,
+19,24,51,23671,
+9,39,44,23671,
+27,28,45,23671,
+0,17,57,23671,
+3,35,48,23671,
+12,37,45,23671,
+0,27,53,23671,
+11,13,57,23671,
+13,39,43,23671,
+33,35,35,23691,
+17,21,53,23691,
+3,41,43,23691,
+1,17,57,23691,
+3,7,59,23691,
+15,17,55,23691,
+7,33,49,23691,
+17,35,45,23691,
+1,27,53,23691,
+27,31,43,23691,
+20,32,46,23691,
+2,20,56,23691,
+4,32,50,23691,
+28,34,40,23691,
+2,40,44,23691,
+16,28,50,23691,
+6,36,47,23691,
+24,38,39,23691,
+0,25,54,23691,
+6,16,57,23691,
+9,34,48,23691,
+9,18,56,23691,
+15,20,54,23691,
+33,34,36,23709,
+7,24,54,23709,
+16,39,42,23709,
+26,29,45,23709,
+9,31,50,23709,
+19,34,45,23709,
+2,17,57,23709,
+30,31,41,23709,
+3,13,58,23709,
+27,37,38,23709,
+18,37,43,23709,
+5,6,59,23709,
+10,29,51,23709,
+2,27,53,23709,
+1,25,54,23709,
+12,30,50,23709,
+22,36,42,23709,
+4,42,42,23709,
+12,22,54,23709,
+6,12,58,23709,
+20,21,52,23709,
+14,18,55,23709,
+3,20,56,23709,
+20,29,48,23709,
+10,41,42,23709,
+25,34,42,23709,
+0,8,59,23709,
+23,30,46,23709,
+10,23,54,23709,
+6,22,55,23709,
+20,36,43,23709,
+4,35,48,23709,
+10,14,57,23709,
+9,10,58,23709,
+2,25,54,23709,
+3,40,44,23709,
+24,37,40,23709,
+0,29,52,23709,
+32,35,36,23747,
+4,41,43,23747,
+1,8,59,23747,
+11,32,49,23747,
+11,17,56,23747,
+27,36,39,23747,
+1,29,52,23747,
+0,39,45,23747,
+11,20,55,23747,
+29,32,41,23747,
+15,36,45,23747,
+19,28,49,23747,
+4,7,59,23747,
+7,19,56,23747,
+1,39,45,23747,
+9,21,55,23747,
+33,33,37,23767,
+3,27,53,23767,
+3,17,57,23767,
+13,38,44,23767,
+5,32,50,23767,
+4,13,58,23767,
+2,8,59,23767,
+8,11,58,23767,
+16,22,53,23767,
+16,38,43,23767,
+2,29,52,23767,
+19,22,52,23767,
+26,32,43,23767,
+10,40,43,23767,
+8,37,46,23767,
+32,34,37,23777,
+13,26,52,23777,
+8,26,53,23777,
+2,39,45,23777,
+25,30,45,23777,
+21,30,47,23777,
+18,25,51,23777,
+7,30,51,23777,
+9,38,45,23777,
+3,25,54,23777,
+4,40,44,23777,
+8,28,52,23777,
+4,20,56,23777,
+18,27,50,23777,
+14,21,54,23777,
+5,42,42,23777,
+24,36,41,23777,
+31,36,36,23822,
+15,32,48,23822,
+24,24,49,23822,
+6,6,59,23822,
+3,8,59,23822,
+16,33,47,23822,
+23,33,44,23822,
+4,27,53,23822,
+27,35,40,23822,
+3,29,52,23822,
+17,31,48,23822,
+7,36,47,23822,
+13,24,53,23822,
+0,23,55,23822,
+4,17,57,23822,
+28,33,41,23822,
+5,35,48,23822,
+7,16,57,23822,
+15,25,52,23822,
+13,28,51,23822,
+25,25,48,23822,
+8,33,49,23822,
+11,27,52,23822,
+9,15,57,23822,
+5,7,59,23822,
+3,39,45,23822,
+23,25,49,23822,
+11,35,47,23822,
+13,19,55,23822,
+31,35,37,23843,
+11,25,53,23843,
+1,23,55,23843,
+5,41,43,23843,
+21,33,45,23843,
+15,27,51,23843,
+12,36,46,23843,
+18,36,44,23843,
+8,24,54,23843,
+24,26,48,23843,
+18,23,52,23843,
+18,32,47,23843,
+7,12,58,23843,
+14,15,56,23843,
+4,25,54,23843,
+16,30,49,23843,
+32,33,38,23864,
+0,34,49,23864,
+10,39,44,23864,
+22,35,43,23864,
+23,23,50,23864,
+2,23,55,23864,
+14,31,49,23864,
+1,34,49,23864,
+5,13,58,23864,
+14,41,41,23864,
+7,22,55,23864,
+22,24,50,23864,
+6,32,50,23864,
+14,40,42,23864,
+0,38,46,23864,
+10,18,56,23864,
+10,34,48,23864,
+0,14,58,23864,
+5,40,44,23864,
+20,35,44,23864,
+4,29,52,23864,
+4,8,59,23864,
+1,14,58,23864,
+28,29,44,23864,
+17,34,46,23864,
+14,34,47,23864,
+10,31,50,23864,
+1,38,46,23864,
+22,26,49,23864,
+22,31,46,23864,
+19,40,40,23864,
+31,34,38,23882,
+8,19,56,23882,
+5,20,56,23882,
+16,37,44,23882,
+13,16,56,23882,
+26,26,47,23882,
+2,34,49,23882,
+0,31,51,23882,
+12,13,57,23882,
+0,9,59,23882,
+23,27,48,23882,
+13,33,48,23882,
+21,39,40,23882,
+24,31,45,23882,
+4,39,45,23882,
+3,23,55,23882,
+1,9,59,23882,
+15,23,53,23882,
+13,37,45,23882,
+1,31,51,23882,
+5,17,57,23882,
+5,27,53,23882,
+11,29,51,23882,
+25,27,47,23882,
+25,33,43,23882,
+19,39,41,23882,
+2,38,46,23882,
+30,30,42,23882,
+26,38,38,23882,
+10,10,58,23882,
+2,14,58,23882,
+18,18,54,23882,
+6,42,42,23882,
+24,35,42,23882,
+30,36,37,23944,
+8,30,51,23944,
+27,30,44,23944,
+19,30,48,23944,
+6,35,48,23944,
+9,11,58,23944,
+9,26,53,23944,
+11,14,57,23944,
+29,31,42,23944,
+2,31,51,23944,
+26,37,39,23944,
+17,26,51,23944,
+21,38,41,23944,
+9,37,46,23944,
+6,7,59,23944,
+21,25,50,23944,
+6,41,43,23944,
+15,35,46,23944,
+14,39,43,23944,
+5,25,54,23944,
+3,34,49,23944,
+15,29,50,23944,
+11,41,42,23944,
+19,33,46,23944,
+11,23,54,23944,
+2,9,59,23944,
+17,19,54,23944,
+18,29,49,23944,
+27,34,41,23944,
+10,21,55,23944,
+8,16,57,23944,
+24,28,47,23944,
+3,14,58,23944,
+13,30,50,23944,
+32,32,39,23977,
+12,32,49,23977,
+3,38,46,23977,
+17,24,52,23977,
+10,38,45,23977,
+8,36,47,23977,
+19,38,42,23977,
+22,22,51,23977,
+30,35,38,23977,
+12,20,55,23977,
+12,17,56,23977,
+6,13,58,23977,
+9,28,52,23977,
+13,22,54,23977,
+5,8,59,23977,
+11,40,43,23977,
+19,20,53,23977,
+5,29,52,23977,
+4,23,55,23977,
+20,31,47,23977,
+16,17,55,23977,
+17,40,41,23977,
+31,33,39,23999,
+21,23,51,23999,
+9,33,49,23999,
+5,39,45,23999,
+3,31,51,23999,
+21,27,49,23999,
+23,39,39,23999,
+3,9,59,23999,
+28,32,42,23999,
+16,20,54,23999,
+6,20,56,23999,
+6,40,44,23999,
+22,28,48,23999,
+8,12,58,23999,
+26,36,40,23999,
+23,38,40,23999,
+4,34,49,23999,
+7,32,50,23999,
+26,31,44,23999,
+0,18,57,23999,
+8,22,55,23999,
+9,24,54,23999,
+17,28,50,23999,
+27,27,46,23999,
+18,35,45,23999,
+10,15,57,23999,
+6,27,53,23999,
+18,21,53,23999,
+1,18,57,23999,
+6,17,57,23999,
+15,18,55,23999,
+17,39,42,23999,
+21,37,42,23999,
+26,28,46,23999,
+22,34,44,23999,
+4,38,46,23999,
+14,38,44,23999,
+20,26,50,23999,
+14,26,52,23999,
+4,14,58,23999,
+2,18,57,23999,
+0,21,56,23999,
+16,36,45,23999,
+12,27,52,23999,
+7,42,42,23999,
+20,24,51,23999,
+6,25,54,23999,
+30,34,39,24038,
+12,25,53,24038,
+23,32,45,24038,
+0,37,47,24038,
+1,21,56,24038,
+12,35,47,24038,
+11,39,44,24038,
+9,19,56,24038,
+4,31,51,24038,
+7,35,48,24038,
+4,9,59,24038,
+23,37,41,24038,
+7,41,43,24038,
+23,29,47,24038,
+19,37,43,24038,
+5,23,55,24038,
+7,7,59,24038,
+29,37,37,24053,
+1,37,47,24053,
+14,24,53,24053,
+29,36,38,24074,
+11,34,48,24074,
+2,21,56,24074,
+20,34,45,24074,
+11,18,56,24074,
+24,34,43,24074,
+6,8,59,24074,
+6,29,52,24074,
+0,10,59,24074,
+13,36,46,24074,
+21,32,46,24074,
+14,28,51,24074,
+6,39,45,24074,
+5,34,49,24074,
+25,29,46,24074,
+1,10,59,24074,
+14,19,55,24074,
+15,21,54,24074,
+9,30,51,24074,
+3,18,57,24074,
+11,31,50,24074,
+17,38,43,24074,
+17,22,53,24074,
+7,13,58,24074,
+27,33,42,24074,
+26,35,41,24074,
+2,37,47,24074,
+16,32,48,24074,
+7,40,44,24074,
+5,38,46,24074,
+10,11,58,24074,
+10,37,46,24074,
+25,32,44,24074,
+5,14,58,24074,
+20,28,49,24074,
+2,10,59,24074,
+31,32,40,24096,
+16,25,52,24096,
+10,26,53,24096,
+7,20,56,24096,
+21,36,43,24096,
+12,29,51,24096,
+21,29,48,24096,
+16,27,51,24096,
+9,16,57,24096,
+15,15,56,24096,
+9,36,47,24096,
+21,21,52,24096,
+3,21,56,24096,
+13,13,57,24096,
+15,31,49,24096,
+29,35,39,24125,
+17,33,47,24125,
+11,21,55,24125,
+3,37,47,24125,
+19,25,51,24125,
+15,41,41,24125,
+7,17,57,24125,
+5,31,51,24125,
+7,27,53,24125,
+5,9,59,24125,
+10,28,52,24125,
+20,22,52,24125,
+14,16,56,24125,
+8,32,50,24125,
+12,14,57,24125,
+9,12,58,24125,
+23,36,42,24125,
+0,33,50,24125,
+14,33,48,24125,
+30,33,40,24139,
+12,23,54,24139,
+0,15,58,24139,
+4,18,57,24139,
+18,31,48,24139,
+12,41,42,24139,
+15,40,42,24139,
+6,23,55,24139,
+11,38,45,24139,
+1,33,50,24139,
+7,25,54,24139,
+29,30,43,24139,
+9,22,55,24139,
+10,33,49,24139,
+19,27,50,24139,
+1,15,58,24139,
+14,37,45,24139,
+3,10,59,24139,
+25,38,39,24139,
+17,30,49,24139,
+15,34,47,24139,
+0,26,54,24139,
+10,24,54,24139,
+24,30,46,24139,
+8,42,42,24139,
+12,40,43,24139,
+8,35,48,24139,
+28,28,45,24139,
+22,30,47,24139,
+4,21,56,24139,
+2,33,50,24139,
+19,36,44,24139,
+0,28,53,24139,
+2,15,58,24139,
+6,34,49,24139,
+1,26,54,24139,
+13,17,56,24139,
+25,37,40,24163,
+13,20,55,24163,
+16,23,53,24163,
+19,23,52,24163,
+1,28,53,24163,
+13,32,49,24163,
+7,8,59,24163,
+7,29,52,24163,
+4,37,47,24163,
+19,32,47,24163,
+17,37,44,24163,
+28,31,43,24163,
+8,41,43,24163,
+11,15,57,24163,
+27,29,45,24163,
+7,39,45,24163,
+15,39,43,24163,
+6,38,46,24163,
+6,14,58,24163,
+2,26,54,24163,
+26,34,42,24167,
+14,30,50,24167,
+18,34,46,24167,
+14,22,54,24167,
+28,37,38,24217,
+16,29,50,24217,
+10,19,56,24217,
+16,35,46,24217,
+29,34,40,24217,
+2,28,53,24217,
+8,13,58,24217,
+4,10,59,24217,
+22,33,45,24217,
+6,9,59,24217,
+6,31,51,24217,
+5,18,57,24217,
+3,33,50,24217,
+3,15,58,24217,
+8,40,44,24217,
+0,36,48,24217,
+0,0,60,24217,
+20,40,40,24217,
+8,20,56,24217,
+12,39,44,24217,
+18,26,51,24217,
+3,26,54,24217,
+0,24,55,24217,
+18,19,54,24217,
+10,30,51,24217,
+24,33,44,24217,
+1,36,48,24217,
+26,30,45,24217,
+0,1,60,24217,
+28,36,39,24256,
+24,25,49,24256,
+25,36,41,24256,
+1,1,60,24256,
+13,27,52,24256,
+20,39,41,24256,
+1,24,55,24256,
+21,35,44,24256,
+27,32,43,24256,
+8,27,53,24256,
+5,21,56,24256,
+0,11,59,24256,
+8,17,57,24256,
+3,28,53,24256,
+23,35,43,24256,
+5,37,47,24256,
+31,31,41,24273,
+1,11,59,24273,
+7,23,55,24273,
+13,25,53,24273,
+13,35,47,24273,
+19,29,49,24273,
+17,17,55,24273,
+12,18,56,24273,
+20,30,48,24273,
+18,24,52,24273,
+2,36,48,24273,
+12,34,48,24273,
+0,30,52,24273,
+0,2,60,24273,
+15,26,52,24273,
+4,33,50,24273,
+10,16,57,24273,
+1,30,52,24273,
+1,2,60,24273,
+18,40,41,24273,
+16,18,55,24273,
+10,36,47,24273,
+15,38,44,24273,
+8,25,54,24273,
+30,32,41,24283,
+12,31,50,24283,
+22,39,40,24283,
+23,24,50,24283,
+25,26,48,24283,
+9,32,50,24283,
+2,24,55,24283,
+17,20,54,24283,
+20,33,46,24283,
+4,15,58,24283,
+7,34,49,24283,
+11,26,53,24283,
+23,31,46,24283,
+23,26,49,24283,
+2,11,59,24283,
+34,35,35,24318,
+11,37,46,24318,
+5,10,59,24318,
+11,11,58,24318,
+14,36,46,24318,
+10,12,58,24318,
+2,30,52,24318,
+20,38,42,24318,
+2,2,60,24318,
+18,28,50,24318,
+34,34,36,24330,
+4,26,54,24330,
+10,22,55,24330,
+0,3,60,24330,
+24,27,48,24330,
+20,20,53,24330,
+11,28,52,24330,
+28,35,40,24330,
+7,14,58,24330,
+18,39,42,24330,
+3,36,48,24330,
+6,18,57,24330,
+22,25,50,24330,
+8,29,52,24330,
+9,42,42,24330,
+22,38,41,24330,
+4,28,53,24330,
+7,38,46,24330,
+8,8,59,24330,
+8,39,45,24330,
+15,24,53,24330,
+15,28,51,24330,
+3,24,55,24330,
+17,36,45,24330,
+12,21,55,24330,
+0,19,57,24330,
+1,3,60,24330,
+9,35,48,24330,
+33,35,36,24354,
+19,35,45,24354,
+13,29,51,24354,
+9,41,43,24354,
+15,19,55,24354,
+3,11,59,24354,
+7,31,51,24354,
+29,33,41,24354,
+25,31,45,24354,
+1,19,57,24354,
+19,21,53,24354,
+21,31,47,24354,
+11,33,49,24354,
+7,9,59,24354,
+6,21,56,24354,
+2,3,60,24354,
+11,24,54,24354,
+12,38,45,24354,
+3,30,52,24354,
+0,42,43,24354,
+16,21,54,24354,
+5,33,50,24354,
+13,14,57,24354,
+13,23,54,24354,
+22,27,49,24354,
+25,35,42,24354,
+6,37,47,24354,
+2,19,57,24354,
+9,13,58,24354,
+26,27,47,24354,
+33,34,37,24388,
+26,33,43,24388,
+5,15,58,24388,
+22,23,51,24388,
+1,42,43,24388,
+13,41,42,24388,
+32,36,36,24403,
+4,36,48,24403,
+0,4,60,24403,
+1,4,60,24403,
+18,38,43,24403,
+5,26,54,24403,
+9,20,56,24403,
+6,10,59,24403,
+23,28,48,24403,
+0,41,44,24403,
+17,32,48,24403,
+9,40,44,24403,
+4,24,55,24403,
+15,16,56,24403,
+18,22,53,24403,
+21,26,50,24403,
+22,37,42,24403,
+27,38,38,24403,
+2,42,43,24403,
+11,19,56,24403,
+20,37,43,24403,
+17,25,52,24403,
+25,28,47,24403,
+8,23,55,24403,
+3,3,60,24403,
+16,31,49,24403,
+32,35,37,24433,
+15,33,48,24433,
+1,41,44,24433,
+4,11,59,24433,
+29,29,44,24433,
+24,39,39,24433,
+12,15,57,24433,
+13,40,43,24433,
+21,24,51,24433,
+16,41,41,24433,
+5,28,53,24433,
+3,19,57,24433,
+27,37,39,24433,
+15,37,45,24433,
+9,17,57,24433,
+17,27,51,24433,
+9,27,53,24433,
+0,22,56,24433,
+0,16,58,24433,
+28,30,44,24433,
+4,30,52,24433,
+2,4,60,24433,
+24,38,40,24433,
+16,40,42,24433,
+28,34,41,24433,
+1,16,58,24433,
+8,34,49,24433,
+14,17,56,24433,
+23,34,44,24433,
+14,32,49,24433,
+16,34,47,24433,
+14,20,55,24433,
+1,22,56,24433,
+2,41,44,24433,
+7,18,57,24433,
+33,33,38,24471,
+9,25,54,24471,
+21,34,45,24471,
+18,33,47,24471,
+11,30,51,24471,
+3,42,43,24471,
+22,32,46,24471,
+2,22,56,24471,
+8,14,58,24471,
+32,34,38,24484,
+2,16,58,24484,
+10,32,50,24484,
+8,38,46,24484,
+0,12,59,24484,
+18,30,49,24484,
+0,32,51,24484,
+24,32,45,24484,
+6,33,50,24484,
+0,40,45,24484,
+15,22,54,24484,
+30,31,42,24484,
+0,5,60,24484,
+6,15,58,24484,
+3,4,60,24484,
+5,36,48,24484,
+27,36,40,24484,
+15,30,50,24484,
+24,29,47,24484,
+11,16,57,24484,
+11,36,47,24484,
+1,12,59,24484,
+0,35,49,24484,
+27,31,44,24484,
+19,31,48,24484,
+31,36,37,24502,
+13,39,44,24502,
+8,31,51,24502,
+7,21,56,24502,
+1,40,45,24502,
+16,39,43,24502,
+1,32,51,24502,
+3,41,44,24502,
+24,37,41,24502,
+5,24,55,24502,
+8,9,59,24502,
+4,19,57,24502,
+21,28,49,24502,
+1,5,60,24502,
+20,25,51,24502,
+9,29,52,24502,
+7,37,47,24502,
+5,11,59,24502,
+17,23,53,24502,
+9,39,45,24502,
+1,35,49,24502,
+6,26,54,24502,
+10,42,42,24502,
+10,35,48,24502,
+2,32,51,24502,
+12,37,46,24502,
+20,27,50,24502,
+22,36,43,24502,
+3,16,58,24502,
+13,34,48,24502,
+18,37,44,24502,
+3,22,56,24502,
+5,30,52,24502,
+14,27,52,24502,
+22,29,48,24502,
+4,42,43,24502,
+11,12,58,24502,
+27,28,46,24502,
+2,5,60,24502,
+12,26,53,24502,
+29,32,42,24502,
+21,22,52,24502,
+2,12,59,24502,
+2,40,45,24502,
+6,28,53,24502,
+13,18,56,24502,
+14,25,53,24502,
+11,22,55,24502,
+17,29,50,24502,
+31,35,38,24530,
+13,31,50,24530,
+17,35,46,24530,
+7,10,59,24530,
+10,41,43,24530,
+14,35,47,24530,
+25,34,43,24530,
+2,35,49,24530,
+20,36,44,24530,
+4,4,60,24530,
+12,28,52,24530,
+4,41,44,24530,
+19,34,46,24530,
+26,29,46,24530,
+20,32,47,24530,
+20,23,52,24530,
+10,13,58,24530,
+3,32,51,24530,
+32,33,39,24575,
+3,12,59,24575,
+12,33,49,24575,
+3,40,45,24575,
+3,5,60,24575,
+13,21,55,24575,
+9,23,55,24575,
+27,35,41,24575,
+3,35,49,24575,
+5,19,57,24575,
+4,16,58,24575,
+0,6,60,24575,
+12,24,54,24575,
+16,38,44,24575,
+4,22,56,24575,
+10,40,44,24575,
+6,36,48,24575,
+16,26,52,24575,
+26,32,44,24575,
+10,20,56,24575,
+24,36,42,24575,
+0,39,46,24575,
+15,36,46,24575,
+28,33,42,24575,
+6,24,55,24575,
+1,6,60,24575,
+8,18,57,24575,
+9,34,49,24575,
+5,42,43,24575,
+10,17,57,24575,
+13,38,45,24575,
+6,11,59,24575,
+10,27,53,24575,
+30,37,37,24608,
+14,29,51,24608,
+19,26,51,24608,
+19,19,54,24608,
+31,34,39,24608,
+1,39,46,24608,
+7,33,50,24608,
+7,15,58,24608,
+17,18,55,24608,
+23,30,47,24608,
+30,36,38,24627,
+6,30,52,24627,
+2,6,60,24627,
+18,20,54,24627,
+14,23,54,24627,
+8,21,56,24627,
+9,14,58,24627,
+12,19,56,24627,
+25,30,46,24627,
+21,40,40,24627,
+7,26,54,24627,
+2,39,46,24627,
+4,32,51,24627,
+16,24,53,24627,
+26,38,39,24627,
+10,25,54,24627,
+16,28,51,24627,
+14,41,42,24627,
+4,40,45,24627,
+19,24,52,24627,
+4,12,59,24627,
+4,5,60,24627,
+9,38,46,24627,
+14,14,57,24627,
+8,37,47,24627,
+16,19,55,24627,
+7,28,53,24627,
+19,40,41,24627,
+20,29,49,24627,
+5,41,44,24627,
+4,35,49,24627,
+21,39,41,24627,
+9,31,51,24627,
+23,33,45,24627,
+13,15,57,24627,
+9,9,59,24627,
+21,30,48,24627,
+5,16,58,24627,
+26,37,40,24638,
+19,28,50,24638,
+10,29,52,24638,
+12,30,51,24638,
+5,22,56,24638,
+3,6,60,24638,
+18,36,45,24638,
+0,27,54,24638,
+11,32,50,24638,
+22,35,44,24638,
+14,40,43,24638,
+8,10,59,24638,
+6,19,57,24638,
+1,27,54,24638,
+30,35,39,24686,
+3,39,46,24686,
+21,33,46,24686,
+17,21,54,24686,
+10,39,45,24686,
+19,39,42,24686,
+16,16,56,24686,
+32,32,40,24697,
+12,36,47,24697,
+21,38,42,24697,
+16,33,48,24697,
+0,7,60,24697,
+30,30,43,24697,
+7,36,48,24697,
+2,27,54,24697,
+11,42,42,24697,
+12,16,57,24697,
+0,20,57,24697,
+27,34,42,24697,
+6,42,43,24697,
+20,35,45,24697,
+25,33,44,24697,
+24,35,43,24697,
+5,12,59,24697,
+20,21,53,24697,
+1,7,60,24697,
+28,29,45,24697,
+11,35,48,24697,
+7,24,55,24697,
+0,29,53,24697,
+0,13,59,24697,
+5,5,60,24697,
+16,37,45,24697,
+5,40,45,24697,
+1,20,57,24697,
+0,25,55,24697,
+31,33,40,24716,
+23,39,40,24716,
+5,32,51,24716,
+15,17,56,24716,
+15,32,49,24716,
+15,20,55,24716,
+25,25,49,24716,
+1,13,59,24716,
+7,11,59,24716,
+17,31,49,24716,
+5,35,49,24716,
+1,25,55,24716,
+29,31,43,24716,
+17,41,41,24716,
+1,29,53,24716,
+11,41,43,24716,
+24,24,50,24716,
+4,6,60,24716,
+12,12,58,24716,
+18,32,48,24716,
+8,33,50,24716,
+0,17,58,24716,
+0,38,47,24716,
+17,40,42,24716,
+2,20,57,24716,
+18,25,52,24716,
+4,39,46,24716,
+24,31,46,24716,
+7,30,52,24716,
+14,39,44,24716,
+24,26,49,24716,
+6,41,44,24716,
+12,22,55,24716,
+8,15,58,24716,
+2,7,60,24716,
+26,36,41,24716,
+3,27,54,24716,
+2,29,53,24716,
+23,25,50,24716,
+2,25,55,24716,
+1,38,47,24716,
+1,17,58,24716,
+17,34,47,24716,
+11,13,58,24716,
+27,30,45,24716,
+13,37,46,24716,
+19,22,53,24716,
+22,31,47,24716,
+9,18,57,24716,
+18,27,51,24716,
+13,26,53,24716,
+29,37,38,24742,
+2,13,59,24742,
+23,38,41,24742,
+10,23,55,24742,
+19,38,43,24742,
+6,22,56,24742,
+8,26,54,24742,
+26,26,48,24742,
+16,30,50,24742,
+16,22,54,24742,
+6,16,58,24742,
+0,34,50,24742,
+30,34,40,24754,
+14,18,56,24754,
+14,34,48,24754,
+2,17,58,24754,
+11,20,56,24754,
+13,28,52,24754,
+8,28,53,24754,
+10,34,49,24754,
+1,34,50,24754,
+2,38,47,24754,
+28,32,43,24754,
+14,31,50,24754,
+11,40,44,24754,
+3,7,60,24754,
+9,21,56,24754,
+15,27,52,24754,
+3,20,57,24754,
+29,36,39,24787,
+25,27,48,24787,
+17,39,43,24787,
+11,17,57,24787,
+7,19,57,24787,
+23,23,51,24787,
+15,35,47,24787,
+23,27,49,24787,
+3,13,59,24787,
+13,33,49,24787,
+3,29,53,24787,
+21,37,43,24787,
+3,25,55,24787,
+11,27,53,24787,
+9,37,47,24787,
+15,25,53,24787,
+19,33,47,24787,
+10,14,58,24787,
+2,34,50,24787,
+22,26,50,24787,
+10,38,46,24787,
+13,24,54,24787,
+22,24,51,24787,
+6,12,59,24787,
+6,40,45,24787,
+5,6,60,24787,
+4,27,54,24787,
+6,32,51,24787,
+23,37,42,24787,
+6,35,49,24787,
+26,31,45,24787,
+3,38,47,24787,
+18,23,53,24787,
+9,10,59,24787,
+14,21,55,24787,
+3,17,58,24787,
+5,39,46,24787,
+10,31,51,24787,
+11,25,54,24787,
+19,30,49,24787,
+7,42,43,24787,
+0,8,60,24787,
+8,36,48,24787,
+24,28,48,24787,
+20,31,48,24787,
+18,35,46,24787,
+8,24,55,24787,
+22,34,45,24787,
+0,31,52,24787,
+0,23,56,24787,
+3,34,50,24787,
+1,8,60,24787,
+26,35,42,24805,
+4,20,57,24805,
+4,7,60,24805,
+14,38,45,24805,
+18,29,50,24805,
+1,23,56,24805,
+13,19,56,24805,
+19,37,44,24805,
+4,29,53,24805,
+4,13,59,24805,
+8,11,59,24805,
+1,31,52,24805,
+31,32,41,24860,
+11,29,52,24860,
+4,25,55,24860,
+7,41,44,24860,
+29,35,40,24860,
+21,25,51,24860,
+11,39,45,24860,
+27,27,47,24860,
+27,33,43,24860,
+25,39,39,24860,
+15,29,51,24860,
+8,30,52,24860,
+16,36,46,24860,
+24,34,44,24860,
+12,32,50,24860,
+2,8,60,24860,
+17,38,44,24860,
+22,28,49,24860,
+23,32,46,24860,
+25,38,40,24860,
+17,26,52,24860,
+7,22,56,24860,
+4,17,58,24860,
+4,38,47,24860,
+7,16,58,24860,
+26,28,47,24860,
+2,23,56,24860,
+2,31,52,24860,
+15,41,42,24860,
+30,33,41,24886,
+14,15,57,24886,
+9,15,58,24886,
+21,27,50,24886,
+9,33,50,24886,
+5,27,54,24886,
+13,30,51,24886,
+15,23,54,24886,
+28,38,38,24906,
+20,34,46,24906,
+4,34,50,24906,
+12,42,42,24906,
+22,22,52,24906,
+6,6,60,24906,
+10,18,57,24906,
+12,35,48,24906,
+21,36,44,24906,
+6,39,46,24906,
+3,8,60,24906,
+9,26,54,24906,
+0,37,48,24906,
+18,18,55,24906,
+7,40,45,24906,
+8,19,57,24906,
+12,41,43,24906,
+28,37,39,24923,
+7,12,59,24923,
+3,23,56,24923,
+15,40,43,24923,
+21,23,52,24923,
+9,28,53,24923,
+1,37,48,24923,
+7,32,51,24923,
+25,32,45,24923,
+13,36,47,24923,
+21,32,47,24923,
+5,20,57,24923,
+17,28,51,24923,
+17,24,53,24923,
+23,29,48,24923,
+13,16,57,24923,
+23,36,43,24923,
+5,7,60,24923,
+3,31,52,24923,
+25,29,47,24923,
+11,23,55,24923,
+35,35,35,24968,
+5,29,53,24968,
+25,37,41,24968,
+7,35,49,24968,
+17,19,55,24968,
+5,13,59,24968,
+5,25,55,24968,
+12,13,58,24968,
+8,42,43,24968,
+19,20,54,24968,
+0,14,59,24968,
+10,21,56,24968,
+20,26,51,24968,
+34,35,36,24993,
+2,37,48,24993,
+29,30,44,24993,
+5,17,58,24993,
+10,37,47,24993,
+13,22,55,24993,
+29,34,41,24993,
+5,38,47,24993,
+11,34,49,24993,
+1,14,59,24993,
+20,24,52,24993,
+12,40,44,24993,
+12,20,56,24993,
+4,8,60,24993,
+28,36,40,24993,
+14,26,53,24993,
+6,27,54,24993,
+11,38,46,24993,
+4,23,56,24993,
+16,17,56,24993,
+18,21,54,24993,
+26,34,43,24993,
+4,31,52,24993,
+9,36,48,24993,
+0,9,60,24993,
+14,37,46,24993,
+11,14,58,24993,
+2,14,59,24993,
+16,20,55,24993,
+33,36,36,25018,
+8,41,44,25018,
+28,31,44,25018,
+20,40,41,25018,
+16,32,49,25018,
+5,34,50,25018,
+10,10,59,25018,
+34,34,37,25018,
+1,9,60,25018,
+12,27,53,25018,
+12,17,57,25018,
+9,24,55,25018,
+19,36,45,25018,
+17,33,48,25018,
+3,37,48,25018,
+15,39,44,25018,
+17,37,45,25018,
+11,31,51,25018,
+9,11,59,25018,
+33,35,37,25044,
+21,29,49,25044,
+22,40,40,25044,
+28,28,46,25044,
+20,28,50,25044,
+14,28,52,25044,
+8,16,58,25044,
+8,22,56,25044,
+24,30,47,25044,
+15,18,56,25044,
+15,34,48,25044,
+25,36,42,25044,
+12,25,54,25044,
+6,20,57,25044,
+20,39,42,25044,
+2,9,60,25044,
+6,7,60,25044,
+9,30,52,25044,
+31,31,42,25044,
+22,39,41,25044,
+18,41,41,25044,
+6,29,53,25044,
+6,25,55,25044,
+18,31,49,25044,
+3,14,59,25044,
+7,39,46,25044,
+27,29,46,25044,
+15,31,50,25044,
+6,13,59,25044,
+14,33,49,25044,
+18,40,42,25044,
+30,32,42,25052,
+0,18,58,25052,
+22,30,48,25052,
+14,24,54,25052,
+18,34,47,25052,
+17,22,54,25052,
+5,8,60,25052,
+6,38,47,25052,
+8,32,51,25052,
+10,15,58,25052,
+16,27,52,25052,
+33,34,38,25098,
+4,37,48,25098,
+12,29,52,25098,
+8,12,59,25098,
+1,18,58,25098,
+8,40,45,25098,
+19,32,48,25098,
+32,36,37,25098,
+17,30,50,25098,
+27,32,44,25098,
+6,17,58,25098,
+10,33,50,25098,
+22,33,46,25098,
+5,31,52,25098,
+16,35,47,25098,
+28,35,41,25098,
+12,39,45,25098,
+8,35,49,25098,
+16,25,53,25098,
+0,21,57,25098,
+24,33,45,25098,
+0,33,51,25098,
+3,9,60,25098,
+23,35,44,25098,
+19,25,52,25098,
+5,23,56,25098,
+15,21,55,25098,
+21,35,45,25098,
+21,21,53,25098,
+1,21,57,25098,
+9,19,57,25098,
+1,33,51,25098,
+19,27,51,25098,
+2,18,58,25098,
+26,30,46,25098,
+10,26,54,25098,
+22,38,42,25098,
+6,34,50,25098,
+4,14,59,25098,
+14,19,56,25098,
+20,22,53,25098,
+10,28,53,25098,
+13,32,50,25098,
+32,35,38,25134,
+20,38,43,25134,
+9,42,43,25134,
+2,33,51,25134,
+29,33,42,25134,
+11,18,57,25134,
+2,21,57,25134,
+27,38,39,25134,
+7,27,54,25134,
+15,38,45,25134,
+18,39,43,25134,
+13,42,42,25134,
+4,9,60,25134,
+14,30,51,25134,
+3,18,58,25134,
+0,36,49,25134,
+24,39,40,25134,
+0,43,43,25134,
+7,7,60,25134,
+1,36,49,25134,
+7,20,57,25134,
+9,41,44,25134,
+13,35,48,25134,
+16,29,51,25134,
+12,23,55,25134,
+5,37,48,25134,
+27,37,40,25142,
+11,21,56,25142,
+20,33,47,25142,
+7,13,59,25142,
+1,43,43,25142,
+31,37,37,25185,
+3,33,51,25185,
+23,31,47,25185,
+15,15,57,25185,
+3,21,57,25185,
+13,41,43,25185,
+11,37,47,25185,
+7,29,53,25185,
+33,33,39,25185,
+7,25,55,25185,
+19,23,53,25185,
+25,35,43,25185,
+0,42,44,25185,
+6,8,60,25185,
+10,36,48,25185,
+0,28,54,25185,
+0,10,60,25185,
+16,41,42,25185,
+17,36,46,25185,
+9,16,58,25185,
+1,42,44,25185,
+10,24,55,25185,
+1,10,60,25185,
+14,36,47,25185,
+8,39,46,25185,
+20,30,49,25185,
+24,38,41,25185,
+24,25,50,25185,
+6,31,52,25185,
+14,16,57,25185,
+32,34,39,25209,
+31,36,38,25209,
+16,23,54,25209,
+0,26,55,25209,
+26,33,44,25209,
+2,36,49,25209,
+6,23,56,25209,
+9,22,56,25209,
+12,34,49,25209,
+1,28,54,25209,
+19,29,50,25209,
+2,43,43,25209,
+22,37,43,25209,
+1,26,55,25209,
+25,26,49,25209,
+10,11,59,25209,
+7,38,47,25209,
+13,13,58,25209,
+5,14,59,25209,
+25,31,46,25209,
+19,35,46,25209,
+7,17,58,25209,
+18,38,44,25209,
+2,42,44,25209,
+12,38,46,25209,
+12,14,58,25209,
+4,18,58,25209,
+2,10,60,25209,
+28,34,42,25209,
+2,28,54,25209,
+10,30,52,25209,
+18,26,52,25209,
+16,40,43,25209,
+2,26,55,25209,
+14,22,55,25209,
+20,37,44,25209,
+23,26,50,25209,
+13,20,56,25209,
+7,34,50,25209,
+13,40,44,25209,
+9,32,51,25209,
+5,9,60,25209,
+24,27,49,25209,
+23,24,51,25209,
+12,31,51,25209,
+0,41,45,25209,
+4,33,51,25209,
+21,31,48,25209,
+4,21,57,25209,
+0,15,59,25209,
+27,36,41,25219,
+9,12,59,25219,
+9,40,45,25219,
+3,36,49,25219,
+29,29,45,25219,
+1,15,59,25219,
+9,35,49,25219,
+3,43,43,25219,
+13,17,57,25219,
+13,27,53,25219,
+1,41,45,25219,
+31,35,39,25256,
+26,27,48,25256,
+6,37,48,25256,
+0,30,53,25256,
+3,10,60,25256,
+18,28,51,25256,
+8,27,54,25256,
+3,28,54,25256,
+28,30,45,25256,
+18,24,53,25256,
+24,37,42,25256,
+3,42,44,25256,
+3,26,55,25256,
+10,19,57,25256,
+15,26,53,25256,
+18,19,55,25256,
+15,37,46,25256,
+11,15,58,25256,
+22,25,51,25256,
+11,33,50,25256,
+2,15,59,25256,
+23,34,45,25256,
+1,30,53,25256,
+13,25,54,25256,
+30,31,43,25256,
+2,41,45,25256,
+0,24,56,25256,
+2,30,53,25256,
+25,28,48,25256,
+4,36,49,25256,
+10,42,43,25256,
+32,33,40,25297,
+1,24,56,25297,
+6,14,59,25297,
+15,28,52,25297,
+11,26,54,25297,
+30,37,38,25297,
+8,20,57,25297,
+21,34,46,25297,
+22,27,50,25297,
+7,8,60,25297,
+16,39,44,25297,
+5,18,58,25297,
+8,25,55,25297,
+29,32,43,25297,
+17,32,49,25297,
+8,13,59,25297,
+13,29,52,25297,
+17,17,56,25297,
+7,23,56,25297,
+23,28,49,25297,
+4,43,43,25297,
+8,29,53,25297,
+11,28,53,25297,
+17,20,55,25297,
+7,31,52,25297,
+3,41,45,25297,
+15,33,49,25297,
+5,33,51,25297,
+3,15,59,25297,
+27,31,45,25297,
+5,21,57,25297,
+13,39,45,25297,
+4,28,54,25297,
+0,40,46,25297,
+20,20,54,25297,
+4,42,44,25297,
+24,32,46,25297,
+22,36,44,25297,
+16,34,48,25297,
+16,18,56,25297,
+2,24,56,25297,
+4,10,60,25297,
+10,41,44,25297,
+25,34,44,25297,
+6,9,60,25297,
+1,40,46,25297,
+8,38,47,25297,
+8,17,58,25297,
+16,31,50,25297,
+15,24,54,25297,
+22,23,52,25297,
+4,26,55,25297,
+12,18,57,25297,
+30,36,39,25347,
+18,33,48,25347,
+22,32,47,25347,
+31,34,40,25347,
+18,37,45,25347,
+9,39,46,25347,
+19,21,54,25347,
+26,39,39,25347,
+3,30,53,25347,
+27,35,42,25347,
+21,26,51,25347,
+14,32,50,25347,
+2,40,46,25347,
+26,38,40,25347,
+10,22,56,25347,
+10,16,58,25347,
+8,34,50,25347,
+20,36,45,25347,
+12,21,56,25347,
+24,29,48,25347,
+3,24,56,25347,
+24,36,43,25347,
+0,0,61,25347,
+11,36,48,25347,
+21,24,52,25347,
+0,11,60,25347,
+5,36,49,25347,
+4,41,45,25347,
+1,11,60,25347,
+16,21,55,25347,
+17,27,52,25347,
+28,33,43,25360,
+4,15,59,25360,
+21,40,41,25360,
+15,19,56,25360,
+11,24,55,25360,
+12,37,47,25360,
+27,28,47,25360,
+7,37,48,25360,
+0,1,61,25360,
+19,41,41,25360,
+17,35,47,25360,
+13,23,55,25360,
+1,1,61,25360,
+17,25,53,25360,
+11,11,59,25360,
+19,31,49,25360,
+5,43,43,25360,
+14,42,42,25360,
+18,30,50,25360,
+6,18,58,25360,
+18,22,54,25360,
+10,32,51,25360,
+11,30,52,25360,
+5,42,44,25360,
+0,2,61,25360,
+19,40,42,25360,
+5,28,54,25360,
+5,10,60,25360,
+10,12,59,25360,
+16,38,45,25360,
+30,35,40,25420,
+0,35,50,25420,
+2,11,60,25420,
+0,19,58,25420,
+10,40,45,25420,
+26,32,45,25420,
+4,30,53,25420,
+21,28,50,25420,
+3,40,46,25420,
+14,35,48,25420,
+1,2,61,25420,
+13,34,49,25420,
+10,35,49,25420,
+1,19,58,25420,
+15,30,51,25420,
+9,27,54,25420,
+19,34,47,25420,
+5,26,55,25420,
+26,37,41,25420,
+26,29,47,25420,
+14,41,43,25420,
+1,35,50,25420,
+6,33,51,25420,
+6,21,57,25420,
+21,39,42,25420,
+22,29,49,25420,
+7,14,59,25420,
+0,32,52,25420,
+4,24,56,25420,
+20,32,48,25420,
+8,8,60,25420,
+2,35,50,25420,
+2,19,58,25420,
+13,38,46,25420,
+23,40,40,25420,
+13,14,58,25420,
+8,31,52,25420,
+2,2,61,25420,
+1,32,52,25420,
+29,38,38,25449,
+32,32,41,25449,
+20,25,52,25449,
+8,23,56,25449,
+15,16,57,25449,
+3,11,60,25449,
+7,9,60,25449,
+9,20,57,25449,
+20,27,51,25449,
+15,36,47,25449,
+0,3,61,25449,
+0,39,47,25449,
+1,39,47,25449,
+5,41,45,25449,
+29,37,39,25466,
+19,39,43,25466,
+11,19,57,25466,
+9,13,59,25466,
+13,31,51,25466,
+17,29,51,25466,
+31,33,41,25466,
+9,25,55,25466,
+9,29,53,25466,
+5,15,59,25466,
+23,39,41,25466,
+1,3,61,25466,
+14,20,56,25466,
+2,32,52,25466,
+4,40,46,25466,
+14,40,44,25466,
+23,30,48,25466,
+12,15,58,25466,
+0,22,57,25466,
+12,33,50,25466,
+6,36,49,25466,
+9,38,47,25466,
+27,34,43,25466,
+14,17,57,25466,
+3,19,58,25466,
+2,3,61,25466,
+5,30,53,25466,
+17,23,54,25466,
+2,39,47,25466,
+9,17,58,25466,
+23,33,46,25466,
+17,41,42,25466,
+21,38,43,25466,
+3,35,50,25466,
+22,35,45,25466,
+14,27,53,25466,
+11,42,43,25466,
+6,43,43,25466,
+21,22,53,25466,
+15,22,55,25466,
+1,22,57,25466,
+25,30,47,25466,
+6,42,44,25466,
+26,36,42,25476,
+6,10,60,25476,
+6,28,54,25476,
+12,26,54,25476,
+30,30,44,25476,
+18,36,46,25476,
+23,38,42,25476,
+12,28,53,25476,
+3,32,52,25476,
+4,11,60,25476,
+0,16,59,25476,
+5,24,56,25476,
+0,4,61,25476,
+29,36,40,25529,
+10,39,46,25529,
+9,34,50,25529,
+8,37,48,25529,
+14,25,54,25529,
+24,35,44,25529,
+2,22,57,25529,
+7,18,58,25529,
+30,34,41,25529,
+6,26,55,25529,
+17,40,43,25529,
+20,23,53,25529,
+1,4,61,25529,
+29,31,44,25529,
+1,16,59,25529,
+11,41,44,25529,
+25,33,45,25529,
+3,3,61,25529,
+7,33,51,25529,
+3,39,47,25529,
+21,33,47,25529,
+7,21,57,25529,
+8,14,59,25529,
+5,40,46,25529,
+2,16,59,25529,
+20,35,46,25529,
+28,29,46,25529,
+11,16,58,25529,
+4,35,50,25529,
+4,19,58,25529,
+20,29,50,25529,
+16,37,46,25529,
+16,26,53,25529,
+19,26,52,25529,
+14,29,52,25529,
+11,22,56,25529,
+2,4,61,25529,
+19,38,44,25529,
+14,39,45,25529,
+6,15,59,25529,
+6,41,45,25529,
+3,22,57,25529,
+21,30,49,25529,
+13,18,57,25529,
+0,12,60,25529,
+16,28,52,25529,
+12,36,48,25529,
+28,32,44,25554,
+4,32,52,25554,
+10,27,54,25554,
+8,9,60,25554,
+1,12,60,25554,
+6,30,53,25554,
+12,24,55,25554,
+27,30,46,25554,
+11,40,45,25554,
+16,33,49,25554,
+35,35,36,25648,
+11,32,51,25648,
+17,39,44,25648,
+3,4,61,25648,
+25,39,40,25648,
+11,12,59,25648,
+4,39,47,25648,
+13,21,56,25648,
+0,5,61,25648,
+19,28,51,25648,
+19,24,53,25648,
+21,37,44,25648,
+24,31,47,25648,
+7,36,49,25648,
+9,23,56,25648,
+3,16,59,25648,
+9,31,52,25648,
+5,11,60,25648,
+11,35,49,25648,
+13,37,47,25648,
+1,5,61,25648,
+29,35,41,25648,
+23,37,43,25648,
+7,43,43,25648,
+19,19,55,25648,
+12,30,52,25648,
+2,12,60,25648,
+34,36,36,25659,
+6,24,56,25659,
+16,24,54,25659,
+0,38,48,25659,
+18,32,49,25659,
+1,38,48,25659,
+18,20,55,25659,
+7,42,44,25659,
+31,32,42,25659,
+4,22,57,25659,
+7,10,60,25659,
+7,28,54,25659,
+22,31,48,25659,
+15,32,50,25659,
+28,38,39,25659,
+17,34,48,25659,
+10,20,57,25659,
+17,18,56,25659,
+2,5,61,25659,
+10,25,55,25659,
+17,31,50,25659,
+5,35,50,25659,
+7,26,55,25659,
+10,29,53,25659,
+25,25,50,25659,
+34,35,37,25685,
+10,13,59,25685,
+5,19,58,25685,
+14,23,55,25685,
+26,35,43,25685,
+25,38,41,25685,
+24,26,50,25685,
+8,18,58,25685,
+2,38,48,25685,
+6,40,46,25685,
+3,12,60,25685,
+14,34,49,25685,
+26,26,49,25685,
+24,24,51,25685,
+10,38,47,25685,
+16,19,56,25685,
+28,37,40,25685,
+4,4,61,25685,
+5,32,52,25685,
+4,16,59,25685,
+10,17,58,25685,
+30,33,42,25685,
+26,31,46,25685,
+15,42,42,25685,
+8,33,51,25685,
+19,33,48,25685,
+0,27,55,25685,
+8,21,57,25685,
+15,35,48,25685,
+9,37,48,25685,
+33,36,37,25718,
+27,33,44,25718,
+12,19,57,25718,
+1,27,55,25718,
+5,39,47,25718,
+7,15,59,25718,
+15,41,43,25718,
+19,37,45,25718,
+25,27,49,25718,
+7,41,45,25718,
+17,21,55,25718,
+3,5,61,25718,
+23,25,51,25718,
+10,34,50,25718,
+22,34,46,25718,
+14,14,58,25718,
+14,38,46,25718,
+34,34,38,25720,
+18,27,52,25720,
+20,21,54,25720,
+6,11,60,25720,
+0,29,54,25720,
+16,30,51,25720,
+3,38,48,25720,
+0,6,61,25720,
+24,34,45,25720,
+0,34,51,25720,
+12,42,43,25720,
+33,35,38,25746,
+5,22,57,25746,
+2,27,55,25746,
+1,29,54,25746,
+17,38,45,25746,
+13,15,58,25746,
+1,34,51,25746,
+1,6,61,25746,
+13,33,50,25746,
+23,27,50,25746,
+18,25,53,25746,
+18,35,47,25746,
+25,37,42,25746,
+9,14,59,25746,
+14,31,51,25746,
+11,39,46,25746,
+7,30,53,25746,
+4,12,60,25746,
+15,20,56,25746,
+8,36,49,25746,
+0,25,56,25746,
+24,28,49,25746,
+7,24,56,25746,
+16,16,57,25746,
+6,19,58,25746,
+12,41,44,25746,
+2,6,61,25746,
+19,22,54,25746,
+15,40,44,25746,
+13,26,54,25746,
+2,29,54,25746,
+28,36,41,25746,
+16,36,47,25746,
+23,36,44,25746,
+19,30,50,25746,
+29,34,42,25746,
+6,35,50,25746,
+22,26,51,25746,
+2,34,51,25746,
+32,37,37,25782,
+4,5,61,25782,
+20,41,41,25782,
+27,27,48,25782,
+5,16,59,25782,
+23,23,52,25782,
+9,9,60,25782,
+20,31,49,25782,
+21,36,45,25782,
+1,25,56,25782,
+13,28,53,25782,
+8,43,43,25782,
+23,32,47,25782,
+15,27,53,25782,
+15,17,57,25782,
+3,27,55,25782,
+8,42,44,25782,
+6,32,52,25782,
+4,38,48,25782,
+12,22,56,25782,
+12,16,58,25782,
+26,28,48,25782,
+22,24,52,25782,
+8,10,60,25782,
+32,36,38,25789,
+0,20,58,25789,
+20,40,42,25789,
+8,28,54,25789,
+1,20,58,25789,
+10,23,56,25789,
+20,34,47,25789,
+10,31,52,25789,
+7,40,46,25789,
+2,25,56,25789,
+8,26,55,25789,
+16,22,55,25789,
+22,40,41,25789,
+25,32,46,25789,
+29,30,45,25789,
+11,27,54,25789,
+3,34,51,25789,
+3,29,54,25789,
+15,25,54,25789,
+3,6,61,25789,
+6,39,47,25789,
+33,34,39,25812,
+18,29,51,25812,
+2,20,58,25812,
+26,34,44,25812,
+22,28,50,25812,
+18,41,42,25812,
+6,22,57,25812,
+22,39,42,25812,
+12,40,45,25812,
+21,32,48,25812,
+18,23,54,25812,
+14,18,57,25812,
+9,18,58,25812,
+12,32,51,25812,
+13,36,48,25812,
+5,12,60,25812,
+0,13,60,25812,
+12,12,59,25812,
+1,13,60,25812,
+25,36,43,25812,
+32,35,39,25856,
+0,7,61,25856,
+4,27,55,25856,
+0,17,59,25856,
+13,24,55,25856,
+25,29,48,25856,
+0,37,49,25856,
+0,31,53,25856,
+8,41,45,25856,
+3,25,56,25856,
+28,31,45,25856,
+15,29,52,25856,
+21,25,52,25856,
+8,15,59,25856,
+11,20,57,25856,
+20,39,43,25856,
+12,35,49,25856,
+7,11,60,25856,
+1,37,49,25856,
+1,31,53,25856,
+11,29,53,25856,
+1,17,59,25856,
+9,21,57,25856,
+31,31,43,25856,
+27,39,39,25856,
+9,33,51,25856,
+11,25,55,25856,
+21,27,51,25856,
+5,5,61,25856,
+23,29,49,25856,
+15,39,45,25856,
+11,13,59,25856,
+1,7,61,25856,
+5,38,48,25856,
+19,36,46,25856,
+8,30,53,25856,
+27,38,40,25856,
+18,40,43,25856,
+10,37,48,25856,
+6,16,59,25856,
+4,29,54,25856,
+13,30,52,25856,
+2,13,60,25856,
+4,34,51,25856,
+28,35,42,25856,
+4,6,61,25856,
+30,32,43,25856,
+3,20,58,25856,
+14,21,56,25856,
+2,7,61,25856,
+7,19,58,25856,
+2,17,59,25856,
+11,38,47,25856,
+2,37,49,25856,
+31,37,38,25878,
+14,37,47,25878,
+7,35,50,25878,
+17,37,46,25878,
+11,17,58,25878,
+17,26,53,25878,
+2,31,53,25878,
+24,40,40,25878,
+8,24,56,25878,
+22,38,43,25878,
+22,22,53,25878,
+10,14,59,25878,
+4,25,56,25878,
+28,28,47,25878,
+7,32,52,25878,
+17,28,52,25878,
+11,34,50,25878,
+31,36,39,25929,
+27,32,45,25929,
+0,23,57,25929,
+33,33,40,25929,
+24,39,41,25929,
+3,13,60,25929,
+9,36,49,25929,
+5,27,55,25929,
+9,43,43,25929,
+21,23,53,25929,
+13,19,57,25929,
+3,37,49,25929,
+17,33,49,25929,
+1,23,57,25929,
+29,33,43,25929,
+3,31,53,25929,
+27,37,41,25929,
+27,29,47,25929,
+23,35,45,25929,
+3,17,59,25929,
+15,23,55,25929,
+3,7,61,25929,
+7,39,47,25929,
+20,38,44,25929,
+4,20,58,25929,
+24,30,48,25929,
+20,26,52,25929,
+6,12,60,25929,
+8,40,46,25929,
+32,34,40,25933,
+16,32,50,25933,
+9,28,54,25933,
+9,42,44,25933,
+12,39,46,25933,
+17,24,54,25933,
+18,39,44,25933,
+9,10,60,25933,
+24,33,46,25933,
+5,6,61,25933,
+5,29,54,25933,
+15,34,49,25933,
+21,29,50,25933,
+21,35,46,25933,
+2,23,57,25933,
+7,22,57,25933,
+5,34,51,25933,
+13,42,43,25933,
+9,26,55,25933,
+22,33,47,25933,
+18,34,48,25933,
+6,38,48,25933,
+24,38,42,25933,
+16,42,42,25933,
+18,18,56,25933,
+16,35,48,25933,
+4,13,60,25933,
+0,43,44,25933,
+18,31,50,25933,
+20,24,53,25933,
+20,28,51,25933,
+22,30,49,25933,
+8,11,60,25933,
+14,15,58,25933,
+26,30,47,25933,
+14,33,50,25933,
+15,38,46,25933,
+0,8,61,25933,
+11,31,52,25933,
+1,8,61,25933,
+25,35,44,25933,
+19,32,49,25933,
+4,31,53,25933,
+13,41,44,25933,
+4,37,49,25933,
+1,43,44,25933,
+4,7,61,25933,
+31,35,40,25987,
+16,41,43,25987,
+5,25,56,25987,
+19,20,55,25987,
+11,23,56,25987,
+7,16,59,25987,
+17,19,56,25987,
+4,17,59,25987,
+9,15,59,25987,
+3,23,57,25987,
+15,31,51,25987,
+9,41,45,25987,
+14,26,54,25987,
+10,18,58,25987,
+30,38,38,25990,
+5,20,58,25990,
+22,37,44,25990,
+0,42,45,25990,
+2,43,44,25990,
+27,36,42,25990,
+12,27,54,25990,
+13,22,56,25990,
+2,8,61,25990,
+13,16,58,25990,
+14,28,53,25990,
+28,34,43,25990,
+8,19,58,25990,
+8,35,50,25990,
+6,27,55,25990,
+30,37,39,26028,
+9,30,53,26028,
+10,21,57,26028,
+26,33,45,26028,
+1,42,45,26028,
+17,30,51,26028,
+10,33,51,26028,
+18,21,55,26028,
+16,40,44,26028,
+8,32,52,26028,
+16,20,56,26028,
+9,24,56,26028,
+12,20,57,26028,
+6,6,61,26028,
+0,33,52,26028,
+6,34,51,26028,
+18,38,45,26028,
+2,42,45,26028,
+7,12,60,26028,
+6,29,54,26028,
+20,33,48,26028,
+17,36,47,26028,
+19,27,52,26028,
+32,33,41,26073,
+13,32,51,26073,
+16,17,57,26073,
+8,39,47,26073,
+23,31,48,26073,
+1,33,52,26073,
+3,8,61,26073,
+12,29,53,26073,
+20,37,45,26073,
+13,40,45,26073,
+11,37,48,26073,
+16,27,53,26073,
+5,13,60,26073,
+3,43,44,26073,
+4,23,57,26073,
+12,25,55,26073,
+24,37,43,26073,
+12,13,59,26073,
+5,37,49,26073,
+25,31,47,26073,
+5,7,61,26073,
+5,31,53,26073,
+19,25,53,26073,
+13,35,49,26073,
+5,17,59,26073,
+19,35,47,26073,
+0,36,50,26073,
+30,36,40,26080,
+14,36,48,26080,
+0,14,60,26080,
+16,25,54,26080,
+7,38,48,26080,
+14,24,55,26080,
+12,38,47,26080,
+1,14,60,26080,
+10,36,49,26080,
+2,33,52,26080,
+0,41,46,26080,
+1,36,50,26080,
+26,39,40,26080,
+9,40,46,26080,
+8,22,57,26080,
+6,25,56,26080,
+30,31,44,26080,
+12,17,58,26080,
+15,18,57,26080,
+31,34,41,26106,
+11,14,59,26106,
+10,43,43,26106,
+1,41,46,26106,
+3,42,45,26106,
+29,29,46,26106,
+21,21,54,26106,
+17,22,55,26106,
+20,30,50,26106,
+20,22,54,26106,
+6,20,58,26106,
+2,14,60,26106,
+10,42,44,26106,
+12,34,50,26106,
+10,28,54,26106,
+28,30,46,26106,
+10,10,60,26106,
+14,30,52,26106,
+2,36,50,26106,
+29,32,44,26106,
+25,26,50,26106,
+4,43,44,26106,
+23,34,46,26106,
+10,26,55,26106,
+26,38,41,26106,
+8,16,59,26106,
+4,8,61,26106,
+2,41,46,26106,
+16,29,52,26106,
+16,39,45,26106,
+15,21,56,26106,
+24,25,51,26106,
+9,11,60,26106,
+3,33,52,26106,
+0,9,61,26106,
+1,9,61,26106,
+15,37,47,26106,
+7,27,55,26106,
+19,29,51,26106,
+27,35,43,26117,
+21,41,41,26117,
+5,23,57,26117,
+21,31,49,26117,
+6,13,60,26117,
+3,14,60,26117,
+4,42,45,26117,
+3,36,50,26117,
+22,36,45,26117,
+0,18,59,26117,
+24,27,50,26117,
+21,40,42,26117,
+0,21,58,26117,
+7,29,54,26117,
+29,38,39,26179,
+9,19,58,26179,
+6,31,53,26179,
+21,34,47,26179,
+27,31,46,26179,
+1,18,59,26179,
+1,21,58,26179,
+2,9,61,26179,
+10,41,45,26179,
+19,41,42,26179,
+30,35,41,26179,
+23,26,51,26179,
+6,37,49,26179,
+10,15,59,26179,
+6,17,59,26179,
+14,19,57,26179,
+25,34,45,26179,
+3,41,46,26179,
+26,27,49,26179,
+6,7,61,26179,
+19,23,54,26179,
+9,35,50,26179,
+7,34,51,26179,
+13,39,46,26179,
+24,36,44,26179,
+8,12,60,26179,
+23,24,52,26179,
+12,23,56,26179,
+2,18,59,26179,
+26,37,42,26179,
+9,32,52,26179,
+14,42,43,26179,
+18,37,46,26179,
+28,33,44,26179,
+24,32,47,26179,
+18,26,53,26179,
+2,21,58,26179,
+11,18,58,26179,
+0,28,55,26179,
+12,31,52,26179,
+4,33,52,26179,
+10,30,53,26179,
+0,40,47,26179,
+23,40,41,26179,
+5,43,44,26179,
+1,40,47,26179,
+16,23,55,26179,
+1,28,55,26179,
+25,28,49,26179,
+19,40,43,26179,
+5,8,61,26179,
+29,37,40,26213,
+7,25,56,26213,
+9,39,47,26213,
+21,39,43,26213,
+11,33,51,26213,
+3,9,61,26213,
+11,21,57,26213,
+22,32,48,26213,
+0,26,56,26213,
+10,24,56,26213,
+8,38,48,26213,
+4,36,50,26213,
+32,32,42,26222,
+20,36,46,26222,
+4,14,60,26222,
+18,28,52,26222,
+22,25,52,26222,
+17,32,50,26222,
+2,28,55,26222,
+16,34,49,26222,
+4,41,46,26222,
+14,41,44,26222,
+1,26,56,26222,
+7,20,58,26222,
+2,40,47,26222,
+23,28,50,26222,
+3,21,58,26222,
+22,27,51,26222,
+6,23,57,26222,
+3,18,59,26222,
+15,15,58,26222,
+18,33,49,26222,
+13,27,54,26222,
+15,33,50,26222,
+9,22,57,26222,
+5,42,45,26222,
+31,33,42,26250,
+23,39,42,26250,
+18,24,54,26250,
+10,40,46,26250,
+16,38,46,26250,
+14,22,56,26250,
+26,32,46,26250,
+14,16,58,26250,
+0,30,54,26250,
+2,26,56,26250,
+35,36,36,26305,
+15,26,54,26305,
+12,37,48,26305,
+27,28,48,26305,
+1,30,54,26305,
+17,42,42,26305,
+9,16,59,26305,
+4,9,61,26305,
+5,33,52,26305,
+15,28,53,26305,
+29,36,41,26305,
+16,31,51,26305,
+17,35,48,26305,
+24,29,49,26305,
+8,27,55,26305,
+3,40,47,26305,
+7,13,60,26305,
+11,36,49,26305,
+13,20,57,26305,
+3,28,55,26305,
+19,39,44,26305,
+7,31,53,26305,
+13,29,53,26305,
+11,43,43,26305,
+35,35,37,26330,
+13,25,55,26330,
+7,37,49,26330,
+13,13,59,26330,
+17,41,43,26330,
+7,7,61,26330,
+7,17,59,26330,
+30,34,42,26330,
+2,30,54,26330,
+21,38,44,26330,
+26,36,43,26330,
+3,26,56,26330,
+4,21,58,26330,
+11,28,54,26330,
+27,34,44,26330,
+5,14,60,26330,
+18,19,56,26330,
+11,42,44,26330,
+19,34,48,26330,
+6,8,61,26330,
+12,14,59,26330,
+4,18,59,26330,
+14,40,45,26330,
+8,29,54,26330,
+21,26,52,26330,
+6,43,44,26330,
+8,34,51,26330,
+10,11,60,26330,
+26,29,48,26330,
+14,32,51,26330,
+0,10,61,26330,
+34,36,37,26343,
+5,36,50,26343,
+13,38,47,26343,
+22,23,53,26343,
+19,31,50,26343,
+1,10,61,26343,
+14,35,49,26343,
+23,38,43,26343,
+5,41,46,26343,
+11,26,55,26343,
+13,17,58,26343,
+0,39,48,26343,
+34,35,38,26382,
+6,42,45,26382,
+20,32,49,26382,
+17,40,44,26382,
+9,12,60,26382,
+4,28,55,26382,
+15,36,48,26382,
+30,30,45,26382,
+20,20,55,26382,
+8,25,56,26382,
+4,40,47,26382,
+22,29,50,26382,
+25,40,40,26382,
+13,34,50,26382,
+0,24,57,26382,
+10,35,50,26382,
+0,15,60,26382,
+2,10,61,26382,
+18,30,51,26382,
+10,19,58,26382,
+22,35,46,26382,
+3,30,54,26382,
+17,20,56,26382,
+0,35,51,26382,
+1,39,48,26382,
+21,24,53,26382,
+1,24,57,26382,
+21,28,51,26382,
+28,39,39,26382,
+15,24,55,26382,
+24,35,45,26382,
+1,15,60,26382,
+33,37,37,26407,
+7,23,57,26407,
+17,27,53,26407,
+11,41,45,26407,
+17,17,57,26407,
+11,15,59,26407,
+25,39,41,26407,
+1,35,51,26407,
+19,21,55,26407,
+29,31,45,26407,
+23,33,47,26407,
+5,9,61,26407,
+10,32,52,26407,
+28,38,40,26407,
+8,20,58,26407,
+4,26,56,26407,
+2,15,60,26407,
+16,18,57,26407,
+25,30,48,26407,
+2,39,48,26407,
+6,33,52,26407,
+9,38,48,26407,
+18,36,47,26407,
+2,24,57,26407,
+33,36,38,26431,
+15,30,52,26431,
+17,25,54,26431,
+29,35,42,26431,
+10,39,47,26431,
+2,35,51,26431,
+5,21,58,26431,
+3,10,61,26431,
+25,33,46,26431,
+5,18,59,26431,
+23,30,49,26431,
+19,38,45,26431,
+11,30,53,26431,
+4,30,54,26431,
+6,14,60,26431,
+12,18,58,26431,
+6,36,50,26431,
+16,21,56,26431,
+0,32,53,26431,
+25,38,42,26431,
+14,39,46,26431,
+28,32,45,26431,
+20,27,52,26431,
+10,22,57,26431,
+11,24,56,26431,
+18,22,55,26431,
+6,41,46,26431,
+8,13,60,26431,
+34,34,39,26448,
+20,25,53,26448,
+5,40,47,26448,
+7,8,61,26448,
+28,29,47,26448,
+21,33,48,26448,
+3,24,57,26448,
+3,15,60,26448,
+5,28,55,26448,
+8,17,59,26448,
+13,31,52,26448,
+16,37,47,26448,
+17,29,52,26448,
+1,32,53,26448,
+7,43,44,26448,
+3,39,48,26448,
+28,37,41,26448,
+12,33,51,26448,
+8,37,49,26448,
+12,21,57,26448,
+20,35,47,26448,
+31,32,43,26448,
+8,31,53,26448,
+23,37,44,26448,
+13,23,56,26448,
+17,39,45,26448,
+15,19,57,26448,
+33,35,39,26484,
+3,35,51,26484,
+9,27,55,26484,
+21,37,45,26484,
+11,40,46,26484,
+4,10,61,26484,
+5,26,56,26484,
+26,35,44,26484,
+32,37,38,26504,
+10,16,59,26504,
+2,32,53,26504,
+6,9,61,26504,
+9,34,51,26504,
+15,42,43,26504,
+30,33,43,26504,
+7,42,45,26504,
+27,30,47,26504,
+9,29,54,26504,
+4,39,48,26504,
+4,15,60,26504,
+4,24,57,26504,
+32,36,39,26533,
+14,27,54,26533,
+6,18,59,26533,
+21,30,50,26533,
+21,22,54,26533,
+12,36,49,26533,
+6,21,58,26533,
+24,31,48,26533,
+5,30,54,26533,
+12,43,43,26533,
+8,23,57,26533,
+0,11,61,26533,
+4,35,51,26533,
+13,37,48,26533,
+20,29,51,26533,
+3,32,53,26533,
+7,33,52,26533,
+0,19,59,26533,
+11,11,60,26533,
+9,25,56,26533,
+15,41,44,26533,
+27,33,45,26533,
+25,37,43,26533,
+1,19,59,26533,
+1,11,61,26533,
+17,23,55,26533,
+12,28,54,26533,
+0,0,62,26533,
+10,12,60,26533,
+28,36,42,26533,
+12,42,44,26533,
+20,41,42,26533,
+33,34,40,26561,
+20,23,54,26561,
+15,22,56,26561,
+9,20,58,26561,
+7,14,60,26561,
+0,1,62,26561,
+15,16,58,26561,
+6,40,47,26561,
+16,33,50,26561,
+7,36,50,26561,
+14,20,57,26561,
+12,26,55,26561,
+6,28,55,26561,
+0,38,49,26561,
+19,26,53,26561,
+22,31,49,26561,
+11,35,50,26561,
+1,1,62,26561,
+19,37,46,26561,
+17,34,49,26561,
+22,41,41,26561,
+11,19,58,26561,
+29,34,43,26561,
+14,29,53,26561,
+2,11,61,26561,
+2,19,59,26561,
+7,41,46,26561,
+1,38,49,26561,
+14,25,55,26561,
+26,31,47,26561,
+13,14,59,26561,
+5,10,61,26561,
+10,38,48,26561,
+6,26,56,26561,
+0,22,58,26561,
+22,40,42,26561,
+16,26,54,26561,
+24,34,46,26561,
+0,2,62,26561,
+18,32,50,26561,
+14,17,58,26561,
+4,32,53,26561,
+2,38,49,26561,
+8,8,61,26561,
+16,28,53,26561,
+8,43,44,26561,
+19,28,52,26561,
+11,32,52,26561,
+32,35,40,26611,
+1,2,62,26611,
+22,34,47,26611,
+1,22,58,26611,
+20,40,43,26611,
+31,38,38,26611,
+17,38,46,26611,
+14,38,47,26611,
+27,39,40,26611,
+15,32,51,26611,
+12,41,45,26611,
+12,15,59,26611,
+9,13,60,26611,
+23,36,45,26611,
+5,24,57,26611,
+15,40,45,26611,
+5,15,60,26611,
+5,39,48,26611,
+3,11,61,26611,
+17,31,51,26611,
+7,9,61,26611,
+9,37,49,26611,
+15,35,49,26611,
+9,17,59,26611,
+19,33,49,26611,
+11,39,47,26611,
+31,37,39,26629,
+5,35,51,26629,
+3,19,59,26629,
+9,31,53,26629,
+25,25,51,26629,
+18,42,42,26629,
+26,26,50,26629,
+6,30,54,26629,
+2,22,58,26629,
+2,2,62,26629,
+14,34,50,26629,
+21,36,46,26629,
+24,26,51,26629,
+18,35,48,26629,
+12,30,53,26629,
+0,3,62,26629,
+8,42,45,26629,
+19,24,54,26629,
+1,3,62,26629,
+7,21,58,26629,
+7,18,59,26629,
+22,39,43,26629,
+3,38,49,26629,
+25,27,50,26629,
+10,27,55,26629,
+27,38,41,26629,
+11,22,57,26629,
+18,41,43,26629,
+24,24,52,26629,
+0,16,60,26629,
+12,24,56,26629,
+16,36,48,26629,
+29,30,46,26629,
+3,22,58,26629,
+8,33,52,26629,
+26,34,45,26629,
+23,32,48,26629,
+31,36,40,26679,
+1,16,60,26679,
+20,39,44,26679,
+13,18,58,26679,
+25,36,44,26679,
+10,29,54,26679,
+24,40,41,26679,
+16,24,55,26679,
+6,10,61,26679,
+10,34,51,26679,
+2,3,62,26679,
+31,31,44,26679,
+5,32,53,26679,
+4,11,61,26679,
+23,25,52,26679,
+25,32,47,26679,
+19,19,56,26679,
+28,35,43,26679,
+4,19,59,26679,
+7,40,47,26679,
+11,16,59,26679,
+7,28,55,26679,
+13,21,57,26679,
+9,23,57,26679,
+27,27,49,26679,
+33,33,41,26700,
+23,27,51,26700,
+13,33,51,26700,
+20,34,48,26700,
+8,14,60,26700,
+18,20,56,26700,
+0,34,52,26700,
+2,16,60,26700,
+16,30,52,26700,
+18,40,44,26700,
+30,32,44,26700,
+12,40,46,26700,
+0,4,62,26700,
+8,36,50,26700,
+24,28,50,26700,
+6,15,60,26700,
+24,39,42,26700,
+14,31,52,26700,
+20,31,50,26700,
+14,23,56,26700,
+10,25,56,26700,
+1,34,52,26700,
+8,41,46,26700,
+28,31,46,26700,
+4,38,49,26700,
+6,39,48,26700,
+32,34,41,26726,
+7,26,56,26726,
+26,28,49,26726,
+1,4,62,26726,
+6,24,57,26726,
+15,39,46,26726,
+18,27,53,26726,
+27,37,42,26726,
+17,18,57,26726,
+3,3,62,26726,
+6,35,51,26726,
+19,30,51,26726,
+2,4,62,26726,
+4,22,58,26726,
+22,26,52,26726,
+22,38,44,26726,
+10,20,58,26726,
+2,34,52,26726,
+0,12,61,26726,
+11,12,60,26726,
+18,25,54,26726,
+3,16,60,26726,
+30,38,39,26750,
+7,30,54,26750,
+0,27,56,26750,
+1,12,61,26750,
+0,29,55,26750,
+1,27,56,26750,
+17,21,56,26750,
+20,21,55,26750,
+9,43,44,26750,
+16,19,57,26750,
+13,36,49,26750,
+21,32,49,26750,
+19,36,47,26750,
+8,9,61,26750,
+29,33,44,26750,
+25,29,49,26750,
+1,29,55,26750,
+5,19,59,26750,
+23,23,53,26750,
+5,11,61,26750,
+31,35,41,26770,
+17,37,47,26770,
+13,43,43,26770,
+3,34,52,26770,
+24,38,43,26770,
+0,37,50,26770,
+13,28,54,26770,
+22,28,51,26770,
+0,5,62,26770,
+10,13,60,26770,
+16,42,43,26770,
+8,18,59,26770,
+13,42,44,26770,
+8,21,58,26770,
+12,35,50,26770,
+2,27,56,26770,
+11,38,48,26770,
+22,24,53,26770,
+30,37,40,26785,
+27,32,46,26785,
+20,38,45,26785,
+3,4,62,26785,
+2,12,61,26785,
+6,32,53,26785,
+12,19,58,26785,
+18,29,52,26785,
+14,37,48,26785,
+10,37,49,26785,
+1,5,62,26785,
+19,22,55,26785,
+5,38,49,26785,
+10,17,59,26785,
+10,31,53,26785,
+13,26,55,26785,
+18,39,45,26785,
+9,42,45,26785,
+15,27,54,26785,
+7,10,61,26785,
+1,37,50,26785,
+23,29,50,26785,
+23,35,46,26785,
+2,29,55,26785,
+0,44,44,26785,
+4,16,60,26785,
+28,28,48,26785,
+12,32,52,26785,
+8,28,55,26785,
+2,37,50,26785,
+14,14,59,26785,
+2,5,62,26785,
+5,22,58,26785,
+1,44,44,26785,
+16,41,44,26785,
+8,40,47,26785,
+0,43,45,26785,
+7,39,48,26785,
+24,33,47,26785,
+12,39,47,26785,
+7,15,60,26785,
+27,36,43,26799,
+0,25,57,26799,
+21,27,52,26799,
+7,24,57,26799,
+27,29,48,26799,
+3,27,56,26799,
+15,20,57,26799,
+9,33,52,26799,
+3,12,61,26799,
+25,35,45,26799,
+21,35,47,26799,
+7,35,51,26799,
+21,25,53,26799,
+1,25,57,26799,
+3,29,55,26799,
+15,29,53,26799,
+13,15,59,26799,
+15,25,55,26799,
+13,41,45,26799,
+11,27,55,26799,
+1,43,45,26799,
+26,40,40,26804,
+8,26,56,26804,
+4,4,62,26804,
+16,22,56,26804,
+16,16,58,26804,
+4,34,52,26804,
+28,34,44,26804,
+2,44,44,26804,
+30,36,41,26841,
+22,33,48,26841,
+9,14,60,26841,
+32,33,42,26841,
+0,31,54,26841,
+24,30,49,26841,
+9,36,50,26841,
+12,22,57,26841,
+18,23,55,26841,
+17,33,50,26841,
+15,38,47,26841,
+2,25,57,26841,
+3,37,50,26841,
+6,19,59,26841,
+1,31,54,26841,
+6,11,61,26841,
+9,41,46,26841,
+13,30,53,26841,
+11,29,54,26841,
+11,34,51,26841,
+2,43,45,26841,
+15,17,58,26841,
+22,37,45,26841,
+3,5,62,26841,
+10,23,57,26841,
+26,39,41,26841,
+0,6,62,26841,
+26,30,48,26841,
+0,42,46,26841,
+8,30,54,26841,
+31,34,42,26862,
+24,37,44,26862,
+4,27,56,26862,
+16,40,45,26862,
+1,42,46,26862,
+0,20,59,26862,
+18,34,49,26862,
+13,24,56,26862,
+2,31,54,26862,
+6,38,49,26862,
+15,34,50,26862,
+1,6,62,26862,
+26,33,46,26862,
+17,26,54,26862,
+12,16,59,26862,
+4,12,61,26862,
+16,32,51,26862,
+3,44,44,26862,
+5,16,60,26862,
+1,20,59,26862,
+16,35,49,26862,
+17,28,53,26862,
+11,25,56,26862,
+7,32,53,26862,
+4,29,55,26862,
+9,9,61,26862,
+3,25,57,26862,
+3,43,45,26862,
+29,39,39,26888,
+21,29,51,26888,
+14,18,58,26888,
+22,22,54,26888,
+22,30,50,26888,
+26,38,42,26888,
+6,22,58,26888,
+2,6,62,26888,
+18,38,46,26888,
+2,42,46,26888,
+11,20,58,26888,
+19,32,50,26888,
+8,10,61,26888,
+20,37,46,26888,
+10,43,44,26888,
+13,40,46,26888,
+4,5,62,26888,
+20,26,53,26888,
+29,38,40,26918,
+2,20,59,26918,
+5,34,52,26918,
+4,37,50,26918,
+21,41,42,26918,
+18,31,51,26918,
+14,21,57,26918,
+9,21,58,26918,
+9,18,59,26918,
+14,33,51,26918,
+3,31,54,26918,
+30,31,45,26918,
+21,23,54,26918,
+4,44,44,26918,
+12,12,60,26918,
+36,36,36,26993,
+20,28,52,26993,
+3,6,62,26993,
+8,15,60,26993,
+10,42,45,26993,
+30,35,42,26993,
+19,42,42,26993,
+0,17,60,26993,
+17,36,48,26993,
+8,24,57,26993,
+3,42,46,26993,
+8,39,48,26993,
+11,13,60,26993,
+5,12,61,26993,
+0,41,47,26993,
+35,36,37,27019,
+9,28,55,27019,
+17,24,55,27019,
+19,35,48,27019,
+3,20,59,27019,
+1,17,60,27019,
+29,32,45,27019,
+15,31,52,27019,
+4,25,57,27019,
+4,43,45,27019,
+20,33,49,27019,
+25,31,48,27019,
+0,13,61,27019,
+8,35,51,27019,
+5,27,56,27019,
+21,40,43,27019,
+15,23,56,27019,
+27,35,44,27019,
+9,40,47,27019,
+5,29,55,27019,
+7,19,59,27019,
+23,41,41,27019,
+29,37,41,27019,
+23,31,49,27019,
+1,13,61,27019,
+19,41,43,27019,
+11,31,53,27019,
+11,17,59,27019,
+7,11,61,27019,
+11,37,49,27019,
+1,41,47,27019,
+29,29,47,27019,
+20,24,54,27019,
+6,16,60,27019,
+12,38,48,27019,
+10,33,52,27019,
+16,39,46,27019,
+2,17,60,27019,
+9,26,56,27019,
+0,7,62,27019,
+4,31,54,27019,
+0,23,58,27019,
+17,30,52,27019,
+14,36,49,27019,
+23,40,42,27019,
+28,30,47,27019,
+13,35,50,27019,
+7,38,49,27019,
+2,13,61,27019,
+35,35,38,27046,
+2,41,47,27046,
+1,23,58,27046,
+1,7,62,27046,
+14,43,43,27046,
+23,34,47,27046,
+34,37,37,27046,
+26,37,43,27046,
+5,5,62,27046,
+13,19,58,27046,
+5,37,50,27046,
+14,42,44,27046,
+10,14,60,27046,
+10,36,50,27046,
+22,36,46,27046,
+14,28,54,27046,
+6,34,52,27046,
+4,42,46,27046,
+4,6,62,27046,
+34,36,38,27063,
+25,34,46,27063,
+2,23,58,27063,
+14,26,55,27063,
+8,32,53,27063,
+13,32,52,27063,
+24,36,45,27063,
+9,30,54,27063,
+10,41,46,27063,
+0,36,51,27063,
+2,7,62,27063,
+19,20,56,27063,
+7,22,58,27063,
+32,32,43,27063,
+4,20,59,27063,
+19,40,44,27063,
+18,18,57,27063,
+5,44,44,27063,
+0,33,53,27063,
+3,17,60,27063,
+21,39,44,27063,
+12,27,55,27063,
+1,36,51,27063,
+15,37,48,27063,
+28,33,45,27063,
+27,31,47,27063,
+19,27,53,27063,
+17,19,57,27063,
+5,43,45,27063,
+23,39,43,27063,
+11,23,57,27063,
+3,41,47,27063,
+5,25,57,27063,
+13,39,47,27063,
+1,33,53,27063,
+31,33,43,27063,
+3,13,61,27063,
+29,36,42,27076,
+2,36,51,27076,
+6,12,61,27076,
+16,27,54,27076,
+6,27,56,27076,
+20,30,51,27076,
+18,21,56,27076,
+12,29,54,27076,
+21,34,48,27076,
+12,34,51,27076,
+34,35,39,27126,
+9,10,61,27126,
+14,15,59,27126,
+19,25,54,27126,
+2,33,53,27126,
+13,22,57,27126,
+33,37,38,27126,
+3,23,58,27126,
+25,26,51,27126,
+6,29,55,27126,
+21,31,50,27126,
+17,42,43,27126,
+18,37,47,27126,
+3,7,62,27126,
+14,41,45,27126,
+5,31,54,27126,
+24,32,48,27126,
+0,40,48,27126,
+1,40,48,27126,
+24,25,52,27126,
+10,18,59,27126,
+28,39,40,27126,
+20,36,47,27126,
+16,20,57,27126,
+10,21,58,27126,
+6,37,50,27126,
+5,6,62,27126,
+30,34,43,27126,
+5,42,46,27126,
+4,17,60,27126,
+7,16,60,27126,
+26,27,50,27126,
+14,30,53,27126,
+12,25,56,27126,
+4,41,47,27126,
+33,36,39,27160,
+8,11,61,27160,
+9,39,48,27160,
+11,43,44,27160,
+9,15,60,27160,
+19,29,52,27160,
+3,36,51,27160,
+16,25,55,27160,
+25,40,41,27160,
+5,20,59,27160,
+4,13,61,27160,
+16,29,53,27160,
+13,16,59,27160,
+9,24,57,27160,
+17,41,44,27160,
+24,27,51,27160,
+8,19,59,27160,
+21,21,55,27160,
+3,33,53,27160,
+9,35,51,27160,
+19,39,45,27160,
+6,44,44,27160,
+14,24,56,27160,
+2,40,48,27160,
+0,8,62,27160,
+26,36,44,27160,
+12,20,58,27160,
+16,38,47,27160,
+8,38,49,27160,
+10,40,47,27160,
+4,7,62,27160,
+10,28,55,27160,
+26,32,47,27160,
+16,17,58,27160,
+4,23,58,27160,
+23,38,44,27160,
+23,26,52,27160,
+17,22,56,27160,
+28,38,41,27160,
+20,22,55,27160,
+25,28,50,27160,
+22,32,49,27160,
+1,8,62,27160,
+7,34,52,27160,
+11,42,45,27160,
+21,38,45,27160,
+6,43,45,27160,
+27,34,45,27160,
+6,25,57,27160,
+25,39,42,27160,
+16,34,50,27160,
+10,26,56,27160,
+2,8,62,27160,
+8,22,58,27160,
+14,40,46,27160,
+34,34,40,27207,
+32,38,38,27207,
+18,33,50,27207,
+15,18,58,27207,
+3,40,48,27207,
+4,36,51,27207,
+6,31,54,27207,
+12,13,60,27207,
+11,33,52,27207,
+17,32,51,27207,
+23,28,51,27207,
+32,37,39,27226,
+33,35,40,27226,
+23,24,53,27226,
+7,12,61,27226,
+27,28,49,27226,
+7,27,56,27226,
+12,37,49,27226,
+4,33,53,27226,
+17,40,45,27226,
+12,17,59,27226,
+5,17,60,27226,
+9,32,53,27226,
+12,31,53,27226,
+5,13,61,27226,
+29,35,43,27226,
+7,29,55,27226,
+15,33,51,27226,
+15,21,57,27226,
+5,41,47,27226,
+17,35,49,27226,
+19,23,55,27226,
+6,6,62,27226,
+10,30,54,27226,
+6,42,46,27226,
+30,30,46,27226,
+18,26,54,27226,
+13,38,48,27226,
+24,35,46,27226,
+6,20,59,27226,
+0,14,61,27226,
+28,37,42,27226,
+11,14,60,27226,
+22,27,52,27226,
+18,28,53,27226,
+24,29,50,27226,
+3,8,62,27226,
+11,36,50,27226,
+22,25,53,27226,
+25,38,43,27226,
+26,29,49,27226,
+29,31,46,27226,
+19,34,49,27226,
+22,35,47,27226,
+11,41,46,27226,
+5,7,62,27226,
+7,37,50,27226,
+1,14,61,27226,
+5,23,58,27226,
+0,28,56,27226,
+32,36,40,27275,
+8,16,60,27275,
+4,40,48,27275,
+16,23,56,27275,
+7,44,44,27275,
+16,31,52,27275,
+2,14,61,27275,
+10,10,61,27275,
+14,19,58,27275,
+31,32,44,27275,
+14,35,50,27275,
+1,28,56,27275,
+19,38,46,27275,
+0,21,59,27275,
+15,36,49,27275,
+23,33,48,27275,
+0,39,49,27275,
+12,23,57,27275,
+5,36,51,27275,
+7,43,45,27275,
+5,33,53,27275,
+13,27,55,27275,
+19,31,51,27275,
+1,21,59,27275,
+9,19,59,27275,
+25,33,47,27275,
+15,43,43,27275,
+7,25,57,27275,
+23,37,45,27275,
+9,11,61,27275,
+1,39,49,27275,
+18,36,48,27275,
+4,8,62,27275,
+28,32,46,27275,
+14,32,52,27275,
+20,32,50,27275,
+8,34,52,27275,
+0,18,60,27275,
+2,28,56,27275,
+15,28,54,27275,
+1,18,60,27275,
+10,39,48,27275,
+0,9,62,27275,
+18,24,55,27275,
+0,30,55,27275,
+0,26,57,27275,
+6,17,60,27275,
+10,15,60,27275,
+30,33,44,27291,
+15,42,44,27291,
+10,24,57,27291,
+1,30,55,27291,
+21,37,46,27291,
+22,29,51,27291,
+11,18,59,27291,
+1,26,57,27291,
+3,14,61,27291,
+31,38,39,27334,
+13,34,51,27334,
+17,39,46,27334,
+13,29,54,27334,
+10,35,51,27334,
+33,34,41,27334,
+21,26,53,27334,
+2,21,59,27334,
+7,31,54,27334,
+9,38,49,27334,
+6,13,61,27334,
+1,9,62,27334,
+26,35,45,27334,
+14,39,47,27334,
+6,41,47,27334,
+25,30,49,27334,
+2,39,49,27334,
+11,21,58,27334,
+15,26,55,27334,
+2,18,60,27334,
+18,30,52,27334,
+20,42,42,27334,
+22,41,42,27334,
+21,28,52,27334,
+8,12,61,27334,
+5,40,48,27334,
+6,23,58,27334,
+8,27,56,27334,
+28,29,48,27334,
+3,28,56,27334,
+9,22,58,27334,
+0,35,52,27334,
+2,26,57,27334,
+27,40,40,27334,
+14,22,57,27334,
+6,7,62,27334,
+2,30,55,27334,
+12,43,44,27334,
+28,36,43,27334,
+20,35,48,27334,
+16,37,48,27334,
+7,42,46,27334,
+23,30,50,27334,
+2,9,62,27334,
+22,23,54,27334,
+32,35,41,27387,
+31,37,40,27387,
+11,28,55,27387,
+8,29,55,27387,
+11,40,47,27387,
+13,25,56,27387,
+1,35,52,27387,
+7,20,59,27387,
+25,37,44,27387,
+20,41,43,27387,
+3,39,49,27387,
+21,33,49,27387,
+3,21,59,27387,
+15,15,59,27387,
+15,41,45,27387,
+27,39,41,27387,
+22,40,43,27387,
+5,8,62,27387,
+3,18,60,27387,
+14,16,59,27387,
+4,14,61,27387,
+2,35,52,27387,
+8,37,50,27387,
+11,26,56,27387,
+27,30,48,27387,
+29,34,44,27387,
+10,32,53,27387,
+21,24,54,27387,
+6,36,51,27387,
+12,42,45,27387,
+13,20,58,27387,
+6,33,53,27387,
+15,30,53,27387,
+3,26,57,27387,
+3,30,55,27387,
+17,27,54,27387,
+18,19,57,27387,
+3,9,62,27387,
+27,33,46,27387,
+4,28,56,27387,
+8,44,44,27387,
+20,20,56,27387,
+20,40,44,27387,
+27,38,42,27406,
+12,33,52,27406,
+15,24,56,27406,
+9,16,60,27406,
+11,30,54,27406,
+18,42,43,27406,
+17,20,57,27406,
+4,39,49,27406,
+31,36,41,27448,
+20,27,53,27448,
+19,21,56,27448,
+8,25,57,27448,
+8,43,45,27448,
+24,31,49,27448,
+3,35,52,27448,
+7,17,60,27448,
+4,21,59,27448,
+24,41,41,27448,
+13,13,60,27448,
+13,31,53,27448,
+17,25,55,27448,
+19,37,47,27448,
+13,37,49,27448,
+17,29,53,27448,
+13,17,59,27448,
+7,41,47,27448,
+7,13,61,27448,
+12,14,60,27448,
+6,40,48,27448,
+4,18,60,27448,
+0,24,58,27448,
+24,40,42,27448,
+0,32,54,27448,
+12,36,50,27448,
+23,36,46,27448,
+4,9,62,27448,
+1,24,58,27448,
+9,34,52,27448,
+26,31,48,27448,
+4,26,57,27448,
+24,34,47,27448,
+12,41,46,27448,
+1,32,54,27448,
+18,41,44,27448,
+20,25,54,27448,
+8,31,54,27448,
+15,40,46,27448,
+4,30,55,27448,
+22,39,44,27448,
+7,7,62,27448,
+30,39,39,27491,
+10,11,61,27491,
+7,23,58,27491,
+17,17,58,27491,
+5,14,61,27491,
+10,19,59,27491,
+33,33,42,27491,
+17,38,47,27491,
+21,30,51,27491,
+30,38,40,27506,
+22,34,48,27506,
+0,38,50,27506,
+0,10,62,27506,
+8,42,46,27506,
+14,38,48,27506,
+32,34,42,27506,
+6,8,62,27506,
+2,24,58,27506,
+16,18,58,27506,
+18,22,56,27506,
+2,32,54,27506,
+17,34,50,27506,
+1,10,62,27506,
+8,20,59,27506,
+5,28,56,27506,
+28,35,44,27506,
+22,31,50,27506,
+10,38,49,27506,
+1,38,50,27506,
+4,35,52,27506,
+20,29,52,27506,
+7,36,51,27506,
+11,24,57,27506,
+25,36,45,27506,
+20,39,45,27506,
+16,21,57,27506,
+16,33,51,27506,
+9,27,56,27506,
+9,12,61,27506,
+21,36,47,27506,
+11,39,48,27506,
+0,15,61,27506,
+11,15,60,27506,
+24,39,43,27506,
+11,35,51,27506,
+27,37,43,27506,
+31,31,45,27506,
+13,23,57,27506,
+1,15,61,27506,
+5,21,59,27506,
+5,39,49,27506,
+9,29,55,27506,
+7,33,53,27506,
+26,34,46,27506,
+2,10,62,27506,
+2,38,50,27506,
+10,22,58,27506,
+3,24,58,27506,
+12,21,58,27506,
+18,40,45,27506,
+3,32,54,27506,
+12,18,59,27506,
+5,18,60,27506,
+30,32,45,27518,
+18,32,51,27518,
+5,9,62,27518,
+15,19,58,27518,
+21,22,55,27518,
+5,30,55,27518,
+5,26,57,27518,
+19,33,50,27518,
+15,35,50,27518,
+30,37,41,27560,
+9,37,50,27560,
+31,35,42,27560,
+2,15,61,27560,
+29,30,47,27560,
+18,35,49,27560,
+14,27,55,27560,
+16,36,49,27560,
+25,32,48,27560,
+9,44,44,27560,
+19,26,54,27560,
+12,28,55,27560,
+3,38,50,27560,
+3,10,62,27560,
+7,40,48,27560,
+12,40,47,27560,
+26,26,51,27560,
+22,38,45,27560,
+14,29,54,27560,
+8,17,60,27560,
+15,32,52,27560,
+14,34,51,27560,
+6,14,61,27560,
+16,43,43,27560,
+23,32,49,27560,
+13,43,44,27560,
+19,28,53,27560,
+8,13,61,27560,
+5,35,52,27560,
+17,23,56,27560,
+20,23,55,27560,
+11,32,53,27560,
+28,31,47,27560,
+8,41,47,27560,
+17,31,52,27560,
+25,25,52,27560,
+29,33,45,27570,
+9,25,57,27570,
+3,15,61,27570,
+15,39,47,27570,
+25,27,51,27570,
+9,43,45,27570,
+6,28,56,27570,
+24,38,44,27570,
+12,26,56,27570,
+4,24,58,27570,
+4,32,54,27570,
+24,26,52,27570,
+16,28,54,27570,
+16,42,44,27570,
+10,16,60,27570,
+26,40,41,27587,
+8,23,58,27587,
+14,25,56,27587,
+20,34,49,27587,
+7,8,62,27587,
+16,26,55,27587,
+27,27,50,27587,
+6,39,49,27587,
+15,22,57,27587,
+13,42,45,27587,
+9,31,54,27587,
+6,21,59,27587,
+20,38,46,27587,
+30,36,42,27644,
+6,18,60,27644,
+26,28,50,27644,
+14,20,58,27644,
+4,38,50,27644,
+4,10,62,27644,
+12,30,54,27644,
+10,34,52,27644,
+8,36,51,27644,
+24,28,51,27644,
+19,36,48,27644,
+6,9,62,27644,
+26,39,42,27644,
+6,26,57,27644,
+6,30,55,27644,
+27,36,44,27644,
+0,19,60,27644,
+0,44,45,27644,
+18,39,46,27644,
+9,42,46,27644,
+36,36,37,27699,
+24,24,53,27699,
+20,31,51,27699,
+1,19,60,27699,
+9,20,59,27699,
+1,44,45,27699,
+32,33,43,27699,
+4,15,61,27699,
+19,24,55,27699,
+16,41,45,27699,
+23,27,52,27699,
+13,33,52,27699,
+29,39,40,27699,
+27,32,47,27699,
+15,16,59,27699,
+8,33,53,27699,
+17,37,48,27699,
+11,11,61,27699,
+23,25,53,27699,
+35,37,37,27724,
+11,19,59,27724,
+23,35,47,27724,
+35,36,38,27735,
+2,19,60,27735,
+0,34,53,27735,
+21,32,50,27735,
+16,30,53,27735,
+13,14,60,27735,
+10,12,61,27735,
+0,11,62,27735,
+13,36,50,27735,
+0,43,46,27735,
+5,24,58,27735,
+0,22,59,27735,
+5,32,54,27735,
+19,30,52,27735,
+10,27,56,27735,
+28,34,45,27735,
+2,44,45,27735,
+6,35,52,27735,
+7,14,61,27735,
+31,34,43,27735,
+13,41,46,27735,
+14,37,49,27735,
+14,31,53,27735,
+25,35,46,27735,
+14,17,59,27735,
+1,11,62,27735,
+11,38,49,27735,
+1,43,46,27735,
+1,34,53,27735,
+29,38,41,27735,
+10,29,55,27735,
+1,22,59,27735,
+25,29,50,27735,
+16,24,56,27735,
+8,40,48,27735,
+5,10,62,27735,
+24,33,48,27735,
+12,39,48,27735,
+21,42,42,27735,
+11,22,58,27735,
+26,38,43,27735,
+10,37,50,27735,
+34,37,38,27751,
+2,22,59,27751,
+12,15,60,27751,
+22,26,53,27751,
+12,24,57,27751,
+7,28,56,27751,
+18,27,54,27751,
+5,38,50,27751,
+22,37,46,27751,
+2,34,53,27751,
+2,43,46,27751,
+0,0,63,27751,
+28,28,49,27751,
+2,11,62,27751,
+12,35,51,27751,
+3,44,45,27751,
+3,19,60,27751,
+9,17,60,27751,
+21,35,48,27751,
+0,1,63,27751,
+0,37,51,27751,
+24,37,45,27751,
+5,15,61,27751,
+7,21,59,27751,
+1,37,51,27751,
+7,39,49,27751,
+23,29,51,27751,
+19,19,57,27751,
+1,1,63,27751,
+9,13,61,27751,
+21,41,43,27751,
+9,41,47,27751,
+35,35,39,27779,
+27,29,49,27779,
+16,40,46,27779,
+8,8,62,27779,
+10,44,44,27779,
+22,28,52,27779,
+15,38,48,27779,
+0,2,63,27779,
+0,42,47,27779,
+7,18,60,27779,
+18,20,57,27779,
+34,36,39,27808,
+1,42,47,27808,
+30,35,43,27808,
+3,11,62,27808,
+1,2,63,27808,
+3,34,53,27808,
+13,18,59,27808,
+23,23,54,27808,
+10,25,57,27808,
+7,26,57,27808,
+14,23,57,27808,
+29,37,42,27808,
+2,37,51,27808,
+7,30,55,27808,
+26,33,47,27808,
+9,23,58,27808,
+10,43,45,27808,
+19,42,43,27808,
+18,25,55,27808,
+3,22,59,27808,
+3,43,46,27808,
+23,41,42,27808,
+7,9,62,27808,
+13,21,58,27808,
+18,29,53,27808,
+22,33,49,27808,
+24,30,50,27808,
+22,24,54,27808,
+6,24,58,27808,
+6,32,54,27808,
+10,31,54,27808,
+18,38,47,27808,
+11,16,60,27808,
+2,42,47,27808,
+12,32,53,27808,
+17,18,58,27808,
+21,40,44,27808,
+0,16,61,27808,
+20,21,56,27808,
+33,38,38,27838,
+0,29,56,27838,
+2,2,63,27838,
+26,30,49,27838,
+4,19,60,27838,
+30,31,46,27838,
+4,44,45,27838,
+13,40,47,27838,
+1,29,56,27838,
+0,3,63,27838,
+13,28,55,27838,
+0,27,57,27838,
+20,37,47,27838,
+1,16,61,27838,
+19,41,44,27838,
+7,35,52,27838,
+23,40,43,27838,
+9,36,51,27838,
+3,37,51,27838,
+15,27,55,27838,
+17,21,57,27838,
+21,27,53,27838,
+33,37,39,27854,
+1,27,57,27854,
+27,35,45,27854,
+9,33,53,27854,
+1,3,63,27854,
+17,33,51,27854,
+18,34,50,27854,
+6,38,50,27854,
+10,42,46,27854,
+6,10,62,27854,
+16,35,50,27854,
+4,22,59,27854,
+4,11,62,27854,
+13,26,56,27854,
+19,22,56,27854,
+4,34,53,27854,
+11,34,52,27854,
+4,43,46,27854,
+26,37,44,27854,
+8,14,61,27854,
+16,19,58,27854,
+2,16,61,27854,
+34,35,40,27875,
+14,43,44,27875,
+2,29,56,27875,
+29,32,46,27875,
+10,20,59,27875,
+21,25,54,27875,
+15,34,51,27875,
+15,29,54,27875,
+6,15,61,27875,
+3,42,47,27875,
+2,27,57,27875,
+2,3,63,27875,
+32,32,44,27875,
+28,40,40,27875,
+8,28,56,27875,
+16,32,52,27875,
+0,4,63,27875,
+14,42,45,27875,
+9,40,48,27875,
+0,41,48,27875,
+22,30,51,27875,
+13,30,54,27875,
+33,36,40,27914,
+8,39,49,27914,
+0,31,55,27914,
+21,29,52,27914,
+11,27,56,27914,
+19,32,51,27914,
+28,39,41,27914,
+29,36,43,27914,
+5,19,60,27914,
+16,39,47,27914,
+11,12,61,27914,
+12,19,59,27914,
+17,36,49,27914,
+1,4,63,27914,
+3,16,61,27914,
+4,37,51,27914,
+29,29,48,27914,
+31,33,44,27914,
+19,40,45,27914,
+8,21,59,27914,
+15,25,56,27914,
+5,44,45,27914,
+1,41,48,27914,
+23,39,44,27914,
+3,29,56,27914,
+3,27,57,27914,
+25,31,49,27914,
+11,29,55,27914,
+1,31,55,27914,
+21,39,45,27914,
+17,43,43,27914,
+25,41,41,27914,
+3,3,63,27914,
+19,35,49,27914,
+24,36,46,27914,
+28,30,48,27914,
+8,18,60,27914,
+0,12,62,27914,
+2,41,48,27914,
+17,28,54,27914,
+23,34,48,27914,
+17,42,44,27914,
+18,23,56,27914,
+1,12,62,27914,
+16,22,57,27914,
+8,30,55,27914,
+28,33,46,27914,
+10,17,60,27914,
+12,38,49,27914,
+2,4,63,27914,
+8,9,62,27914,
+7,32,54,27914,
+4,42,47,27914,
+7,24,58,27914,
+32,38,39,27961,
+8,26,57,27961,
+14,33,52,27961,
+22,36,47,27961,
+20,33,50,27961,
+15,20,58,27961,
+25,40,42,27961,
+0,25,58,27961,
+18,31,52,27961,
+5,34,53,27961,
+5,43,46,27961,
+1,25,58,27961,
+10,41,47,27961,
+11,37,50,27961,
+17,26,55,27961,
+23,31,50,27961,
+2,31,55,27961,
+10,13,61,27961,
+5,11,62,27961,
+25,34,47,27961,
+5,22,59,27961,
+2,12,62,27961,
+12,22,58,27961,
+20,26,54,27961,
+30,34,44,27961,
+28,38,42,27961,
+14,36,50,27961,
+14,14,60,27961,
+32,37,40,27986,
+10,23,58,27986,
+16,16,59,27986,
+8,35,52,27986,
+7,38,50,27986,
+22,22,55,27986,
+4,16,61,27986,
+2,25,58,27986,
+14,41,46,27986,
+20,28,53,27986,
+7,10,62,27986,
+34,34,41,27986,
+4,29,56,27986,
+11,44,44,27986,
+0,5,63,27986,
+3,4,63,27986,
+27,31,48,27986,
+3,41,48,27986,
+4,27,57,27986,
+13,39,48,27986,
+13,15,60,27986,
+13,24,57,27986,
+13,35,51,27986,
+5,37,51,27986,
+33,35,41,28004,
+15,17,59,28004,
+25,39,43,28004,
+21,23,55,28004,
+17,41,45,28004,
+15,31,53,28004,
+1,5,63,28004,
+7,15,61,28004,
+15,37,49,28004,
+11,43,45,28004,
+3,31,55,28004,
+11,25,57,28004,
+6,44,45,28004,
+3,12,62,28004,
+18,37,48,28004,
+10,36,51,28004,
+26,36,45,28004,
+6,19,60,28004,
+9,14,61,28004,
+5,42,47,28004,
+19,39,46,28004,
+23,38,45,28004,
+3,25,58,28004,
+2,5,63,28004,
+10,33,53,28004,
+17,30,53,28004,
+21,34,49,28004,
+11,31,54,28004,
+0,20,60,28004,
+0,36,52,28004,
+12,16,60,28004,
+20,36,48,28004,
+11,42,46,28004,
+24,32,49,28004,
+1,36,52,28004,
+32,36,41,28059,
+14,21,58,28059,
+20,24,55,28059,
+4,41,48,28059,
+0,40,49,28059,
+6,43,46,28059,
+6,34,53,28059,
+14,18,59,28059,
+4,4,63,28059,
+9,28,56,28059,
+21,38,46,28059,
+17,24,56,28059,
+6,11,62,28059,
+27,34,46,28059,
+6,22,59,28059,
+1,20,60,28059,
+28,37,43,28059,
+13,32,53,28059,
+5,16,61,28059,
+5,29,56,28059,
+1,40,49,28059,
+11,20,59,28059,
+29,35,44,28059,
+4,31,55,28059,
+3,5,63,28059,
+31,39,39,28090,
+15,23,57,28090,
+9,21,59,28090,
+9,39,49,28090,
+21,31,51,28090,
+5,27,57,28090,
+26,32,48,28090,
+4,12,62,28090,
+2,20,60,28090,
+12,34,52,28090,
+16,38,48,28090,
+20,30,52,28090,
+8,32,54,28090,
+10,40,48,28090,
+2,36,52,28090,
+8,24,58,28090,
+0,6,63,28090,
+14,28,55,28090,
+9,18,60,28090,
+14,40,47,28090,
+0,33,54,28090,
+17,40,46,28090,
+2,40,49,28090,
+4,25,58,28090,
+25,26,52,28090,
+31,38,40,28101,
+25,38,44,28101,
+9,9,62,28101,
+6,37,51,28101,
+19,27,54,28101,
+9,26,57,28101,
+1,6,63,28101,
+9,30,55,28101,
+1,33,54,28101,
+26,27,51,28101,
+14,26,56,28101,
+22,32,50,28101,
+8,10,62,28101,
+8,38,50,28101,
+6,42,47,28101,
+30,30,47,28101,
+2,33,54,28101,
+3,20,60,28101,
+12,12,61,28101,
+24,27,52,28101,
+12,27,56,28101,
+2,6,63,28101,
+33,34,42,28143,
+3,36,52,28143,
+3,40,49,28143,
+7,19,60,28143,
+0,23,59,28143,
+24,25,53,28143,
+7,44,45,28143,
+5,41,48,28143,
+4,5,63,28143,
+19,20,57,28143,
+31,32,45,28143,
+9,35,52,28143,
+24,35,47,28143,
+12,29,55,28143,
+27,40,41,28143,
+11,17,60,28143,
+15,43,44,28143,
+16,27,55,28143,
+0,17,61,28143,
+25,28,51,28143,
+8,15,61,28143,
+1,23,59,28143,
+5,31,55,28143,
+11,41,47,28143,
+13,19,59,28143,
+29,31,47,28143,
+19,29,53,28143,
+11,13,61,28143,
+31,37,41,28163,
+19,25,55,28163,
+1,17,61,28163,
+22,42,42,28163,
+18,18,58,28163,
+14,30,54,28163,
+0,13,62,28163,
+16,34,51,28163,
+6,16,61,28163,
+5,12,62,28163,
+16,29,54,28163,
+20,42,43,28163,
+22,35,48,28163,
+12,37,50,28163,
+32,35,42,28182,
+6,29,56,28182,
+27,28,50,28182,
+23,26,53,28182,
+5,25,58,28182,
+22,41,43,28182,
+7,43,46,28182,
+2,17,61,28182,
+7,11,62,28182,
+17,19,58,28182,
+7,22,59,28182,
+15,42,45,28182,
+3,33,54,28182,
+18,33,51,28182,
+11,23,58,28182,
+18,21,57,28182,
+30,33,45,28182,
+17,35,50,28182,
+1,13,62,28182,
+13,38,49,28182,
+27,39,42,28182,
+19,38,47,28182,
+2,23,59,28182,
+7,34,53,28182,
+6,27,57,28182,
+3,6,63,28182,
+23,37,46,28182,
+28,36,44,28182,
+4,20,60,28182,
+4,36,52,28182,
+12,44,44,28182,
+19,34,50,28182,
+26,35,46,28182,
+4,40,49,28182,
+13,22,58,28182,
+2,13,62,28182,
+10,14,61,28182,
+16,25,56,28182,
+20,41,44,28182,
+26,29,50,28182,
+23,28,52,28182,
+17,32,52,28182,
+28,32,47,28182,
+12,43,45,28182,
+25,33,48,28182,
+0,7,63,28182,
+11,36,51,28182,
+15,33,52,28182,
+12,25,57,28182,
+24,29,51,28182,
+21,21,56,28182,
+1,7,63,28182,
+23,33,49,28182,
+7,37,51,28182,
+3,17,61,28182,
+5,5,63,28182,
+17,39,47,28182,
+3,23,59,28182,
+21,37,47,28182,
+25,37,45,28182,
+11,33,53,28182,
+20,22,56,28182,
+22,40,44,28182,
+10,28,56,28182,
+16,20,58,28182,
+14,24,57,28182,
+0,39,50,28182,
+4,33,54,28182,
+12,31,54,28182,
+4,6,63,28182,
+9,32,54,28182,
+9,24,58,28182,
+18,36,49,28182,
+14,15,60,28182,
+30,39,40,28253,
+23,24,54,28253,
+31,36,42,28253,
+14,39,48,28253,
+24,41,42,28253,
+15,36,50,28253,
+6,41,48,28253,
+14,35,51,28253,
+22,27,53,28253,
+10,21,59,28253,
+29,34,45,28253,
+15,41,46,28253,
+7,42,47,28253,
+3,13,62,28253,
+1,39,50,28253,
+27,38,43,28253,
+6,31,55,28253,
+2,7,63,28253,
+17,22,57,28253,
+18,43,43,28253,
+10,39,49,28253,
+18,42,44,28253,
+10,18,60,28253,
+6,12,62,28253,
+12,42,46,28253,
+18,28,54,28253,
+6,25,58,28253,
+2,39,50,28253,
+9,10,62,28253,
+20,32,51,28253,
+9,38,50,28253,
+10,26,57,28253,
+8,44,45,28253,
+5,20,60,28253,
+10,30,55,28253,
+8,19,60,28253,
+30,38,41,28288,
+18,26,55,28288,
+5,36,52,28288,
+11,40,48,28288,
+25,30,50,28288,
+22,25,54,28288,
+13,16,60,28288,
+20,40,45,28288,
+24,40,43,28288,
+12,20,59,28288,
+19,31,52,28288,
+4,23,59,28288,
+16,31,53,28288,
+5,40,49,28288,
+4,17,61,28288,
+16,17,59,28288,
+19,23,56,28288,
+7,29,56,28288,
+20,35,49,28288,
+7,16,61,28288,
+28,29,49,28288,
+16,37,49,28288,
+7,27,57,28288,
+33,33,43,28308,
+3,7,63,28308,
+27,33,47,28308,
+9,15,61,28308,
+8,22,59,28308,
+14,32,53,28308,
+8,34,53,28308,
+4,13,62,28308,
+32,34,43,28315,
+8,11,62,28315,
+13,34,52,28315,
+22,29,52,28315,
+10,35,52,28315,
+8,43,46,28315,
+23,30,51,28315,
+5,33,54,28315,
+5,6,63,28315,
+21,33,50,28315,
+27,30,49,28315,
+18,41,45,28315,
+15,21,58,28315,
+3,39,50,28315,
+15,18,59,28315,
+22,39,45,28315,
+18,30,53,28315,
+21,26,54,28315,
+24,39,44,28315,
+12,17,60,28315,
+0,28,57,28315,
+30,37,42,28345,
+0,8,63,28345,
+15,28,55,28345,
+4,7,63,28345,
+1,28,57,28345,
+16,23,57,28345,
+7,41,48,28345,
+23,36,47,28345,
+12,13,61,28345,
+28,35,45,28345,
+1,8,63,28345,
+12,41,47,28345,
+36,37,37,28397,
+15,40,47,28397,
+13,27,56,28397,
+8,37,51,28397,
+21,28,53,28397,
+0,35,53,28397,
+19,37,48,28397,
+27,37,44,28397,
+31,35,43,28397,
+13,29,55,28397,
+5,23,59,28397,
+5,17,61,28397,
+7,31,55,28397,
+1,35,53,28397,
+6,36,52,28397,
+6,20,60,28397,
+36,36,38,28403,
+18,24,56,28403,
+0,30,56,28403,
+24,34,48,28403,
+4,39,50,28403,
+7,12,62,28403,
+8,42,47,28403,
+15,26,56,28403,
+6,40,49,28403,
+20,39,46,28403,
+2,8,63,28403,
+1,30,56,28403,
+25,36,46,28403,
+2,28,57,28403,
+17,38,48,28403,
+12,23,58,28403,
+24,31,50,28403,
+11,14,61,28403,
+13,37,50,28403,
+5,13,62,28403,
+2,35,53,28403,
+31,31,46,28403,
+14,19,59,28403,
+26,41,41,28403,
+26,31,49,28403,
+7,25,58,28403,
+22,23,55,28403,
+35,37,38,28436,
+30,32,46,28436,
+10,32,54,28436,
+26,40,42,28436,
+0,26,58,28436,
+18,40,46,28436,
+10,24,58,28436,
+0,14,62,28436,
+2,30,56,28436,
+8,16,61,28436,
+0,21,60,28436,
+6,6,63,28436,
+13,44,44,28436,
+1,14,62,28436,
+12,36,51,28436,
+16,43,44,28436,
+8,29,56,28436,
+15,30,54,28436,
+1,26,58,28436,
+14,38,49,28436,
+21,36,48,28436,
+26,34,47,28436,
+29,40,40,28436,
+6,33,54,28436,
+11,28,56,28436,
+22,34,49,28436,
+35,36,39,28476,
+9,19,60,28476,
+3,28,57,28476,
+1,21,60,28476,
+8,27,57,28476,
+12,33,53,28476,
+9,44,45,28476,
+3,8,63,28476,
+21,24,55,28476,
+13,25,57,28476,
+11,21,59,28476,
+17,27,55,28476,
+29,39,41,28476,
+11,39,49,28476,
+3,35,53,28476,
+5,7,63,28476,
+13,43,45,28476,
+10,10,62,28476,
+22,38,46,28476,
+34,38,38,28482,
+14,22,58,28482,
+2,26,58,28482,
+2,14,62,28482,
+10,38,50,28482,
+24,38,45,28482,
+16,42,45,28482,
+21,30,52,28482,
+29,30,48,28482,
+30,36,43,28482,
+0,38,51,28482,
+20,27,54,28482,
+3,30,56,28482,
+11,18,60,28482,
+0,18,61,28482,
+2,21,60,28482,
+10,15,61,28482,
+17,34,51,28482,
+1,38,51,28482,
+6,17,61,28482,
+9,22,59,28482,
+9,43,46,28482,
+11,26,57,28482,
+13,31,54,28482,
+5,39,50,28482,
+34,37,39,28500,
+1,18,61,28500,
+17,29,54,28500,
+29,33,46,28500,
+11,30,55,28500,
+26,39,43,28500,
+9,11,62,28500,
+6,23,59,28500,
+9,34,53,28500,
+22,31,51,28500,
+12,40,48,28500,
+18,19,58,28500,
+3,14,62,28500,
+4,8,63,28500,
+28,31,48,28500,
+16,33,52,28500,
+18,35,50,28500,
+2,18,61,28500,
+6,13,62,28500,
+0,32,55,28500,
+20,20,57,28500,
+32,33,44,28500,
+13,42,46,28500,
+3,26,58,28500,
+29,38,42,28500,
+2,38,51,28500,
+8,41,48,28500,
+4,28,57,28500,
+7,36,52,28500,
+7,20,60,28500,
+15,39,48,28500,
+7,40,49,28500,
+15,24,57,28500,
+35,35,40,28555,
+8,31,55,28555,
+1,32,55,28555,
+13,20,59,28555,
+20,29,53,28555,
+0,45,45,28555,
+4,35,53,28555,
+20,25,55,28555,
+11,35,52,28555,
+15,15,60,28555,
+25,32,49,28555,
+27,36,45,28555,
+0,9,63,28555,
+17,25,56,28555,
+3,21,60,28555,
+9,37,51,28555,
+1,9,63,28555,
+19,21,57,28555,
+15,35,51,28555,
+1,45,45,28555,
+19,33,51,28555,
+8,12,62,28555,
+18,32,52,28555,
+0,44,46,28555,
+16,36,50,28555,
+14,16,60,28555,
+4,30,56,28555,
+34,36,40,28561,
+8,25,58,28561,
+1,44,46,28561,
+31,34,44,28561,
+23,32,50,28561,
+17,20,58,28561,
+2,32,55,28561,
+20,38,47,28561,
+16,41,46,28561,
+9,42,47,28561,
+18,39,47,28561,
+2,9,63,28561,
+33,38,39,28598,
+3,18,61,28598,
+2,45,45,28598,
+6,7,63,28598,
+3,38,51,28598,
+21,42,43,28598,
+7,33,54,28598,
+2,44,46,28598,
+26,38,44,28598,
+20,34,50,28598,
+14,34,52,28598,
+4,26,58,28598,
+4,14,62,28598,
+28,34,46,28598,
+26,26,52,28598,
+23,42,42,28598,
+0,24,59,28598,
+27,32,48,28598,
+6,39,50,28598,
+18,22,57,28598,
+4,21,60,28598,
+21,41,44,28598,
+1,24,59,28598,
+19,36,49,28598,
+5,8,63,28598,
+0,43,47,28598,
+5,28,57,28598,
+25,27,52,28598,
+3,32,55,28598,
+15,32,53,28598,
+13,17,60,28598,
+9,29,56,28598,
+23,35,48,28598,
+9,16,61,28598,
+33,37,40,28627,
+17,31,53,28627,
+29,37,43,28627,
+9,27,57,28627,
+25,25,53,28627,
+13,41,47,28627,
+23,41,43,28627,
+3,9,63,28627,
+25,35,47,28627,
+1,43,47,28627,
+3,45,45,28627,
+19,43,43,28627,
+7,17,61,28627,
+7,23,59,28627,
+5,35,53,28627,
+13,13,61,28627,
+17,37,49,28627,
+27,27,51,28627,
+17,17,59,28627,
+21,22,56,28627,
+19,28,54,28627,
+16,21,58,28627,
+16,18,59,28627,
+12,14,61,28627,
+26,28,51,28627,
+2,24,59,28627,
+10,19,60,28627,
+3,44,46,28627,
+24,26,53,28627,
+4,38,51,28627,
+11,24,58,28627,
+5,30,56,28627,
+14,27,56,28627,
+19,42,44,28627,
+30,35,44,28627,
+4,18,61,28627,
+11,32,54,28627,
+24,37,46,28627,
+10,44,45,28627,
+2,43,47,28627,
+13,23,58,28627,
+34,35,41,28660,
+7,13,62,28660,
+14,29,55,28660,
+19,26,55,28660,
+22,37,47,28660,
+24,28,52,28660,
+8,36,52,28660,
+8,20,60,28660,
+12,28,56,28660,
+10,11,62,28660,
+11,38,50,28660,
+20,31,52,28660,
+5,14,62,28660,
+14,37,50,28660,
+10,43,46,28660,
+5,26,58,28660,
+16,40,47,28660,
+28,40,41,28660,
+10,22,59,28660,
+16,28,55,28660,
+20,23,56,28660,
+8,40,49,28660,
+10,34,53,28660,
+23,40,44,28660,
+4,32,55,28660,
+12,21,59,28660,
+32,39,39,28706,
+4,9,63,28706,
+3,24,59,28706,
+33,36,41,28706,
+4,45,45,28706,
+24,33,49,28706,
+5,21,60,28706,
+21,32,51,28706,
+9,41,48,28706,
+12,39,49,28706,
+21,40,45,28706,
+13,36,51,28706,
+11,15,61,28706,
+23,27,53,28706,
+17,23,57,28706,
+13,33,53,28706,
+19,41,45,28706,
+7,7,63,28706,
+15,19,59,28706,
+25,29,51,28706,
+3,43,47,28706,
+21,35,49,28706,
+9,31,55,28706,
+28,28,50,28706,
+4,44,46,28706,
+16,26,56,28706,
+14,44,44,28706,
+32,38,40,28718,
+24,24,54,28718,
+12,18,60,28718,
+0,42,48,28718,
+8,33,54,28718,
+9,12,62,28718,
+1,42,48,28718,
+0,15,62,28718,
+0,10,63,28718,
+12,26,57,28718,
+6,8,63,28718,
+28,39,42,28718,
+12,30,55,28718,
+26,33,48,28718,
+6,28,57,28718,
+25,41,42,28718,
+14,25,57,28718,
+10,37,51,28718,
+9,25,58,28718,
+14,43,45,28718,
+1,10,63,28718,
+7,39,50,28718,
+1,15,62,28718,
+30,31,47,28718,
+27,29,50,28718,
+5,18,61,28718,
+19,30,53,28718,
+6,35,53,28718,
+27,35,46,28718,
+23,25,54,28718,
+15,38,49,28718,
+26,37,45,28718,
+5,38,51,28718,
+2,42,48,28718,
+0,34,54,28718,
+16,30,54,28718,
+18,38,48,28718,
+6,30,56,28718,
+15,22,58,28718,
+13,40,48,28718,
+20,37,48,28718,
+12,35,52,28718,
+10,42,47,28718,
+29,36,44,28738,
+1,34,54,28738,
+19,24,56,28738,
+0,37,52,28738,
+2,15,62,28738,
+2,10,63,28738,
+22,33,50,28738,
+4,24,59,28738,
+14,31,54,28738,
+32,32,45,28738,
+1,37,52,28738,
+29,32,47,28738,
+8,23,59,28738,
+17,43,44,28738,
+32,37,41,28787,
+5,32,55,28787,
+8,17,61,28787,
+23,29,52,28787,
+25,40,43,28787,
+4,43,47,28787,
+5,9,63,28787,
+23,39,45,28787,
+31,33,45,28787,
+5,45,45,28787,
+6,26,58,28787,
+14,42,46,28787,
+2,34,54,28787,
+26,30,50,28787,
+34,34,42,28789,
+6,14,62,28789,
+22,26,54,28789,
+10,16,61,28789,
+14,20,59,28789,
+6,21,60,28789,
+10,29,56,28789,
+3,42,48,28789,
+8,13,62,28789,
+22,28,53,28789,
+2,37,52,28789,
+24,30,51,28789,
+19,40,46,28789,
+5,44,46,28789,
+28,38,43,28789,
+18,27,55,28789,
+10,27,57,28789,
+3,10,63,28789,
+21,39,46,28789,
+3,15,62,28789,
+17,42,45,28789,
+33,35,42,28819,
+3,34,54,28819,
+9,20,60,28819,
+16,24,57,28819,
+9,36,52,28819,
+16,39,48,28819,
+18,34,51,28819,
+18,29,54,28819,
+6,38,51,28819,
+15,16,60,28819,
+24,36,47,28819,
+30,34,45,28819,
+6,18,61,28819,
+7,28,57,28819,
+0,41,49,28819,
+31,39,40,28852,
+5,24,59,28852,
+7,8,63,28852,
+16,35,51,28852,
+11,19,60,28852,
+25,39,44,28852,
+0,19,61,28852,
+11,44,45,28852,
+28,33,47,28852,
+17,33,52,28852,
+3,37,52,28852,
+9,40,49,28852,
+7,35,53,28852,
+1,41,49,28852,
+1,19,61,28852,
+5,43,47,28852,
+23,23,55,28852,
+29,29,49,28852,
+12,24,58,28852,
+4,42,48,28852,
+12,32,54,28852,
+0,22,60,28852,
+22,36,48,28852,
+32,36,42,28861,
+14,17,60,28861,
+25,34,48,28861,
+4,15,62,28861,
+1,22,60,28861,
+15,34,52,28861,
+22,24,55,28861,
+18,25,56,28861,
+8,39,50,28861,
+10,41,48,28861,
+6,32,55,28861,
+4,10,63,28861,
+28,30,49,28861,
+17,36,50,28861,
+7,30,56,28861,
+17,41,46,28861,
+13,14,61,28861,
+10,31,55,28861,
+6,9,63,28861,
+31,38,41,28883,
+19,35,50,28883,
+11,11,62,28883,
+9,33,54,28883,
+25,31,50,28883,
+23,34,49,28883,
+2,19,61,28883,
+2,41,49,28883,
+11,34,53,28883,
+14,41,47,28883,
+21,27,54,28883,
+19,19,58,28883,
+6,45,45,28883,
+11,22,59,28883,
+11,43,46,28883,
+12,38,50,28883,
+18,20,58,28883,
+4,34,54,28883,
+6,44,46,28883,
+10,12,62,28883,
+22,30,52,28883,
+2,22,60,28883,
+26,36,46,28883,
+7,26,58,28883,
+4,37,52,28883,
+23,38,46,28883,
+28,37,44,28883,
+14,23,58,28883,
+7,14,62,28883,
+13,28,56,28883,
+19,32,52,28883,
+16,32,53,28883,
+10,25,58,28883,
+12,15,61,28883,
+20,21,57,28883,
+0,29,57,28883,
+0,11,63,28883,
+20,33,51,28883,
+7,21,60,28883,
+15,27,56,28883,
+23,31,51,28883,
+9,17,61,28883,
+27,41,41,28895,
+1,11,63,28895,
+27,31,49,28895,
+21,25,55,28895,
+9,23,59,28895,
+3,19,61,28895,
+11,37,51,28895,
+15,29,55,28895,
+13,39,49,28895,
+19,39,47,28895,
+1,29,57,28895,
+3,41,49,28895,
+21,29,53,28895,
+29,35,45,28895,
+13,21,59,28895,
+14,36,51,28895,
+13,18,60,28895,
+5,42,48,28895,
+6,24,59,28895,
+27,40,42,28922,
+3,22,60,28922,
+0,27,58,28922,
+13,26,57,28922,
+11,42,47,28922,
+5,10,63,28922,
+33,34,43,28955,
+18,31,53,28955,
+1,27,58,28955,
+17,18,59,28955,
+19,22,57,28955,
+31,37,42,28955,
+18,37,49,28955,
+2,29,57,28955,
+5,15,62,28955,
+25,38,45,28955,
+21,38,47,28955,
+6,43,47,28955,
+14,33,53,28955,
+15,37,50,28955,
+17,21,58,28955,
+27,34,47,28955,
+2,11,63,28955,
+7,38,51,28955,
+9,13,62,28955,
+13,30,55,28955,
+7,18,61,28955,
+0,0,64,28955,
+2,27,58,28955,
+5,34,54,28955,
+22,42,43,28955,
+8,28,57,28955,
+20,36,49,28955,
+0,31,56,28955,
+8,8,63,28955,
+15,44,44,28955,
+21,34,50,28955,
+0,1,64,28955,
+5,37,52,28955,
+8,35,53,28955,
+7,32,55,28955,
+11,29,56,28955,
+11,16,61,28955,
+1,31,56,28955,
+16,19,59,28955,
+4,41,49,28955,
+13,35,52,28955,
+32,35,43,29006,
+17,40,47,29006,
+1,1,64,29006,
+20,43,43,29006,
+4,19,61,29006,
+17,28,55,29006,
+7,9,63,29006,
+11,27,57,29006,
+15,43,45,29006,
+3,11,63,29006,
+15,25,57,29006,
+27,39,43,29006,
+7,45,45,29006,
+3,29,57,29006,
+14,40,48,29006,
+0,16,62,29006,
+10,20,60,29006,
+8,30,56,29006,
+24,32,50,29006,
+0,40,50,29006,
+0,2,64,29006,
+4,22,60,29006,
+20,42,44,29006,
+30,40,40,29010,
+10,36,52,29010,
+20,28,54,29010,
+10,40,49,29010,
+2,31,56,29010,
+16,38,49,29010,
+22,41,44,29010,
+1,2,64,29010,
+20,26,55,29010,
+31,32,46,29010,
+17,26,56,29010,
+26,32,49,29010,
+1,40,50,29010,
+1,16,62,29010,
+7,44,46,29010,
+15,31,54,29010,
+18,23,57,29010,
+9,39,50,29010,
+30,39,41,29052,
+3,27,58,29052,
+2,40,50,29052,
+24,42,42,29052,
+6,42,48,29052,
+16,22,58,29052,
+2,16,62,29052,
+22,22,56,29052,
+30,30,48,29052,
+8,26,58,29052,
+2,2,64,29052,
+8,14,62,29052,
+6,10,63,29052,
+28,36,45,29052,
+24,35,48,29052,
+17,30,54,29052,
+15,42,46,29052,
+12,19,60,29052,
+12,44,45,29052,
+10,33,54,29052,
+6,15,62,29052,
+8,21,60,29052,
+30,33,46,29052,
+0,36,53,29052,
+0,3,64,29052,
+1,36,53,29052,
+29,31,48,29052,
+4,29,57,29052,
+24,41,43,29052,
+3,31,56,29052,
+20,41,45,29052,
+11,41,48,29052,
+15,20,59,29052,
+4,11,63,29052,
+1,3,64,29052,
+7,24,59,29052,
+21,23,56,29052,
+21,31,52,29052,
+31,36,43,29081,
+0,25,59,29081,
+5,41,49,29081,
+7,43,47,29081,
+37,37,37,29124,
+11,31,55,29124,
+5,19,61,29124,
+1,25,59,29124,
+23,37,47,29124,
+30,38,42,29124,
+6,34,54,29124,
+12,22,59,29124,
+13,32,54,29124,
+5,22,60,29124,
+8,18,61,29124,
+3,16,62,29124,
+27,38,44,29124,
+20,30,53,29124,
+36,37,38,29142,
+26,27,52,29142,
+22,32,51,29142,
+3,40,50,29142,
+19,38,48,29142,
+11,12,62,29142,
+2,3,64,29142,
+12,34,53,29142,
+12,43,46,29142,
+4,27,58,29142,
+6,37,52,29142,
+2,36,53,29142,
+22,40,45,29142,
+8,38,51,29142,
+13,24,58,29142,
+18,43,44,29142,
+26,35,47,29142,
+10,23,59,29142,
+2,25,59,29142,
+22,35,49,29142,
+11,25,58,29142,
+25,26,53,29142,
+10,17,61,29142,
+25,37,46,29142,
+16,16,60,29142,
+20,24,56,29142,
+0,4,64,29142,
+28,32,48,29142,
+24,40,44,29142,
+13,38,50,29142,
+0,12,63,29142,
+18,42,45,29142,
+10,13,62,29142,
+25,28,52,29142,
+14,14,61,29142,
+4,31,56,29142,
+1,4,64,29142,
+29,34,46,29142,
+36,36,39,29173,
+35,38,38,29173,
+8,32,55,29173,
+21,37,48,29173,
+15,17,60,29173,
+17,24,57,29173,
+0,33,55,29173,
+27,28,51,29173,
+17,39,48,29173,
+24,27,53,29173,
+33,33,44,29173,
+1,12,63,29173,
+3,3,64,29173,
+9,28,57,29173,
+3,36,53,29173,
+12,37,51,29173,
+8,45,45,29173,
+8,9,63,29173,
+1,33,55,29173,
+35,37,39,29195,
+15,41,47,29195,
+3,25,59,29195,
+19,27,55,29195,
+5,11,63,29195,
+5,29,57,29195,
+25,33,49,29195,
+9,35,53,29195,
+13,15,61,29195,
+17,35,51,29195,
+8,44,46,29195,
+4,40,50,29195,
+20,40,46,29195,
+32,34,44,29195,
+2,4,64,29195,
+16,34,52,29195,
+4,16,62,29195,
+14,28,56,29195,
+12,42,47,29195,
+2,12,63,29195,
+7,42,48,29195,
+9,30,56,29195,
+18,33,52,29195,
+24,25,54,29195,
+26,29,51,29195,
+6,41,49,29195,
+30,37,43,29195,
+23,33,50,29195,
+2,33,55,29195,
+7,10,63,29195,
+19,34,51,29195,
+14,21,59,29195,
+15,23,58,29195,
+5,27,58,29195,
+7,15,62,29195,
+6,19,61,29195,
+14,39,49,29195,
+19,29,54,29195,
+14,18,60,29195,
+18,36,50,29195,
+6,22,60,29195,
+16,27,56,29195,
+11,36,52,29195,
+4,36,53,29195,
+14,30,55,29195,
+35,36,40,29246,
+14,26,57,29246,
+26,41,42,29246,
+12,16,61,29246,
+10,39,50,29246,
+0,5,64,29246,
+18,41,46,29246,
+3,4,64,29246,
+9,26,58,29246,
+9,14,62,29246,
+11,20,60,29246,
+22,39,46,29246,
+12,29,56,29246,
+8,24,59,29246,
+23,26,54,29246,
+0,20,61,29246,
+34,38,39,29246,
+24,29,52,29246,
+7,34,54,29246,
+27,33,48,29246,
+0,39,51,29246,
+31,35,44,29246,
+23,28,53,29246,
+1,5,64,29246,
+12,27,57,29246,
+5,31,56,29246,
+11,40,49,29246,
+24,39,45,29246,
+7,37,52,29246,
+9,21,60,29246,
+1,20,61,29246,
+15,36,51,29246,
+17,32,53,29246,
+3,12,63,29246,
+29,40,41,29246,
+8,43,47,29246,
+4,25,59,29246,
+19,25,56,29246,
+16,29,55,29246,
+15,33,53,29246,
+3,33,55,29246,
+27,37,45,29246,
+1,39,51,29246,
+28,35,46,29246,
+5,40,50,29246,
+2,5,64,29246,
+14,35,52,29246,
+34,37,40,29292,
+28,29,50,29292,
+20,35,50,29292,
+19,20,58,29292,
+26,40,43,29292,
+2,20,61,29292,
+5,16,62,29292,
+16,37,50,29292,
+25,30,51,29292,
+9,18,61,29292,
+6,29,57,29292,
+6,11,63,29292,
+29,39,42,29292,
+9,38,51,29292,
+11,33,54,29292,
+2,39,51,29292,
+16,44,44,29292,
+20,32,52,29292,
+4,4,64,29292,
+12,41,48,29292,
+4,12,63,29292,
+0,23,60,29292,
+23,36,48,29292,
+15,40,48,29292,
+27,30,50,29292,
+18,18,59,29292,
+18,21,58,29292,
+22,27,54,29292,
+6,27,58,29292,
+12,31,55,29292,
+5,36,53,29292,
+3,5,64,29292,
+23,24,55,29292,
+13,19,60,29292,
+20,39,47,29292,
+25,36,47,29292,
+1,23,60,29292,
+3,20,61,29292,
+13,44,45,29292,
+16,25,57,29292,
+16,43,45,29292,
+9,32,55,29292,
+4,33,55,29292,
+5,25,59,29292,
+19,31,53,29292,
+19,37,49,29292,
+33,39,39,29343,
+35,35,41,29343,
+21,33,51,29343,
+11,23,59,29343,
+7,19,61,29343,
+9,45,45,29343,
+7,41,49,29343,
+3,39,51,29343,
+17,19,59,29343,
+21,21,57,29343,
+11,17,61,29343,
+9,9,63,29343,
+31,31,47,29343,
+30,36,44,29343,
+12,12,62,29343,
+0,6,64,29343,
+8,42,48,29343,
+30,32,47,29343,
+10,28,57,29343,
+16,31,54,29343,
+12,25,58,29343,
+33,38,40,29368,
+24,34,49,29368,
+8,15,62,29368,
+0,17,62,29368,
+9,44,46,29368,
+6,31,56,29368,
+2,23,60,29368,
+23,30,52,29368,
+1,6,64,29368,
+18,28,55,29368,
+26,39,44,29368,
+34,36,41,29368,
+7,22,60,29368,
+20,22,57,29368,
+18,40,47,29368,
+8,10,63,29368,
+22,29,53,29368,
+11,13,62,29368,
+17,38,49,29368,
+13,34,53,29368,
+1,17,62,29368,
+13,22,59,29368,
+29,38,43,29368,
+13,43,46,29368,
+10,35,53,29368,
+22,25,55,29368,
+18,26,56,29368,
+6,40,50,29368,
+6,16,62,29368,
+16,42,46,29368,
+14,32,54,29368,
+14,24,58,29368,
+8,34,54,29368,
+24,38,46,29368,
+26,34,48,29368,
+10,30,56,29368,
+2,6,64,29368,
+16,20,59,29368,
+26,31,50,29368,
+22,38,47,29368,
+4,20,61,29368,
+17,22,58,29368,
+2,17,62,29368,
+4,5,64,29368,
+8,37,52,29368,
+9,24,59,29368,
+21,36,49,29368,
+0,13,63,29368,
+24,31,51,29368,
+3,23,60,29368,
+4,39,51,29368,
+5,12,63,29368,
+32,33,45,29384,
+7,11,63,29384,
+5,33,55,29384,
+9,43,47,29384,
+7,29,57,29384,
+21,43,43,29384,
+13,37,51,29384,
+1,13,63,29384,
+33,37,41,29416,
+29,33,47,29416,
+19,23,57,29416,
+10,14,62,29416,
+18,30,54,29416,
+14,38,50,29416,
+10,26,58,29416,
+22,34,50,29416,
+27,36,46,29416,
+21,42,44,29416,
+3,6,64,29416,
+10,21,60,29416,
+6,36,53,29416,
+0,35,54,29416,
+21,28,54,29416,
+0,45,46,29416,
+2,13,63,29416,
+7,27,58,29416,
+1,45,46,29416,
+3,17,62,29416,
+29,30,49,29416,
+23,42,43,29416,
+21,26,55,29416,
+6,25,59,29416,
+1,35,54,29416,
+13,42,47,29416,
+31,34,45,29416,
+14,15,61,29416,
+11,39,50,29416,
+12,20,60,29416,
+12,36,52,29416,
+15,28,56,29416,
+16,17,60,29416,
+10,38,51,29416,
+0,44,47,29416,
+26,38,45,29416,
+0,7,64,29416,
+2,35,54,29416,
+12,40,49,29416,
+10,18,61,29416,
+32,39,40,29474,
+34,35,42,29474,
+4,23,60,29474,
+2,45,46,29474,
+19,43,44,29474,
+7,31,56,29474,
+8,19,61,29474,
+5,20,61,29474,
+1,7,64,29474,
+13,16,61,29474,
+23,41,44,29474,
+13,29,56,29474,
+16,41,47,29474,
+5,5,64,29474,
+28,41,41,29474,
+8,41,49,29474,
+28,31,49,29474,
+29,37,44,29474,
+1,44,47,29474,
+5,39,51,29474,
+13,27,57,29474,
+3,13,63,29474,
+15,39,49,29474,
+15,21,59,29474,
+21,41,45,29474,
+4,6,64,29474,
+8,22,60,29474,
+0,28,58,29474,
+0,38,52,29474,
+20,38,48,29474,
+28,40,42,29474,
+32,38,41,29502,
+4,17,62,29502,
+33,36,42,29502,
+1,38,52,29502,
+2,44,47,29502,
+0,30,57,29502,
+17,34,52,29502,
+9,42,48,29502,
+1,28,58,29502,
+7,40,50,29502,
+6,12,63,29502,
+15,18,60,29502,
+2,7,64,29502,
+7,16,62,29502,
+18,24,57,29502,
+22,31,52,29502,
+10,32,55,29502,
+22,23,56,29502,
+25,32,50,29502,
+18,39,48,29502,
+16,23,58,29502,
+28,34,47,29502,
+12,33,54,29502,
+1,30,57,29502,
+21,30,53,29502,
+15,30,55,29502,
+15,26,57,29502,
+3,35,54,29502,
+9,10,63,29502,
+30,35,45,29502,
+19,42,45,29502,
+9,15,62,29502,
+6,33,55,29502,
+10,45,45,29502,
+18,35,51,29502,
+3,45,46,29502,
+2,28,58,29502,
+2,38,52,29502,
+10,44,46,29502,
+0,43,48,29502,
+25,42,42,29502,
+16,36,51,29502,
+9,34,54,29502,
+21,24,56,29502,
+2,30,57,29502,
+8,29,57,29502,
+17,27,56,29502,
+5,23,60,29502,
+13,41,48,29502,
+12,17,61,29502,
+28,39,43,29516,
+12,23,59,29516,
+16,33,53,29516,
+25,35,48,29516,
+4,13,63,29516,
+27,32,49,29516,
+3,7,64,29516,
+23,40,45,29516,
+9,37,52,29516,
+3,44,47,29516,
+1,43,48,29516,
+19,33,52,29516,
+15,35,52,29516,
+8,11,63,29516,
+20,27,55,29516,
+23,32,51,29516,
+24,37,47,29516,
+11,28,57,29516,
+7,36,53,29516,
+13,31,55,29516,
+17,29,55,29516,
+11,35,53,29516,
+7,25,59,29516,
+25,41,43,29516,
+23,35,49,29516,
+20,29,54,29516,
+8,27,58,29516,
+3,28,58,29516,
+4,45,46,29516,
+6,20,61,29516,
+14,44,45,29516,
+4,35,54,29516,
+32,37,42,29573,
+3,38,52,29573,
+20,34,51,29573,
+10,24,59,29573,
+18,32,53,29573,
+2,43,48,29573,
+0,26,59,29573,
+14,19,60,29573,
+11,30,56,29573,
+21,40,46,29573,
+12,13,62,29573,
+19,36,50,29573,
+22,37,48,29573,
+5,6,64,29573,
+5,17,62,29573,
+3,30,57,29573,
+6,39,51,29573,
+13,25,58,29573,
+17,37,50,29573,
+19,41,46,29573,
+1,26,59,29573,
+10,43,47,29573,
+16,40,48,29573,
+0,8,64,29573,
+0,32,56,29573,
+34,34,43,29615,
+8,31,56,29615,
+17,44,44,29615,
+26,37,46,29615,
+14,43,46,29615,
+11,14,62,29615,
+4,7,64,29615,
+31,40,40,29615,
+14,22,59,29615,
+1,32,56,29615,
+2,26,59,29615,
+4,44,47,29615,
+26,26,53,29615,
+11,26,58,29615,
+1,8,64,29615,
+20,25,56,29615,
+14,34,53,29615,
+25,40,44,29615,
+11,21,60,29615,
+0,21,61,29615,
+3,43,48,29615,
+29,36,45,29615,
+27,27,52,29615,
+7,12,63,29615,
+31,39,41,29640,
+5,13,63,29640,
+25,27,53,29640,
+27,35,47,29640,
+7,33,55,29640,
+9,19,61,29640,
+9,41,49,29640,
+33,35,43,29640,
+17,25,57,29640,
+1,21,61,29640,
+17,43,45,29640,
+2,8,64,29640,
+2,32,56,29640,
+4,28,58,29640,
+8,40,50,29640,
+4,38,52,29640,
+28,38,44,29640,
+26,28,52,29640,
+20,20,58,29640,
+32,32,46,29640,
+8,16,62,29640,
+0,14,63,29640,
+15,24,58,29640,
+30,31,48,29640,
+4,30,57,29640,
+6,23,60,29640,
+9,22,60,29640,
+0,42,49,29640,
+24,33,50,29640,
+15,32,54,29640,
+12,39,50,29640,
+5,45,46,29640,
+14,37,51,29640,
+17,31,54,29640,
+23,39,46,29640,
+21,35,50,29640,
+18,19,59,29640,
+31,33,46,29640,
+26,33,49,29640,
+1,42,49,29640,
+3,26,59,29640,
+19,21,58,29640,
+11,38,51,29640,
+1,14,63,29640,
+25,25,54,29640,
+5,35,54,29640,
+2,21,61,29640,
+11,18,61,29640,
+6,6,64,29640,
+0,18,62,29640,
+10,42,48,29640,
+24,26,54,29640,
+6,17,62,29640,
+18,38,49,29640,
+29,32,48,29640,
+13,20,60,29640,
+1,18,62,29640,
+8,36,53,29640,
+2,14,63,29640,
+21,32,52,29640,
+3,32,56,29640,
+28,28,51,29640,
+32,36,43,29694,
+10,15,62,29694,
+2,42,49,29694,
+14,42,47,29694,
+17,42,46,29694,
+15,38,50,29694,
+13,36,52,29694,
+31,38,42,29694,
+4,43,48,29694,
+10,10,63,29694,
+3,8,64,29694,
+24,28,53,29694,
+19,28,55,29694,
+11,32,55,29694,
+5,44,47,29694,
+20,31,53,29694,
+17,20,59,29694,
+7,20,61,29694,
+5,7,64,29694,
+8,25,59,29694,
+20,37,49,29694,
+25,29,52,29694,
+13,40,49,29694,
+19,40,47,29694,
+25,39,45,29694,
+3,21,61,29694,
+9,29,57,29694,
+9,11,63,29694,
+15,15,61,29694,
+11,45,45,29694,
+27,29,51,29694,
+7,39,51,29694,
+21,39,47,29694,
+2,18,62,29694,
+18,22,58,29694,
+10,34,54,29694,
+30,34,46,29694,
+10,37,52,29694,
+19,26,56,29694,
+5,38,52,29694,
+5,28,58,29694,
+11,44,46,29694,
+4,26,59,29694,
+14,29,56,29694,
+14,16,61,29694,
+23,27,54,29694,
+9,27,58,29694,
+5,30,57,29694,
+13,33,54,29694,
+3,42,49,29694,
+14,27,57,29694,
+27,41,42,29716,
+21,22,57,29716,
+3,14,63,29716,
+22,33,51,29716,
+6,13,63,29716,
+0,24,60,29716,
+4,8,64,29716,
+4,32,56,29716,
+24,36,48,29716,
+16,28,56,29716,
+3,18,62,29716,
+19,30,54,29716,
+6,45,46,29716,
+0,9,64,29716,
+6,35,54,29716,
+26,30,51,29716,
+24,24,55,29716,
+1,24,60,29716,
+8,12,63,29716,
+28,33,48,29716,
+12,28,57,29716,
+8,33,55,29716,
+4,21,61,29716,
+20,23,57,29716,
+7,23,60,29716,
+5,43,48,29716,
+16,39,49,29716,
+9,31,56,29716,
+11,24,59,29716,
+16,21,59,29716,
+27,40,43,29749,
+28,37,45,29749,
+0,37,53,29749,
+1,9,64,29749,
+12,35,53,29749,
+17,17,60,29749,
+13,17,61,29749,
+23,29,53,29749,
+31,37,43,29793,
+11,43,47,29793,
+23,25,55,29793,
+17,41,47,29793,
+1,37,53,29793,
+13,23,59,29793,
+2,24,60,29793,
+24,30,52,29793,
+12,30,56,29793,
+16,18,60,29793,
+30,40,41,29813,
+6,7,64,29813,
+2,9,64,29813,
+33,34,44,29813,
+4,14,63,29813,
+4,42,49,29813,
+9,40,50,29813,
+22,36,49,29813,
+16,26,57,29813,
+9,16,62,29813,
+0,34,55,29813,
+6,44,47,29813,
+16,30,55,29813,
+26,36,47,29813,
+0,41,50,29813,
+14,41,48,29813,
+25,34,49,29813,
+22,43,43,29813,
+23,38,47,29813,
+10,19,61,29813,
+1,41,50,29813,
+14,31,55,29813,
+1,34,55,29813,
+29,35,46,29813,
+37,37,38,29851,
+13,13,62,29851,
+2,37,53,29851,
+5,26,59,29851,
+17,23,58,29851,
+29,29,50,29851,
+10,41,49,29851,
+7,17,62,29851,
+12,14,62,29851,
+6,28,58,29851,
+28,30,50,29851,
+18,34,52,29851,
+22,42,44,29851,
+12,26,58,29851,
+10,22,60,29851,
+4,18,62,29851,
+36,38,38,29872,
+22,28,54,29872,
+6,38,52,29872,
+25,38,46,29872,
+5,8,64,29872,
+12,21,60,29872,
+30,39,42,29872,
+6,30,57,29872,
+14,25,58,29872,
+22,26,55,29872,
+20,43,44,29872,
+16,35,52,29872,
+3,24,60,29872,
+23,34,50,29872,
+2,41,50,29872,
+32,35,44,29872,
+2,34,55,29872,
+5,32,56,29872,
+8,20,61,29872,
+8,39,51,29872,
+27,39,44,29872,
+3,9,64,29872,
+15,44,45,29872,
+19,24,57,29872,
+17,36,51,29872,
+15,19,60,29872,
+19,39,48,29872,
+36,37,39,29903,
+9,36,53,29903,
+7,13,63,29903,
+3,37,53,29903,
+19,35,51,29903,
+17,33,53,29903,
+9,25,59,29903,
+25,31,51,29903,
+5,21,61,29903,
+12,38,51,29903,
+11,42,48,29903,
+27,34,48,29903,
+24,42,43,29903,
+18,27,56,29903,
+20,42,45,29903,
+6,43,48,29903,
+21,38,48,29903,
+12,18,61,29903,
+10,11,63,29903,
+5,14,63,29903,
+15,22,59,29903,
+11,15,62,29903,
+5,42,49,29903,
+7,35,54,29903,
+10,29,57,29903,
+15,43,46,29903,
+35,38,39,29944,
+18,29,55,29944,
+7,45,46,29944,
+13,39,50,29944,
+27,31,50,29944,
+15,34,53,29944,
+3,41,50,29944,
+22,41,45,29944,
+3,34,55,29944,
+36,36,40,29957,
+4,24,60,29957,
+4,9,64,29957,
+5,18,62,29957,
+30,38,43,29957,
+17,40,48,29957,
+12,32,55,29957,
+22,30,53,29957,
+18,37,50,29957,
+20,33,52,29957,
+11,34,54,29957,
+24,41,44,29957,
+8,23,60,29957,
+31,36,44,29957,
+10,27,58,29957,
+6,26,59,29957,
+23,23,56,29957,
+4,37,53,29957,
+11,37,52,29957,
+9,12,63,29957,
+19,32,53,29957,
+12,45,45,29957,
+35,37,40,29983,
+31,32,47,29983,
+7,44,47,29983,
+7,7,64,29983,
+23,31,52,29983,
+0,15,63,29983,
+15,37,51,29983,
+1,15,63,29983,
+21,27,55,29983,
+9,33,55,29983,
+16,24,58,29983,
+28,36,46,29983,
+12,44,46,29983,
+0,10,64,29983,
+6,32,56,29983,
+14,36,52,29983,
+18,44,44,29983,
+20,36,50,29983,
+16,32,54,29983,
+22,24,56,29983,
+6,8,64,29983,
+14,20,60,29983,
+14,40,49,29983,
+4,41,50,29983,
+8,17,62,29983,
+1,10,64,29983,
+7,28,58,29983,
+10,31,56,29983,
+4,34,55,29983,
+20,41,46,29983,
+7,38,52,29983,
+27,38,45,29983,
+21,29,54,29983,
+7,30,57,29983,
+21,34,51,29983,
+18,43,45,29983,
+30,33,47,29983,
+2,15,63,29983,
+18,25,57,29983,
+15,42,47,29983,
+34,39,39,30011,
+6,21,61,30011,
+22,40,46,30011,
+10,40,50,30011,
+26,32,50,30011,
+2,10,64,30011,
+16,38,50,30011,
+10,16,62,30011,
+34,38,40,30025,
+14,33,54,30025,
+12,24,59,30025,
+24,40,45,30025,
+24,32,51,30025,
+6,14,63,30025,
+30,30,49,30025,
+18,31,54,30025,
+5,24,60,30025,
+6,42,49,30025,
+0,40,51,30025,
+12,43,47,30025,
+15,29,56,30025,
+9,20,61,30025,
+15,16,61,30025,
+23,37,48,30025,
+24,35,49,30025,
+7,43,48,30025,
+35,36,41,30060,
+21,25,56,30060,
+1,40,51,30060,
+5,9,64,30060,
+13,28,57,30060,
+8,13,63,30060,
+3,15,63,30060,
+25,37,47,30060,
+11,41,49,30060,
+11,19,61,30060,
+29,41,41,30060,
+15,27,57,30060,
+19,19,59,30060,
+9,39,51,30060,
+5,37,53,30060,
+33,33,45,30060,
+29,31,49,30060,
+13,35,53,30060,
+26,42,42,30060,
+18,42,46,30060,
+6,18,62,30060,
+32,34,45,30060,
+0,29,58,30060,
+20,21,58,30060,
+0,22,61,30060,
+0,19,62,30060,
+2,40,51,30060,
+29,40,42,30060,
+18,20,59,30060,
+26,35,48,30060,
+13,30,56,30060,
+11,22,60,30060,
+3,10,64,30060,
+10,36,53,30060,
+8,45,46,30060,
+8,35,54,30060,
+30,37,44,30060,
+7,26,59,30060,
+14,23,59,30060,
+29,34,47,30060,
+19,38,49,30060,
+1,22,61,30060,
+1,29,58,30060,
+14,17,61,30060,
+5,34,55,30060,
+1,19,62,30060,
+34,37,41,30093,
+5,41,50,30093,
+26,41,43,30093,
+10,25,59,30093,
+20,40,47,30093,
+7,32,56,30093,
+7,8,64,30093,
+13,26,58,30093,
+19,22,58,30093,
+2,19,62,30093,
+20,28,55,30093,
+2,29,58,30093,
+17,28,56,30093,
+2,22,61,30093,
+28,32,49,30093,
+22,35,50,30093,
+8,44,47,30093,
+13,14,62,30093,
+3,40,51,30093,
+0,31,57,30093,
+15,41,48,30093,
+13,21,60,30093,
+4,15,63,30093,
+9,23,60,30093,
+33,39,40,30129,
+0,27,59,30129,
+1,27,59,30129,
+21,37,49,30129,
+11,11,63,30129,
+29,39,43,30129,
+15,31,55,30129,
+7,21,61,30129,
+21,31,53,30129,
+17,39,49,30129,
+11,29,57,30129,
+17,21,59,30129,
+31,35,45,30129,
+1,31,57,30129,
+4,10,64,30129,
+8,28,58,30129,
+20,26,56,30129,
+22,32,52,30129,
+0,36,54,30129,
+26,40,44,30129,
+12,42,48,30129,
+8,38,52,30129,
+6,24,60,30129,
+1,36,54,30129,
+8,30,57,30129,
+17,18,60,30129,
+12,15,62,30129,
+10,12,63,30129,
+6,9,64,30129,
+24,39,46,30129,
+26,27,53,30129,
+3,29,58,30129,
+13,38,51,30129,
+25,33,50,30129,
+35,35,42,30167,
+7,14,63,30167,
+18,41,47,30167,
+3,22,61,30167,
+22,39,47,30167,
+33,38,41,30167,
+11,27,58,30167,
+2,27,59,30167,
+2,31,57,30167,
+17,30,55,30167,
+6,37,53,30167,
+3,19,62,30167,
+10,33,55,30167,
+7,42,49,30167,
+27,37,46,30167,
+9,17,62,30167,
+17,26,57,30167,
+15,25,58,30167,
+13,18,61,30167,
+34,36,42,30187,
+2,36,54,30187,
+20,30,54,30187,
+12,34,54,30187,
+27,28,52,30187,
+4,40,51,30187,
+0,11,64,30187,
+25,26,54,30187,
+18,23,58,30187,
+6,34,55,30187,
+16,19,60,30187,
+8,43,48,30187,
+7,18,62,30187,
+6,41,50,30187,
+14,39,50,30187,
+12,37,52,30187,
+22,22,57,30187,
+16,44,45,30187,
+13,32,55,30187,
+28,35,47,30187,
+25,28,53,30187,
+1,11,64,30187,
+17,35,52,30187,
+11,31,56,30187,
+3,27,59,30187,
+13,45,45,30187,
+27,33,49,30187,
+3,31,57,30187,
+9,13,63,30187,
+23,33,51,30187,
+21,23,57,30187,
+5,15,63,30187,
+10,20,61,30187,
+30,36,45,30197,
+16,34,53,30197,
+24,27,54,30197,
+11,16,62,30197,
+29,38,44,30197,
+19,34,52,30197,
+13,44,46,30197,
+26,29,52,30197,
+11,40,50,30197,
+16,43,46,30197,
+5,10,64,30197,
+18,36,51,30197,
+4,19,62,30197,
+16,22,59,30197,
+2,11,64,30197,
+8,26,59,30197,
+4,29,58,30197,
+3,36,54,30197,
+4,22,61,30197,
+9,45,46,30197,
+9,35,54,30197,
+33,37,42,30236,
+10,39,51,30236,
+26,39,45,30236,
+18,33,53,30236,
+32,40,40,30248,
+8,8,64,30248,
+8,32,56,30248,
+0,33,56,30248,
+20,39,48,30248,
+15,20,60,30248,
+0,39,52,30248,
+7,24,60,30248,
+0,25,60,30248,
+20,24,57,30248,
+15,36,52,30248,
+0,16,63,30248,
+0,0,65,30248,
+25,36,48,30248,
+12,19,61,30248,
+19,27,56,30248,
+23,36,49,30248,
+24,25,55,30248,
+16,37,51,30248,
+7,9,64,30248,
+8,21,61,30248,
+28,29,51,30248,
+1,39,52,30248,
+12,41,49,30248,
+4,31,57,30248,
+32,39,41,30274,
+9,44,47,30274,
+15,40,49,30274,
+3,11,64,30274,
+5,40,51,30274,
+21,43,44,30274,
+1,33,56,30274,
+20,35,51,30274,
+4,27,59,30274,
+24,29,53,30274,
+1,16,63,30274,
+1,25,60,30274,
+13,24,59,30274,
+0,1,65,30274,
+31,31,48,30274,
+11,36,53,30274,
+23,43,43,30274,
+1,1,65,30274,
+13,43,47,30274,
+11,25,59,30274,
+7,37,53,30274,
+19,29,55,30274,
+18,40,48,30274,
+12,22,60,30274,
+30,32,48,30274,
+4,36,54,30274,
+28,41,42,30274,
+9,38,52,30274,
+16,42,47,30274,
+2,25,60,30274,
+17,32,54,30274,
+24,38,47,30274,
+23,42,44,30274,
+10,23,60,30274,
+0,2,65,30274,
+9,28,58,30274,
+8,14,63,30274,
+8,42,49,30274,
+25,30,52,30274,
+2,16,63,30274,
+32,33,46,30274,
+2,33,56,30274,
+2,39,52,30274,
+14,28,57,30274,
+17,24,58,30274,
+23,28,54,30274,
+14,35,53,30274,
+1,2,65,30274,
+5,29,58,30274,
+27,30,51,30274,
+21,42,45,30274,
+6,15,63,30274,
+7,41,50,30274,
+23,26,55,30274,
+15,33,54,30274,
+5,19,62,30274,
+34,35,43,30313,
+7,34,55,30313,
+5,22,61,30313,
+9,30,57,30313,
+19,37,50,30313,
+8,18,62,30313,
+14,30,56,30313,
+24,34,50,30313,
+32,38,42,30330,
+6,10,64,30330,
+0,46,46,30330,
+22,38,48,30330,
+10,17,62,30330,
+28,40,43,30330,
+2,2,65,30330,
+16,29,56,30330,
+31,34,46,30330,
+1,46,46,30330,
+26,34,49,30330,
+19,44,44,30330,
+4,11,64,30330,
+16,16,61,30330,
+17,38,50,30330,
+20,32,53,30330,
+3,39,52,30330,
+33,36,43,30363,
+0,45,47,30363,
+12,29,57,30363,
+21,33,52,30363,
+3,25,60,30363,
+27,36,47,30363,
+29,33,48,30363,
+16,27,57,30363,
+3,16,63,30363,
+0,3,65,30363,
+9,43,48,30363,
+3,33,56,30363,
+11,12,63,30363,
+5,27,59,30363,
+19,43,45,30363,
+5,31,57,30363,
+1,45,47,30363,
+15,17,61,30363,
+19,25,57,30363,
+11,33,55,30363,
+29,37,45,30363,
+1,3,65,30363,
+23,41,45,30363,
+15,23,59,30363,
+2,46,46,30363,
+14,26,58,30363,
+14,14,62,30363,
+26,38,46,30363,
+13,42,48,30363,
+12,27,58,30363,
+6,40,51,30363,
+21,36,50,30363,
+5,36,54,30363,
+14,21,60,30363,
+2,3,65,30363,
+2,45,47,30363,
+21,41,46,30363,
+19,31,54,30363,
+10,13,63,30363,
+9,26,59,30363,
+25,42,43,30363,
+13,15,62,30363,
+22,27,55,30363,
+23,30,53,30363,
+26,31,51,30363,
+0,44,48,30363,
+0,12,64,30363,
+8,24,60,30363,
+14,38,51,30363,
+6,29,58,30363,
+6,22,61,30363,
+19,42,46,30363,
+0,4,65,30363,
+28,39,44,30385,
+10,45,46,30385,
+1,12,64,30385,
+4,33,56,30385,
+29,30,50,30385,
+30,35,46,30385,
+12,31,56,30385,
+23,24,56,30385,
+4,25,60,30385,
+9,32,56,30385,
+22,29,54,30385,
+6,19,62,30385,
+4,39,52,30385,
+16,41,48,30385,
+13,34,54,30385,
+8,9,64,30385,
+3,46,46,30385,
+24,31,52,30385,
+1,44,48,30385,
+10,35,54,30385,
+22,34,51,30385,
+4,16,63,30385,
+14,18,61,30385,
+1,4,65,30385,
+5,11,64,30385,
+16,31,55,30385,
+11,20,61,30385,
+25,41,44,30385,
+13,37,52,30385,
+19,20,59,30385,
+31,40,41,30417,
+8,37,53,30417,
+32,37,43,30417,
+3,45,47,30417,
+3,3,65,30417,
+11,39,51,30417,
+9,21,61,30417,
+7,15,63,30417,
+2,44,48,30417,
+18,28,56,30417,
+0,20,62,30417,
+28,34,48,30417,
+2,12,64,30417,
+12,16,62,30417,
+12,40,50,30417,
+8,41,50,30417,
+16,25,58,30417,
+14,32,55,30417,
+2,4,65,30417,
+22,25,56,30417,
+7,10,64,30417,
+28,31,50,30417,
+23,40,46,30417,
+10,44,47,30417,
+8,34,55,30417,
+20,38,49,30417,
+1,20,62,30417,
+14,45,45,30417,
+21,21,58,30417,
+9,14,63,30417,
+15,39,50,30417,
+18,21,59,30417,
+18,39,49,30417,
+31,39,42,30450,
+9,42,49,30450,
+6,27,59,30450,
+6,31,57,30450,
+34,34,44,30468,
+2,20,62,30468,
+20,22,58,30468,
+10,38,52,30468,
+4,46,46,30468,
+18,18,60,30468,
+6,36,54,30468,
+14,44,46,30468,
+10,28,58,30468,
+3,12,64,30468,
+18,30,55,30468,
+3,44,48,30468,
+24,37,48,30468,
+12,36,53,30468,
+10,30,57,30468,
+18,26,57,30468,
+9,18,62,30468,
+21,40,47,30468,
+21,28,55,30468,
+0,43,49,30468,
+17,19,60,30468,
+0,35,55,30468,
+12,25,59,30468,
+33,35,44,30508,
+7,40,51,30508,
+5,39,52,30508,
+4,45,47,30508,
+25,40,45,30508,
+11,23,60,30508,
+5,25,60,30508,
+25,32,51,30508,
+5,33,56,30508,
+17,44,45,30508,
+0,23,61,30508,
+3,4,65,30508,
+0,5,65,30508,
+5,16,63,30508,
+1,5,65,30508,
+1,35,55,30508,
+1,23,61,30508,
+13,41,49,30508,
+13,19,61,30508,
+1,43,49,30508,
+25,35,49,30508,
+19,41,47,30508,
+28,38,45,30508,
+27,32,50,30508,
+10,43,48,30508,
+6,11,64,30508,
+14,24,59,30508,
+13,22,60,30508,
+29,36,46,30508,
+21,26,56,30508,
+3,20,62,30508,
+18,35,52,30508,
+0,38,53,30508,
+2,43,49,30508,
+23,35,50,30508,
+1,38,53,30508,
+14,43,47,30508,
+2,35,55,30508,
+19,23,58,30508,
+26,37,47,30508,
+7,29,58,30508,
+22,37,49,30508,
+7,19,62,30508,
+17,34,53,30508,
+2,23,61,30508,
+11,17,62,30508,
+17,22,59,30508,
+17,43,46,30508,
+31,38,43,30533,
+2,5,65,30533,
+22,31,53,30533,
+7,22,61,30533,
+16,20,60,30533,
+4,12,64,30533,
+32,36,44,30554,
+4,44,48,30554,
+16,36,52,30554,
+21,30,54,30554,
+9,24,60,30554,
+37,38,38,30600,
+27,42,42,30600,
+23,32,52,30600,
+12,12,63,30600,
+5,46,46,30600,
+16,40,49,30600,
+10,26,59,30600,
+2,38,53,30600,
+4,4,65,30600,
+32,32,47,30600,
+12,33,55,30600,
+15,28,57,30600,
+27,35,48,30600,
+9,9,64,30600,
+8,15,63,30600,
+19,36,51,30600,
+0,17,63,30600,
+27,41,43,30600,
+7,31,57,30600,
+31,33,47,30600,
+17,37,51,30600,
+5,45,47,30600,
+3,43,49,30600,
+7,27,59,30600,
+19,33,53,30600,
+37,37,39,30616,
+3,5,65,30616,
+11,13,63,30616,
+23,39,47,30616,
+3,35,55,30616,
+15,35,53,30616,
+9,37,53,30616,
+3,23,61,30616,
+13,29,57,30616,
+1,17,63,30616,
+8,10,64,30616,
+10,32,56,30616,
+4,20,62,30616,
+20,34,52,30616,
+0,6,65,30616,
+6,25,60,30616,
+36,38,39,30648,
+16,33,54,30648,
+6,39,52,30648,
+15,30,56,30648,
+6,33,56,30648,
+6,16,63,30648,
+7,36,54,30648,
+17,42,47,30648,
+30,31,49,30648,
+30,41,41,30648,
+3,38,53,30648,
+10,21,61,30648,
+13,27,58,30648,
+22,23,57,30648,
+9,34,55,30648,
+1,6,65,30648,
+11,45,46,30648,
+9,41,50,30648,
+2,17,63,30648,
+25,39,46,30648,
+11,35,54,30648,
+18,24,58,30648,
+30,40,42,30648,
+18,32,54,30648,
+14,42,48,30648,
+0,42,50,30648,
+0,30,58,30648,
+30,34,47,30648,
+27,40,44,30648,
+2,6,65,30648,
+10,14,63,30648,
+1,42,50,30648,
+19,40,48,30648,
+8,40,51,30648,
+0,28,59,30648,
+0,13,64,30648,
+14,15,62,30648,
+5,12,64,30648,
+15,26,58,30648,
+36,37,40,30676,
+26,33,50,30676,
+5,44,48,30676,
+10,42,49,30676,
+12,20,61,30676,
+1,30,58,30676,
+20,27,56,30676,
+29,32,49,30676,
+4,23,61,30676,
+4,35,55,30676,
+17,29,56,30676,
+12,39,51,30676,
+11,44,47,30676,
+16,17,61,30676,
+24,33,51,30676,
+1,13,64,30676,
+21,39,48,30676,
+21,24,57,30676,
+7,11,64,30676,
+15,21,60,30676,
+4,5,65,30676,
+16,23,59,30676,
+20,29,55,30676,
+4,43,49,30676,
+13,31,56,30676,
+1,28,59,30676,
+31,37,44,30676,
+27,27,53,30676,
+21,35,51,30676,
+35,39,39,30708,
+17,27,57,30708,
+3,17,63,30708,
+26,26,54,30708,
+18,38,50,30708,
+2,42,50,30708,
+2,30,58,30708,
+6,46,46,30708,
+10,18,62,30708,
+14,34,54,30708,
+4,38,53,30708,
+22,43,44,30708,
+13,16,62,30708,
+8,19,62,30708,
+11,38,52,30708,
+5,20,62,30708,
+20,37,50,30708,
+11,28,58,30708,
+8,22,61,30708,
+35,38,40,30723,
+2,28,59,30723,
+14,37,52,30723,
+8,29,58,30723,
+28,37,46,30723,
+2,13,64,30723,
+26,28,53,30723,
+13,40,50,30723,
+6,45,47,30723,
+30,39,43,30723,
+15,38,51,30723,
+3,6,65,30723,
+11,30,57,30723,
+33,34,45,30723,
+25,27,54,30723,
+15,18,61,30723,
+28,28,52,30723,
+20,44,44,30723,
+22,42,45,30723,
+36,36,41,30751,
+0,32,57,30751,
+3,30,58,30751,
+12,23,60,30751,
+3,42,50,30751,
+24,36,49,30751,
+13,36,53,30751,
+17,41,48,30751,
+27,29,52,30751,
+3,13,64,30751,
+11,43,48,30751,
+28,33,49,30751,
+3,28,59,30751,
+7,33,56,30751,
+8,27,59,30751,
+7,25,60,30751,
+24,43,43,30751,
+7,39,52,30751,
+7,16,63,30751,
+32,35,45,30751,
+0,7,65,30751,
+1,32,57,30751,
+8,31,57,30751,
+21,32,53,30751,
+4,17,63,30751,
+20,25,57,30751,
+20,43,45,30751,
+15,32,55,30751,
+15,45,45,30751,
+5,23,61,30751,
+9,15,63,30751,
+27,39,45,30751,
+5,5,65,30751,
+17,31,55,30751,
+5,35,55,30751,
+35,37,41,30772,
+5,43,49,30772,
+25,25,55,30772,
+29,35,47,30772,
+13,25,59,30772,
+1,7,65,30772,
+25,29,53,30772,
+6,12,64,30772,
+8,36,54,30772,
+6,44,48,30772,
+26,36,48,30772,
+10,24,60,30772,
+24,28,54,30772,
+0,26,60,30772,
+24,42,44,30772,
+24,26,55,30772,
+20,31,54,30772,
+9,10,64,30772,
+22,33,52,30772,
+16,39,50,30772,
+15,44,46,30772,
+2,32,57,30772,
+4,6,65,30772,
+34,39,40,30786,
+12,17,62,30786,
+23,38,48,30786,
+1,26,60,30786,
+17,25,58,30786,
+11,26,59,30786,
+25,38,47,30786,
+14,19,61,30786,
+5,38,53,30786,
+2,7,65,30786,
+14,41,49,30786,
+10,37,53,30786,
+14,22,60,30786,
+4,30,58,30786,
+2,26,60,30786,
+30,38,44,30786,
+22,36,50,30786,
+4,42,50,30786,
+20,42,46,30786,
+26,30,52,30786,
+6,20,62,30786,
+25,34,50,30786,
+10,41,50,30786,
+10,34,55,30786,
+22,41,46,30786,
+20,20,59,30786,
+11,32,56,30786,
+4,28,59,30786,
+8,11,64,30786,
+19,28,56,30786,
+34,38,41,30831,
+4,13,64,30831,
+7,46,46,30831,
+3,32,57,30831,
+12,13,63,30831,
+0,41,51,30831,
+31,36,45,30831,
+24,41,45,30831,
+15,24,59,30831,
+9,40,51,30831,
+19,21,59,30831,
+13,33,55,30831,
+1,41,51,30831,
+23,27,55,30831,
+19,39,49,30831,
+11,21,61,30831,
+7,45,47,30831,
+3,7,65,30831,
+15,43,47,30831,
+5,17,63,30831,
+29,29,51,30831,
+35,36,42,30874,
+28,30,51,30874,
+18,44,45,30874,
+0,37,54,30874,
+3,26,60,30874,
+18,19,60,30874,
+24,30,53,30874,
+12,45,46,30874,
+0,21,62,30874,
+12,35,54,30874,
+9,19,62,30874,
+23,34,51,30874,
+2,41,51,30874,
+21,38,49,30874,
+9,22,61,30874,
+19,26,57,30874,
+6,35,55,30874,
+11,42,49,30874,
+1,37,54,30874,
+19,30,55,30874,
+6,23,61,30874,
+23,29,54,30874,
+5,6,65,30874,
+6,43,49,30874,
+11,14,63,30874,
+14,29,57,30874,
+27,34,49,30874,
+29,41,42,30874,
+9,29,58,30874,
+1,21,62,30874,
+24,24,56,30874,
+8,39,52,30874,
+26,42,43,30874,
+5,30,58,30874,
+34,37,42,30894,
+8,16,63,30894,
+16,28,57,30894,
+14,27,58,30894,
+6,38,53,30894,
+12,44,47,30894,
+5,42,50,30894,
+17,20,60,30894,
+8,33,56,30894,
+21,22,58,30894,
+31,32,48,30894,
+8,25,60,30894,
+7,12,64,30894,
+2,37,54,30894,
+2,21,62,30894,
+18,43,46,30894,
+4,32,57,30894,
+18,22,59,30894,
+33,40,40,30894,
+17,36,52,30894,
+11,18,62,30894,
+7,44,48,30894,
+28,36,47,30894,
+0,8,65,30894,
+18,34,53,30894,
+27,38,46,30894,
+17,40,49,30894,
+25,31,52,30894,
+29,40,43,30894,
+19,35,52,30894,
+20,41,47,30894,
+16,35,53,30894,
+5,13,64,30894,
+13,20,61,30894,
+1,8,65,30894,
+5,28,59,30894,
+4,7,65,30894,
+23,25,56,30894,
+9,31,57,30894,
+33,39,41,30920,
+27,31,51,30920,
+9,27,59,30920,
+13,39,51,30920,
+3,41,51,30920,
+16,30,56,30920,
+0,34,56,30920,
+12,28,58,30920,
+24,40,46,30920,
+4,26,60,30920,
+0,14,64,30920,
+12,38,52,30920,
+0,18,63,30920,
+15,42,48,30920,
+2,8,65,30920,
+22,40,47,30920,
+1,34,56,30920,
+9,36,54,30920,
+12,30,57,30920,
+30,33,48,30920,
+1,14,64,30920,
+20,23,58,30920,
+7,20,62,30920,
+22,28,55,30920,
+14,31,56,30920,
+26,41,44,30920,
+18,37,51,30920,
+1,18,63,30920,
+33,33,46,30920,
+3,21,62,30920,
+15,15,62,30920,
+17,33,54,30920,
+3,37,54,30920,
+6,17,63,30920,
+30,37,45,30920,
+10,15,63,30920,
+14,40,50,30920,
+22,26,56,30920,
+10,10,64,30920,
+16,26,58,30920,
+32,34,46,30926,
+2,14,64,30926,
+8,46,46,30926,
+2,34,56,30926,
+14,16,62,30926,
+6,6,65,30926,
+0,24,61,30926,
+18,42,47,30926,
+16,21,60,30926,
+12,43,48,30926,
+20,36,51,30926,
+33,38,42,30980,
+11,24,60,30980,
+15,34,54,30980,
+2,18,63,30980,
+29,39,44,30980,
+15,37,52,30980,
+20,33,53,30980,
+25,37,48,30980,
+4,41,51,30980,
+9,11,64,30980,
+1,24,61,30980,
+5,32,57,30980,
+3,8,65,30980,
+13,23,60,30980,
+8,45,47,30980,
+17,23,59,30980,
+7,43,49,30980,
+23,31,53,30980,
+35,35,43,31000,
+7,23,61,31000,
+7,35,55,31000,
+17,17,61,31000,
+11,37,53,31000,
+23,37,49,31000,
+5,7,65,31000,
+6,30,58,31000,
+30,30,50,31000,
+6,42,50,31000,
+22,30,54,31000,
+26,40,45,31000,
+34,36,43,31010,
+24,35,50,31010,
+19,32,54,31010,
+19,24,58,31010,
+16,18,61,31010,
+2,24,61,31010,
+29,34,48,31010,
+3,14,64,31010,
+16,38,51,31010,
+6,28,59,31010,
+4,21,62,31010,
+18,29,56,31010,
+14,36,53,31010,
+5,26,60,31010,
+6,13,64,31010,
+4,37,54,31010,
+12,26,59,31010,
+26,32,51,31010,
+21,34,52,31010,
+3,34,56,31010,
+10,40,51,31010,
+7,38,53,31010,
+14,25,59,31010,
+29,31,50,31010,
+11,34,55,31010,
+13,17,62,31010,
+31,35,46,31010,
+11,41,50,31010,
+3,18,63,31010,
+18,27,57,31010,
+26,35,49,31010,
+0,40,52,31010,
+8,44,48,31010,
+12,32,56,31010,
+8,12,64,31010,
+24,32,52,31010,
+20,40,48,31010,
+1,40,52,31010,
+10,29,58,31010,
+19,38,50,31010,
+10,19,62,31010,
+4,8,65,31010,
+32,40,41,31054,
+10,22,61,31054,
+16,32,55,31054,
+9,39,52,31054,
+21,27,56,31054,
+16,45,45,31054,
+9,25,60,31054,
+0,9,65,31054,
+9,33,56,31054,
+9,16,63,31054,
+12,21,61,31054,
+24,39,47,31054,
+3,24,61,31054,
+13,13,63,31054,
+23,23,57,31054,
+15,19,61,31054,
+15,41,49,31054,
+7,17,63,31054,
+5,41,51,31054,
+1,9,65,31054,
+21,29,55,31054,
+27,37,47,31054,
+33,37,43,31082,
+28,32,50,31082,
+16,44,46,31082,
+4,14,64,31082,
+2,40,52,31082,
+8,20,62,31082,
+4,34,56,31082,
+6,32,57,31082,
+12,14,63,31082,
+15,22,60,31082,
+18,41,48,31082,
+22,24,57,31082,
+4,18,63,31082,
+22,39,48,31082,
+12,42,49,31082,
+32,39,42,31102,
+5,37,54,31102,
+18,31,55,31102,
+17,39,50,31102,
+10,27,59,31102,
+14,33,55,31102,
+6,7,65,31102,
+21,37,50,31102,
+13,45,46,31102,
+5,21,62,31102,
+2,9,65,31102,
+13,35,54,31102,
+10,31,57,31102,
+22,35,51,31102,
+29,38,45,31102,
+28,42,42,31102,
+10,36,54,31102,
+12,18,62,31102,
+30,36,46,31102,
+6,26,60,31102,
+7,30,58,31102,
+26,39,46,31102,
+7,42,50,31102,
+3,40,52,31102,
+18,25,58,31102,
+21,44,44,31102,
+9,46,46,31102,
+4,24,61,31102,
+16,24,59,31102,
+28,35,48,31102,
+23,43,44,31102,
+5,8,65,31102,
+13,44,47,31102,
+28,41,43,31112,
+16,43,47,31112,
+8,35,55,31112,
+8,43,49,31112,
+8,23,61,31112,
+7,28,59,31112,
+7,13,64,31112,
+21,43,45,31112,
+9,45,47,31112,
+21,25,57,31112,
+11,15,63,31112,
+3,9,65,31112,
+15,29,57,31112,
+25,33,51,31112,
+22,32,53,31112,
+10,11,64,31112,
+5,34,56,31112,
+5,14,64,31112,
+8,38,53,31112,
+13,28,58,31112,
+14,20,61,31112,
+13,38,52,31112,
+32,38,43,31188,
+34,35,44,31188,
+13,30,57,31188,
+23,42,45,31188,
+15,27,58,31188,
+21,31,54,31188,
+27,33,50,31188,
+6,41,51,31188,
+14,39,51,31188,
+5,18,63,31188,
+4,40,52,31188,
+12,24,60,31188,
+28,40,44,31188,
+20,28,56,31188,
+33,36,44,31211,
+6,37,54,31211,
+21,42,46,31211,
+6,21,62,31211,
+9,44,48,31211,
+9,12,64,31211,
+0,15,64,31211,
+26,27,54,31211,
+0,36,55,31211,
+19,44,45,31211,
+12,37,53,31211,
+1,15,64,31211,
+27,28,53,31211,
+20,39,49,31211,
+0,29,59,31211,
+4,9,65,31211,
+8,17,63,31211,
+25,36,49,31211,
+13,43,48,31211,
+15,31,56,31211,
+19,19,60,31211,
+17,28,57,31211,
+32,33,47,31211,
+20,21,59,31211,
+11,40,51,31211,
+7,32,57,31211,
+1,36,55,31211,
+23,33,52,31211,
+5,24,61,31211,
+7,7,65,31211,
+31,41,41,31235,
+31,31,49,31235,
+25,43,43,31235,
+1,29,59,31235,
+17,35,53,31235,
+16,42,48,31235,
+18,20,60,31235,
+18,36,52,31235,
+24,38,48,31235,
+12,41,50,31235,
+30,32,49,31235,
+2,15,64,31235,
+10,25,60,31235,
+9,20,62,31235,
+31,40,42,31248,
+2,36,55,31248,
+6,8,65,31248,
+25,42,44,31248,
+20,30,55,31248,
+18,40,49,31248,
+10,16,63,31248,
+0,31,58,31248,
+7,26,60,31248,
+0,10,65,31248,
+0,46,47,31248,
+12,34,55,31248,
+17,30,56,31248,
+14,23,60,31248,
+20,26,57,31248,
+23,36,50,31248,
+10,39,52,31248,
+25,28,54,31248,
+15,40,50,31248,
+10,33,56,31248,
+15,16,62,31248,
+23,41,46,31248,
+2,29,59,31248,
+31,34,47,31248,
+29,37,46,31248,
+19,43,46,31248,
+1,31,58,31248,
+11,29,58,31248,
+11,19,62,31248,
+26,29,53,31248,
+19,22,59,31248,
+19,34,53,31248,
+25,26,55,31248,
+1,10,65,31248,
+1,46,47,31248,
+11,22,61,31248,
+13,26,59,31248,
+16,34,54,31248,
+6,14,64,31248,
+6,34,56,31248,
+0,22,62,31248,
+8,30,58,31248,
+8,42,50,31248,
+1,22,62,31248,
+16,37,52,31248,
+2,46,47,31248,
+14,17,62,31248,
+28,29,52,31248,
+27,36,48,31248,
+18,33,54,31248,
+2,31,58,31248,
+5,40,52,31248,
+13,32,56,31248,
+0,45,48,31248,
+22,38,49,31248,
+8,13,64,31248,
+8,28,59,31248,
+32,37,44,31282,
+17,26,58,31282,
+26,38,47,31282,
+20,35,52,31282,
+6,18,63,31282,
+0,27,60,31282,
+2,10,65,31282,
+17,21,60,31282,
+1,27,60,31282,
+15,36,53,31282,
+1,45,48,31282,
+24,27,55,31282,
+0,19,63,31282,
+28,39,45,31282,
+3,36,55,31282,
+3,15,64,31282,
+0,39,53,31282,
+1,19,63,31282,
+5,9,65,31282,
+31,39,43,31304,
+11,31,57,31304,
+9,35,55,31304,
+9,43,49,31304,
+3,29,59,31304,
+25,41,45,31304,
+29,33,49,31304,
+19,37,51,31304,
+21,41,47,31304,
+15,25,59,31304,
+7,41,51,31304,
+13,21,61,31304,
+1,39,53,31304,
+11,27,59,31304,
+9,23,61,31304,
+22,22,58,31304,
+26,34,50,31304,
+2,22,62,31304,
+10,46,46,31304,
+38,38,38,31328,
+24,34,51,31328,
+11,36,54,31328,
+6,24,61,31328,
+27,30,52,31328,
+2,27,60,31328,
+24,29,54,31328,
+2,45,48,31328,
+25,30,53,31328,
+2,19,63,31328,
+13,42,49,31328,
+19,42,47,31328,
+7,37,54,31328,
+30,35,47,31328,
+3,10,65,31328,
+9,38,53,31328,
+37,38,39,31360,
+18,23,59,31360,
+17,18,61,31360,
+10,45,47,31360,
+3,46,47,31360,
+7,21,62,31360,
+17,38,51,31360,
+13,14,63,31360,
+2,39,53,31360,
+21,23,58,31360,
+3,31,58,31360,
+4,36,55,31360,
+0,44,49,31360,
+3,22,62,31360,
+13,18,62,31360,
+24,25,56,31360,
+14,35,54,31360,
+14,45,46,31360,
+4,15,64,31360,
+34,34,45,31360,
+8,32,57,31360,
+3,27,60,31360,
+4,29,59,31360,
+1,44,49,31360,
+12,15,63,31360,
+0,33,57,31360,
+23,28,55,31360,
+11,11,64,31360,
+36,39,39,31412,
+37,37,40,31412,
+16,41,49,31412,
+16,19,61,31412,
+19,29,56,31412,
+7,8,65,31412,
+23,40,47,31412,
+21,36,51,31412,
+17,32,55,31412,
+3,45,48,31412,
+21,33,53,31412,
+33,35,45,31412,
+17,45,45,31412,
+15,33,55,31412,
+3,19,63,31412,
+1,33,57,31412,
+3,39,53,31412,
+9,17,63,31412,
+19,27,57,31412,
+20,32,54,31412,
+10,44,48,31412,
+8,26,60,31412,
+6,40,52,31412,
+16,22,60,31412,
+36,38,40,31419,
+10,12,64,31419,
+20,24,58,31419,
+17,44,46,31419,
+4,46,47,31419,
+4,10,65,31419,
+7,14,64,31419,
+28,34,49,31419,
+14,44,47,31419,
+7,34,56,31419,
+4,31,58,31419,
+31,38,44,31419,
+25,40,46,31419,
+2,44,49,31419,
+23,26,56,31419,
+26,31,52,31419,
+2,33,57,31419,
+7,18,63,31419,
+29,30,51,31419,
+6,9,65,31419,
+27,42,43,31419,
+4,22,62,31419,
+20,38,50,31419,
+14,38,52,31419,
+22,34,52,31419,
+14,28,58,31419,
+10,20,62,31419,
+28,38,46,31419,
+4,45,48,31419,
+12,40,51,31419,
+32,36,45,31437,
+21,40,48,31437,
+14,30,57,31437,
+9,42,50,31437,
+4,27,60,31437,
+23,30,54,31437,
+30,41,42,31437,
+9,30,58,31437,
+18,39,50,31437,
+13,24,60,31437,
+0,25,61,31437,
+15,20,61,31437,
+29,36,47,31437,
+0,11,65,31437,
+19,41,48,31437,
+11,39,52,31437,
+4,19,63,31437,
+11,16,63,31437,
+5,36,55,31437,
+11,33,56,31437,
+24,37,49,31437,
+7,24,61,31437,
+28,31,51,31437,
+17,24,59,31437,
+3,44,49,31437,
+24,31,53,31437,
+27,41,44,31437,
+8,41,51,31437,
+4,39,53,31437,
+9,13,64,31437,
+35,39,40,31498,
+36,37,41,31498,
+5,15,64,31498,
+16,29,57,31498,
+9,28,59,31498,
+11,25,60,31498,
+3,33,57,31498,
+13,37,53,31498,
+1,11,65,31498,
+19,31,55,31498,
+1,25,61,31498,
+15,39,51,31498,
+17,43,47,31498,
+5,29,59,31498,
+8,21,62,31498,
+0,43,50,31498,
+12,29,58,31498,
+8,37,54,31498,
+12,19,62,31498,
+30,40,43,31498,
+16,27,58,31498,
+22,27,56,31498,
+14,43,48,31498,
+26,37,48,31498,
+12,22,61,31498,
+10,43,49,31498,
+25,35,50,31498,
+13,41,50,31498,
+2,11,65,31498,
+5,10,65,31498,
+5,31,58,31498,
+35,38,41,31525,
+2,25,61,31525,
+13,34,55,31525,
+10,35,55,31525,
+10,23,61,31525,
+22,29,55,31525,
+19,25,58,31525,
+5,46,47,31525,
+1,43,50,31525,
+32,32,48,31525,
+0,16,64,31525,
+4,44,49,31525,
+1,16,64,31525,
+2,43,50,31525,
+25,32,52,31525,
+22,37,50,31525,
+16,31,56,31525,
+7,40,52,31525,
+8,8,65,31525,
+5,22,62,31525,
+10,38,53,31525,
+14,26,59,31525,
+11,46,46,31525,
+4,33,57,31525,
+31,33,48,31525,
+12,27,59,31525,
+27,32,51,31525,
+12,31,57,31525,
+23,39,48,31525,
+5,45,48,31525,
+5,27,60,31525,
+27,40,45,31525,
+23,24,57,31525,
+9,32,57,31525,
+15,23,60,31525,
+5,19,63,31525,
+3,11,65,31525,
+7,9,65,31525,
+31,37,45,31534,
+3,25,61,31534,
+27,35,49,31534,
+23,35,51,31534,
+11,45,47,31534,
+5,39,53,31534,
+25,39,47,31534,
+16,16,62,31534,
+8,14,64,31534,
+0,0,66,31534,
+34,40,40,31581,
+36,36,42,31581,
+14,32,56,31581,
+12,36,54,31581,
+22,44,44,31581,
+8,34,56,31581,
+16,40,50,31581,
+2,16,64,31581,
+0,1,66,31581,
+17,42,48,31581,
+8,18,63,31581,
+6,15,64,31581,
+6,36,55,31581,
+30,39,44,31581,
+9,26,60,31581,
+18,28,57,31581,
+18,35,53,31581,
+22,43,45,31581,
+6,29,59,31581,
+1,1,66,31581,
+3,43,50,31581,
+34,39,41,31620,
+14,21,61,31620,
+10,17,63,31620,
+22,25,57,31620,
+15,17,62,31620,
+35,37,42,31620,
+30,34,48,31620,
+0,38,54,31620,
+18,30,56,31620,
+0,2,66,31620,
+6,10,65,31620,
+14,42,49,31620,
+33,34,46,31620,
+6,31,58,31620,
+22,31,54,31620,
+20,44,45,31620,
+24,43,44,31620,
+3,16,64,31620,
+19,36,52,31620,
+8,24,61,31620,
+14,14,63,31620,
+11,12,64,31620,
+30,31,50,31620,
+11,44,48,31620,
+0,35,56,31620,
+1,38,54,31620,
+6,46,47,31620,
+1,2,66,31620,
+17,34,54,31620,
+19,20,60,31620,
+21,28,56,31620,
+16,36,53,31620,
+5,44,49,31620,
+16,25,59,31620,
+4,25,61,31620,
+19,40,49,31620,
+4,11,65,31620,
+17,37,52,31620,
+1,35,56,31620,
+23,32,53,31620,
+28,37,47,31620,
+13,15,63,31620,
+21,39,49,31620,
+21,21,59,31620,
+9,41,51,31620,
+5,33,57,31620,
+2,38,54,31620,
+34,38,42,31664,
+10,42,50,31664,
+18,26,58,31664,
+14,18,62,31664,
+6,22,62,31664,
+22,42,46,31664,
+2,2,66,31664,
+10,30,58,31664,
+18,21,60,31664,
+29,32,50,31664,
+10,13,64,31664,
+0,42,51,31664,
+11,20,62,31664,
+32,35,46,31664,
+6,27,60,31664,
+20,22,59,31664,
+20,43,46,31664,
+24,42,45,31664,
+10,28,59,31664,
+0,3,66,31664,
+6,45,48,31664,
+20,34,53,31664,
+2,35,56,31664,
+4,43,50,31664,
+21,26,57,31664,
+15,45,46,31664,
+19,33,54,31664,
+1,3,66,31664,
+21,30,55,31664,
+9,21,62,31664,
+1,42,51,31664,
+26,33,51,31664,
+27,39,46,31664,
+15,35,54,31664,
+6,19,63,31664,
+9,37,54,31664,
+6,39,53,31664,
+4,16,64,31664,
+8,40,52,31664,
+12,16,63,31664,
+18,18,61,31664,
+3,38,54,31664,
+24,33,52,31664,
+0,12,65,31664,
+29,42,42,31678,
+12,39,52,31678,
+30,38,45,31678,
+2,3,66,31678,
+0,20,63,31678,
+12,25,60,31678,
+2,42,51,31678,
+18,38,51,31678,
+12,33,56,31678,
+8,9,65,31678,
+1,12,65,31678,
+1,20,63,31678,
+7,36,55,31678,
+16,33,55,31678,
+33,40,41,31733,
+7,15,64,31733,
+35,36,43,31733,
+20,37,51,31733,
+13,40,51,31733,
+29,35,48,31733,
+21,35,52,31733,
+15,44,47,31733,
+3,35,56,31733,
+11,23,61,31733,
+17,19,61,31733,
+11,43,49,31733,
+5,25,61,31733,
+5,11,65,31733,
+19,23,59,31733,
+7,29,59,31733,
+29,41,43,31733,
+17,41,49,31733,
+11,35,55,31733,
+0,4,66,31733,
+14,24,60,31733,
+24,36,50,31733,
+10,32,57,31733,
+0,23,62,31733,
+15,28,58,31733,
+15,38,52,31733,
+25,38,48,31733,
+18,32,55,31733,
+2,20,63,31733,
+20,42,47,31733,
+9,34,56,31733,
+9,14,64,31733,
+1,4,66,31733,
+31,36,46,31733,
+6,44,49,31733,
+2,12,65,31733,
+24,41,46,31733,
+28,33,50,31733,
+26,36,49,31733,
+17,22,60,31733,
+3,42,51,31733,
+5,43,50,31733,
+7,46,47,31733,
+1,23,62,31733,
+11,38,53,31733,
+7,31,58,31733,
+18,45,45,31733,
+3,3,66,31733,
+9,18,63,31733,
+22,41,47,31733,
+13,22,61,31733,
+7,10,65,31733,
+23,38,49,31733,
+27,27,54,31733,
+6,33,57,31733,
+33,39,42,31768,
+13,29,58,31768,
+15,30,57,31768,
+26,43,43,31768,
+13,19,62,31768,
+14,37,53,31768,
+34,37,43,31768,
+2,4,66,31768,
+4,38,54,31768,
+18,44,46,31768,
+10,26,60,31768,
+26,42,44,31768,
+26,28,54,31768,
+12,46,46,31768,
+28,28,53,31768,
+26,26,55,31768,
+4,35,56,31768,
+14,41,50,31768,
+2,23,62,31768,
+29,40,44,31768,
+22,23,58,31768,
+5,16,64,31768,
+20,29,56,31768,
+16,20,61,31768,
+7,22,62,31768,
+14,34,55,31768,
+12,45,47,31768,
+3,12,65,31768,
+7,27,60,31768,
+3,20,63,31768,
+20,27,57,31768,
+7,45,48,31768,
+9,24,61,31768,
+16,39,51,31768,
+15,43,48,31768,
+7,39,53,31768,
+27,29,53,31768,
+13,27,59,31768,
+17,29,57,31768,
+7,19,63,31768,
+11,17,63,31768,
+25,27,55,31768,
+13,31,57,31768,
+22,36,51,31768,
+21,32,54,31768,
+13,36,54,31768,
+3,4,66,31768,
+0,30,59,31768,
+0,5,66,31768,
+21,24,58,31768,
+18,24,59,31768,
+4,42,51,31768,
+33,38,43,31838,
+18,43,47,31838,
+26,41,45,31838,
+19,39,50,31838,
+17,27,58,31838,
+25,34,51,31838,
+22,33,53,31838,
+27,38,47,31838,
+1,30,59,31838,
+25,29,54,31838,
+6,11,65,31838,
+10,41,51,31838,
+15,26,59,31838,
+1,5,66,31838,
+3,23,62,31838,
+6,25,61,31838,
+12,12,64,31838,
+12,44,48,31838,
+0,28,60,31838,
+28,36,48,31838,
+2,5,66,31838,
+24,40,47,31838,
+10,21,62,31838,
+8,15,64,31838,
+16,23,60,31838,
+8,36,55,31838,
+11,42,50,31838,
+9,40,52,31838,
+26,30,53,31838,
+15,32,56,31838,
+21,38,50,31838,
+20,41,48,31838,
+1,28,60,31838,
+11,30,58,31838,
+4,20,63,31838,
+5,38,54,31838,
+6,43,50,31838,
+10,37,54,31838,
+0,41,52,31838,
+0,17,64,31838,
+30,37,46,31838,
+2,30,59,31838,
+24,28,55,31838,
+27,34,50,31838,
+4,12,65,31838,
+35,35,44,31886,
+7,44,49,31886,
+25,25,56,31886,
+20,31,55,31886,
+31,32,49,31886,
+1,17,64,31886,
+5,35,56,31886,
+11,13,64,31886,
+17,31,56,31886,
+29,29,52,31886,
+1,41,52,31886,
+32,41,41,31886,
+8,29,59,31886,
+11,28,59,31886,
+29,39,45,31886,
+15,21,61,31886,
+9,9,65,31886,
+33,33,47,31886,
+7,33,57,31886,
+22,40,48,31886,
+12,20,62,31886,
+34,36,44,31896,
+2,28,60,31896,
+4,4,66,31896,
+32,40,42,31896,
+6,16,64,31896,
+28,30,52,31896,
+24,26,56,31896,
+0,32,58,31896,
+8,10,65,31896,
+16,17,62,31896,
+8,46,47,31896,
+2,17,64,31896,
+1,32,58,31896,
+20,25,58,31896,
+17,40,50,31896,
+4,23,62,31896,
+32,34,47,31896,
+8,31,58,31896,
+2,41,52,31896,
+23,34,52,31896,
+3,30,59,31896,
+14,15,63,31896,
+3,5,66,31896,
+30,33,49,31896,
+5,42,51,31896,
+15,42,49,31896,
+24,30,54,31896,
+0,6,66,31896,
+8,22,62,31896,
+26,40,46,31896,
+18,42,48,31896,
+10,34,56,31896,
+2,32,58,31896,
+10,14,64,31896,
+8,45,48,31896,
+15,18,62,31896,
+10,18,63,31896,
+8,27,60,31896,
+3,28,60,31896,
+1,6,66,31896,
+8,39,53,31896,
+5,20,63,31896,
+13,33,56,31896,
+12,23,61,31896,
+0,13,65,31896,
+13,25,60,31896,
+0,37,55,31896,
+3,41,52,31896,
+27,31,52,31896,
+12,43,49,31896,
+23,27,56,31896,
+8,19,63,31896,
+32,39,43,31957,
+13,39,52,31957,
+19,28,57,31957,
+12,35,55,31957,
+3,17,64,31957,
+5,12,65,31957,
+17,36,53,31957,
+13,16,63,31957,
+11,32,57,31957,
+33,37,44,31957,
+19,35,53,31957,
+1,37,55,31957,
+17,25,59,31957,
+7,25,61,31957,
+25,31,53,31957,
+31,35,47,31957,
+1,13,65,31957,
+25,37,49,31957,
+23,29,55,31957,
+7,11,65,31957,
+6,38,54,31957,
+2,6,66,31957,
+18,34,54,31957,
+16,35,54,31957,
+14,40,51,31957,
+6,35,56,31957,
+4,5,66,31957,
+0,26,61,31957,
+12,38,53,31957,
+4,30,59,31957,
+18,37,52,31957,
+16,45,46,31957,
+19,30,56,31957,
+28,42,43,31957,
+3,32,58,31957,
+10,24,61,31957,
+11,26,60,31957,
+23,37,50,31957,
+1,26,61,31957,
+29,34,49,31957,
+7,43,50,31957,
+2,13,65,31957,
+2,37,55,31957,
+5,23,62,31957,
+20,20,60,31957,
+4,28,60,31957,
+20,36,52,31957,
+4,17,64,31957,
+26,35,50,31957,
+30,30,51,31957,
+6,42,51,31957,
+24,24,57,31957,
+19,26,58,31957,
+8,44,49,31957,
+29,38,46,31972,
+13,46,46,31972,
+4,41,52,31972,
+16,44,47,31972,
+15,24,60,31972,
+23,44,44,31972,
+7,16,64,31972,
+3,6,66,31972,
+14,19,62,31972,
+14,29,58,31972,
+2,26,61,31972,
+28,41,44,31972,
+14,22,61,31972,
+24,39,48,31972,
+20,40,49,31972,
+8,33,57,31972,
+12,17,63,31972,
+21,44,45,31972,
+9,36,55,31972,
+27,37,48,31972,
+24,35,51,31972,
+9,15,64,31972,
+19,21,60,31972,
+3,37,55,31972,
+13,45,47,31972,
+17,33,55,31972,
+3,13,65,31972,
+15,37,53,31972,
+23,25,57,31972,
+11,41,51,31972,
+23,43,45,31972,
+29,31,51,31972,
+9,29,59,31972,
+26,32,52,31972,
+10,40,52,31972,
+16,28,58,31972,
+32,38,44,32030,
+16,38,52,32030,
+22,28,56,32030,
+4,32,58,32030,
+0,34,57,32030,
+20,33,54,32030,
+16,30,57,32030,
+6,20,63,32030,
+6,12,65,32030,
+30,36,47,32030,
+0,7,66,32030,
+3,26,61,32030,
+19,38,51,32030,
+18,41,49,32030,
+21,43,46,32030,
+11,37,54,32030,
+5,30,59,32030,
+11,21,62,32030,
+15,34,55,32030,
+1,34,57,32030,
+14,27,59,32030,
+21,34,53,32030,
+9,46,47,32030,
+1,7,66,32030,
+14,31,57,32030,
+31,41,42,32055,
+9,10,65,32055,
+22,39,49,32055,
+5,5,66,32055,
+34,35,45,32055,
+26,39,47,32055,
+9,31,58,32055,
+23,31,54,32055,
+21,22,59,32055,
+15,41,50,32055,
+18,19,61,32055,
+12,42,50,32055,
+4,6,66,32055,
+18,22,60,32055,
+14,36,54,32055,
+12,30,58,32055,
+23,42,46,32055,
+9,22,62,32055,
+13,44,48,32055,
+16,43,48,32055,
+12,28,59,32055,
+22,30,55,32055,
+24,32,53,32055,
+22,26,57,32055,
+38,38,39,32126,
+7,38,54,32126,
+12,13,64,32126,
+2,7,66,32126,
+6,23,62,32126,
+28,40,45,32126,
+5,28,60,32126,
+2,34,57,32126,
+28,32,51,32126,
+0,40,53,32126,
+17,20,61,32126,
+8,11,65,32126,
+4,13,65,32126,
+4,37,55,32126,
+19,32,55,32126,
+20,23,59,32126,
+33,36,45,32126,
+7,35,56,32126,
+9,45,48,32126,
+25,43,44,32126,
+1,40,53,32126,
+28,35,49,32126,
+5,41,52,32126,
+8,25,61,32126,
+0,21,63,32126,
+9,27,60,32126,
+31,40,43,32126,
+5,17,64,32126,
+19,45,45,32126,
+21,37,51,32126,
+37,39,39,32143,
+9,19,63,32143,
+1,21,63,32143,
+17,39,51,32143,
+9,39,53,32143,
+11,14,64,32143,
+11,34,56,32143,
+5,32,58,32143,
+16,26,59,32143,
+22,35,52,32143,
+2,40,53,32143,
+37,38,40,32163,
+19,44,46,32163,
+8,43,50,32163,
+13,20,62,32163,
+4,26,61,32163,
+11,18,63,32163,
+18,29,57,32163,
+25,42,45,32163,
+2,21,63,32163,
+7,42,51,32163,
+21,42,47,32163,
+3,7,66,32163,
+3,34,57,32163,
+8,16,64,32163,
+16,32,56,32163,
+5,6,66,32163,
+36,39,40,32210,
+32,33,48,32210,
+12,32,57,32210,
+6,30,59,32210,
+18,27,58,32210,
+0,47,47,32210,
+11,24,61,32210,
+7,12,65,32210,
+32,37,45,32210,
+21,29,56,32210,
+16,21,61,32210,
+19,24,59,32210,
+7,20,63,32210,
+17,23,60,32210,
+3,40,53,32210,
+31,39,44,32210,
+25,33,52,32210,
+9,44,49,32210,
+9,33,57,32210,
+21,27,57,32210,
+15,15,63,32210,
+27,33,51,32210,
+19,43,47,32210,
+5,37,55,32210,
+29,37,47,32210,
+23,41,47,32210,
+13,23,61,32210,
+37,37,41,32229,
+1,47,47,32229,
+13,35,55,32229,
+13,43,49,32229,
+3,21,63,32229,
+5,13,65,32229,
+0,46,48,32229,
+0,18,64,32229,
+12,26,60,32229,
+0,8,66,32229,
+0,24,62,32229,
+6,28,60,32229,
+20,39,50,32229,
+25,36,50,32229,
+4,34,57,32229,
+31,34,48,32229,
+24,38,49,32229,
+14,16,63,32229,
+16,42,49,32229,
+14,25,60,32229,
+28,39,46,32229,
+4,7,66,32229,
+18,31,56,32229,
+1,18,64,32229,
+0,14,65,32229,
+36,38,41,32239,
+10,15,64,32239,
+1,46,48,32239,
+6,17,64,32239,
+10,36,55,32239,
+14,33,56,32239,
+6,41,52,32239,
+14,39,52,32239,
+1,24,62,32239,
+1,8,66,32239,
+7,23,62,32239,
+23,23,58,32239,
+25,41,46,32239,
+31,31,50,32239,
+10,29,59,32239,
+2,47,47,32239,
+17,17,62,32239,
+1,14,65,32239,
+13,38,53,32239,
+5,26,61,32239,
+2,24,62,32239,
+16,18,62,32239,
+2,18,64,32239,
+18,40,50,32239,
+2,8,66,32239,
+8,38,54,32239,
+26,38,48,32239,
+6,32,58,32239,
+2,46,48,32239,
+30,32,50,32239,
+22,32,54,32239,
+22,24,58,32239,
+10,46,47,32239,
+2,14,65,32239,
+35,40,40,32266,
+10,31,58,32266,
+4,40,53,32266,
+8,35,56,32266,
+10,10,65,32266,
+11,40,52,32266,
+21,41,48,32266,
+27,36,49,32266,
+23,36,51,32266,
+12,41,51,32266,
+4,21,63,32266,
+0,45,49,32266,
+15,40,51,32266,
+23,33,53,32266,
+1,45,49,32266,
+13,17,63,32266,
+9,25,61,32266,
+3,47,47,32266,
+27,43,43,32266,
+35,39,41,32292,
+9,11,65,32292,
+21,31,55,32292,
+22,38,50,32292,
+6,6,66,32292,
+10,22,62,32292,
+14,46,46,32292,
+30,42,42,32292,
+34,34,46,32292,
+8,42,51,32292,
+27,28,54,32292,
+30,35,48,32292,
+36,37,42,32320,
+19,42,48,32320,
+3,8,66,32320,
+10,27,60,32320,
+12,37,54,32320,
+12,21,62,32320,
+27,42,44,32320,
+3,24,62,32320,
+3,46,48,32320,
+18,36,53,32320,
+3,18,64,32320,
+10,45,48,32320,
+6,37,55,32320,
+17,45,46,32320,
+2,45,49,32320,
+15,22,61,32320,
+5,7,66,32320,
+21,25,58,32320,
+18,25,59,32320,
+5,34,57,32320,
+15,29,58,32320,
+15,19,62,32320,
+30,41,43,32320,
+9,43,50,32320,
+7,30,59,32320,
+33,35,46,32320,
+14,45,47,32320,
+10,19,63,32320,
+31,38,45,32320,
+17,35,54,32320,
+6,13,65,32320,
+26,27,55,32320,
+3,14,65,32320,
+29,33,50,32320,
+10,39,53,32320,
+16,24,60,32320,
+0,36,56,32320,
+7,28,60,32320,
+35,38,42,32366,
+13,30,58,32366,
+26,34,51,32366,
+23,40,48,32366,
+13,42,50,32366,
+20,28,57,32366,
+8,12,65,32366,
+26,29,54,32366,
+6,26,61,32366,
+9,16,64,32366,
+8,20,63,32366,
+19,34,54,32366,
+1,36,56,32366,
+19,37,52,32366,
+13,13,64,32366,
+17,44,47,32366,
+28,29,53,32366,
+4,47,47,32366,
+7,41,52,32366,
+5,40,53,32366,
+13,28,59,32366,
+20,35,53,32366,
+25,28,55,32366,
+16,37,53,32366,
+25,40,47,32366,
+7,17,64,32366,
+15,31,57,32366,
+27,41,45,32366,
+3,45,49,32366,
+15,27,59,32366,
+5,21,63,32366,
+4,46,48,32366,
+12,14,64,32366,
+0,44,50,32366,
+32,36,46,32366,
+4,24,62,32366,
+2,36,56,32366,
+30,40,44,32366,
+24,34,52,32366,
+4,18,64,32366,
+20,30,56,32366,
+12,34,56,32366,
+14,44,48,32366,
+4,8,66,32366,
+12,18,63,32366,
+0,39,54,32366,
+17,28,58,32366,
+10,44,49,32366,
+16,34,55,32366,
+8,23,62,32366,
+7,32,58,32366,
+16,41,50,32366,
+34,40,41,32392,
+0,9,66,32392,
+28,38,47,32392,
+4,14,65,32392,
+1,44,50,32392,
+25,26,56,32392,
+17,38,52,32392,
+15,36,54,32392,
+27,30,53,32392,
+17,30,57,32392,
+1,39,54,32392,
+10,33,57,32392,
+1,9,66,32392,
+18,33,55,32392,
+20,26,58,32392,
+2,44,50,32392,
+28,34,50,32392,
+14,20,62,32392,
+3,36,56,32392,
+6,34,57,32392,
+0,29,60,32392,
+9,38,54,32392,
+2,39,54,32392,
+6,7,66,32392,
+34,39,42,32437,
+25,30,54,32437,
+2,9,66,32437,
+24,27,56,32437,
+29,36,48,32437,
+12,24,61,32437,
+21,36,52,32437,
+36,36,43,32437,
+20,21,60,32437,
+11,15,64,32437,
+11,36,55,32437,
+17,43,48,32437,
+4,45,49,32437,
+0,31,59,32437,
+9,35,56,32437,
+21,40,49,32437,
+13,32,57,32437,
+1,29,60,32437,
+24,29,55,32437,
+1,31,59,32437,
+7,37,55,32437,
+7,13,65,32437,
+35,37,43,32466,
+19,41,49,32466,
+11,29,59,32466,
+5,47,47,32466,
+19,19,61,32466,
+8,30,59,32466,
+24,37,50,32466,
+5,46,48,32466,
+6,40,53,32466,
+29,30,52,32466,
+19,22,60,32466,
+5,24,62,32466,
+3,44,50,32466,
+20,38,51,32466,
+5,8,66,32466,
+13,26,60,32466,
+5,18,64,32466,
+18,20,61,32466,
+2,29,60,32466,
+22,44,45,32466,
+27,40,46,32466,
+2,31,59,32466,
+18,39,51,32466,
+31,37,46,32466,
+6,21,63,32466,
+26,31,53,32466,
+3,9,66,32466,
+14,43,49,32466,
+5,14,65,32466,
+9,42,51,32466,
+3,39,54,32466,
+11,31,58,32466,
+11,46,47,32466,
+21,33,54,32466,
+14,35,55,32466,
+26,37,49,32466,
+17,26,59,32466,
+14,23,61,32466,
+10,25,61,32466,
+30,39,45,32466,
+10,11,65,32466,
+7,26,61,32466,
+8,28,60,32466,
+4,36,56,32466,
+24,44,44,32466,
+12,40,52,32466,
+8,17,64,32466,
+20,32,55,32466,
+28,31,52,32466,
+22,34,53,32466,
+23,28,56,32466,
+22,22,59,32466,
+11,22,62,32466,
+10,43,50,32466,
+22,43,46,32466,
+34,38,43,32512,
+14,38,53,32512,
+8,41,52,32512,
+17,32,56,32512,
+32,32,49,32512,
+0,43,51,32512,
+3,29,60,32512,
+15,16,63,32512,
+24,43,45,32512,
+24,25,57,32512,
+20,45,45,32512,
+15,39,52,32512,
+15,33,56,32512,
+11,45,48,32512,
+25,39,48,32512,
+11,27,60,32512,
+0,27,61,32512,
+15,25,60,32512,
+9,20,63,32512,
+0,15,65,32512,
+9,12,65,32512,
+11,39,53,32512,
+21,23,59,32512,
+1,15,65,32512,
+1,27,61,32512,
+11,19,63,32512,
+31,33,49,32512,
+33,41,41,32532,
+25,35,51,32532,
+19,29,57,32532,
+13,41,51,32532,
+17,21,61,32532,
+3,31,59,32532,
+5,45,49,32532,
+23,39,49,32532,
+1,43,51,32532,
+20,44,46,32532,
+8,32,58,32532,
+10,16,64,32532,
+4,44,50,32532,
+0,22,63,32532,
+24,31,54,32532,
+0,33,58,32532,
+4,9,66,32532,
+18,23,60,32532,
+4,39,54,32532,
+33,40,42,32551,
+29,42,43,32551,
+22,37,51,32551,
+27,35,50,32551,
+33,34,47,32551,
+23,30,55,32551,
+23,26,57,32551,
+6,47,47,32551,
+2,15,65,32551,
+2,43,51,32551,
+1,33,58,32551,
+14,17,63,32551,
+1,22,63,32551,
+19,27,58,32551,
+7,7,66,32551,
+7,34,57,32551,
+17,42,49,32551,
+9,23,62,32551,
+2,27,61,32551,
+13,21,62,32551,
+13,37,54,32551,
+6,18,64,32551,
+24,42,46,32551,
+6,8,66,32551,
+6,24,62,32551,
+6,46,48,32551,
+0,10,66,32551,
+0,19,64,32551,
+1,10,66,32551,
+28,37,48,32551,
+6,14,65,32551,
+5,36,56,32551,
+17,18,62,32551,
+2,22,63,32551,
+15,46,46,32551,
+20,24,59,32551,
+2,33,58,32551,
+35,36,44,32582,
+30,34,49,32582,
+4,29,60,32582,
+16,40,51,32582,
+22,42,47,32582,
+27,32,52,32582,
+32,35,47,32582,
+8,13,65,32582,
+11,44,49,32582,
+19,31,56,32582,
+23,35,52,32582,
+25,32,53,32582,
+4,31,59,32582,
+8,37,55,32582,
+29,41,44,32582,
+7,40,53,32582,
+20,43,47,32582,
+1,19,64,32582,
+15,45,47,32582,
+27,39,47,32582,
+33,39,43,32610,
+3,15,65,32610,
+11,33,57,32610,
+3,27,61,32610,
+3,43,51,32610,
+7,21,63,32610,
+14,42,50,32610,
+10,38,54,32610,
+2,10,66,32610,
+30,38,46,32610,
+14,30,58,32610,
+34,37,44,32625,
+2,19,64,32625,
+10,35,56,32625,
+13,34,56,32625,
+16,29,58,32625,
+13,14,64,32625,
+26,43,44,32625,
+16,22,61,32625,
+5,44,50,32625,
+22,29,56,32625,
+8,26,61,32625,
+14,28,59,32625,
+19,40,50,32625,
+16,19,62,32625,
+5,9,66,32625,
+3,33,58,32625,
+13,18,63,32625,
+3,22,63,32625,
+9,30,59,32625,
+22,27,57,32625,
+5,39,54,32625,
+21,39,50,32625,
+6,45,49,32625,
+30,31,51,32625,
+9,28,60,32625,
+3,10,66,32625,
+10,42,51,32625,
+17,24,60,32625,
+26,42,45,32625,
+15,44,48,32625,
+18,35,54,32625,
+12,36,55,32625,
+18,45,46,32625,
+12,15,64,32625,
+16,27,59,32625,
+19,36,53,32625,
+24,41,47,32625,
+31,36,47,32652,
+9,41,52,32652,
+13,24,61,32652,
+4,15,65,32652,
+29,32,51,32652,
+12,29,59,32652,
+16,31,57,32652,
+3,19,64,32652,
+5,29,60,32652,
+4,43,51,32652,
+9,17,64,32652,
+29,40,45,32652,
+4,27,61,32652,
+11,25,61,32652,
+11,11,65,32652,
+17,37,53,32652,
+29,35,49,32652,
+19,25,59,32652,
+7,47,47,32652,
+5,31,59,32652,
+6,36,56,32652,
+0,42,52,32652,
+20,42,48,32652,
+16,36,54,32652,
+1,42,52,32652,
+7,18,64,32652,
+7,8,66,32652,
+14,32,57,32652,
+32,41,42,32721,
+4,22,63,32721,
+10,12,65,32721,
+0,38,55,32721,
+23,24,58,32721,
+4,33,58,32721,
+10,20,63,32721,
+33,38,44,32721,
+22,41,48,32721,
+18,44,47,32721,
+0,25,62,32721,
+12,31,58,32721,
+26,33,52,32721,
+7,24,62,32721,
+8,34,57,32721,
+15,20,62,32721,
+7,46,48,32721,
+9,32,58,32721,
+12,46,47,32721,
+23,32,54,32721,
+1,38,55,32721,
+22,31,55,32721,
+1,25,62,32721,
+17,34,55,32721,
+11,43,50,32721,
+17,41,50,32721,
+25,38,49,32721,
+7,14,65,32721,
+12,22,62,32721,
+4,10,66,32721,
+20,34,54,32721,
+2,42,52,32721,
+26,36,50,32721,
+18,38,52,32721,
+6,44,50,32721,
+14,26,60,32721,
+18,28,58,32721,
+4,19,64,32721,
+11,16,64,32721,
+6,39,54,32721,
+23,38,50,32721,
+32,40,43,32740,
+2,25,62,32740,
+10,23,62,32740,
+22,25,58,32740,
+26,41,46,32740,
+20,37,52,32740,
+12,27,60,32740,
+6,9,66,32740,
+8,40,53,32740,
+18,30,57,32740,
+2,38,55,32740,
+24,36,51,32740,
+12,45,48,32740,
+13,40,52,32740,
+21,28,57,32740,
+8,21,63,32740,
+24,33,53,32740,
+0,35,57,32740,
+28,33,51,32740,
+12,19,63,32740,
+12,39,53,32740,
+5,27,61,32740,
+15,43,49,32740,
+19,33,55,32740,
+9,13,65,32740,
+35,35,45,32769,
+7,45,49,32769,
+5,43,51,32769,
+9,37,55,32769,
+1,35,57,32769,
+15,23,61,32769,
+5,15,65,32769,
+21,35,53,32769,
+15,35,55,32769,
+6,29,60,32769,
+21,30,56,32769,
+18,43,48,32769,
+34,36,45,32798,
+0,11,66,32798,
+27,38,48,32798,
+3,42,52,32798,
+5,33,58,32798,
+30,37,47,32798,
+29,39,46,32798,
+9,26,61,32798,
+6,31,59,32798,
+14,41,51,32798,
+5,22,63,32798,
+15,38,53,32798,
+2,35,57,32798,
+3,25,62,32798,
+1,11,66,32798,
+3,38,55,32798,
+24,40,48,32798,
+21,26,58,32798,
+2,11,66,32798,
+14,21,62,32798,
+11,38,54,32798,
+16,33,56,32798,
+5,10,66,32798,
+28,36,49,32798,
+7,36,56,32798,
+32,39,44,32836,
+16,16,63,32836,
+10,30,59,32836,
+16,25,60,32836,
+0,16,65,32836,
+18,26,59,32836,
+16,39,52,32836,
+12,44,49,32836,
+14,37,54,32836,
+8,47,47,32836,
+19,20,61,32836,
+21,21,60,32836,
+11,35,56,32836,
+33,33,48,32836,
+12,33,57,32836,
+20,41,49,32836,
+1,16,65,32836,
+5,19,64,32836,
+28,43,43,32836,
+15,17,63,32836,
+33,37,45,32863,
+19,39,51,32863,
+27,27,55,32863,
+3,35,57,32863,
+32,34,48,32863,
+8,24,62,32863,
+10,28,60,32863,
+8,8,66,32863,
+20,22,60,32863,
+22,36,52,32863,
+28,42,44,32863,
+18,32,56,32863,
+8,46,48,32863,
+4,42,52,32863,
+8,18,64,32863,
+28,28,54,32863,
+2,16,65,32863,
+25,34,52,32863,
+4,25,62,32863,
+26,28,55,32863,
+7,44,50,32863,
+10,41,52,32863,
+31,32,50,32863,
+26,40,47,32863,
+4,38,55,32863,
+8,14,65,32863,
+22,40,49,32863,
+10,17,64,32863,
+7,39,54,32863,
+21,38,51,32863,
+18,21,61,32863,
+27,34,51,32863,
+3,11,66,32863,
+27,29,54,32863,
+6,27,61,32863,
+7,9,66,32863,
+38,39,39,32922,
+6,15,65,32922,
+9,34,57,32922,
+11,42,51,32922,
+6,43,51,32922,
+38,38,40,32938,
+14,14,64,32938,
+26,26,56,32938,
+16,46,46,32938,
+14,34,56,32938,
+10,32,58,32938,
+0,0,67,32938,
+30,33,50,32938,
+22,33,54,32938,
+18,42,49,32938,
+6,33,58,32938,
+31,42,42,32938,
+15,30,58,32938,
+6,22,63,32938,
+14,18,63,32938,
+15,42,50,32938,
+37,39,40,32964,
+0,1,67,32964,
+11,12,65,32964,
+4,35,57,32964,
+20,29,57,32964,
+13,15,64,32964,
+21,32,55,32964,
+31,35,48,32964,
+12,25,61,32964,
+8,45,49,32964,
+3,16,65,32964,
+23,44,45,32964,
+11,20,63,32964,
+19,23,60,32964,
+9,40,53,32964,
+15,28,59,32964,
+7,29,60,32964,
+25,27,56,32964,
+0,41,53,32964,
+16,45,47,32964,
+13,36,55,32964,
+28,41,45,32964,
+17,40,51,32964,
+29,29,53,32964,
+31,41,43,32964,
+9,21,63,32964,
+25,29,55,32964,
+1,1,67,32964,
+13,29,59,32964,
+1,41,53,32964,
+7,31,59,32964,
+21,45,45,32964,
+18,18,62,32964,
+6,10,66,32964,
+26,30,54,32964,
+12,43,50,32964,
+14,24,61,32964,
+0,2,67,32964,
+21,44,46,32964,
+20,27,58,32964,
+4,11,66,32964,
+32,38,45,32964,
+6,19,64,32964,
+5,42,52,32964,
+28,30,53,32964,
+13,31,58,32964,
+5,25,62,32964,
+25,37,50,32964,
+5,38,55,32964,
+11,23,62,32964,
+23,43,46,32964,
+17,29,58,32964,
+1,2,67,32964,
+23,34,53,32964,
+2,41,53,32964,
+13,46,47,32964,
+17,19,62,32964,
+17,22,61,32964,
+10,37,55,32964,
+37,38,41,33001,
+22,23,59,33001,
+10,13,65,33001,
+29,38,47,33001,
+0,20,64,33001,
+12,16,64,33001,
+8,36,56,33001,
+24,28,56,33001,
+36,40,40,33013,
+16,44,48,33013,
+10,26,61,33013,
+25,44,44,33013,
+20,31,56,33013,
+4,16,65,33013,
+31,40,44,33013,
+34,35,46,33013,
+29,34,50,33013,
+2,2,67,33013,
+13,22,62,33013,
+1,20,64,33013,
+13,45,48,33013,
+15,32,57,33013,
+24,39,49,33013,
+0,3,67,33013,
+36,39,41,33041,
+21,24,59,33041,
+13,27,60,33041,
+0,23,63,33041,
+7,27,61,33041,
+1,3,67,33041,
+23,37,51,33041,
+27,37,49,33041,
+9,47,47,33041,
+13,19,63,33041,
+17,27,59,33041,
+25,43,45,33041,
+3,41,53,33041,
+25,25,57,33041,
+27,31,53,33041,
+7,15,65,33041,
+1,23,63,33041,
+5,35,57,33041,
+21,43,47,33041,
+13,39,53,33041,
+7,43,51,33041,
+17,31,57,33041,
+30,36,48,33041,
+28,40,46,33041,
+8,44,50,33041,
+14,40,52,33041,
+2,20,64,33041,
+18,24,60,33041,
+16,20,62,33041,
+0,12,66,33041,
+20,40,50,33041,
+0,30,60,33041,
+33,36,46,33041,
+17,36,54,33041,
+1,30,60,33041,
+9,46,48,33041,
+9,24,62,33041,
+15,26,60,33041,
+1,12,66,33041,
+24,26,57,33041,
+26,39,48,33041,
+24,30,55,33041,
+8,39,54,33041,
+9,18,64,33041,
+8,9,66,33041,
+2,23,63,33041,
+25,31,54,33041,
+18,37,53,33041,
+11,30,59,33041,
+19,45,46,33041,
+9,14,65,33041,
+7,22,63,33041,
+5,11,66,33041,
+7,33,58,33041,
+37,37,42,33058,
+19,35,54,33058,
+2,3,67,33058,
+23,42,47,33058,
+26,35,51,33058,
+36,38,42,33081,
+6,42,52,33081,
+12,38,54,33081,
+2,12,66,33081,
+30,30,52,33081,
+2,30,60,33081,
+6,38,55,33081,
+18,34,55,33081,
+25,42,46,33081,
+10,34,57,33081,
+0,37,56,33081,
+20,36,53,33081,
+3,20,64,33081,
+0,32,59,33081,
+18,41,50,33081,
+24,35,52,33081,
+11,28,60,33081,
+7,10,66,33081,
+0,4,67,33081,
+22,39,50,33081,
+0,28,61,33081,
+6,25,62,33081,
+8,29,60,33081,
+12,35,56,33081,
+16,23,61,33081,
+20,25,59,33081,
+1,28,61,33081,
+19,44,47,33081,
+1,4,67,33081,
+16,35,55,33081,
+16,43,49,33081,
+23,29,56,33081,
+13,44,49,33081,
+8,31,59,33081,
+1,37,56,33081,
+5,16,65,33081,
+35,40,41,33112,
+29,31,52,33112,
+11,41,52,33112,
+11,17,64,33112,
+1,32,59,33112,
+7,19,64,33112,
+4,41,53,33112,
+3,23,63,33112,
+15,41,51,33112,
+23,27,57,33112,
+13,33,57,33112,
+31,39,45,33112,
+3,3,67,33112,
+9,45,49,33112,
+2,32,59,33112,
+11,32,58,33112,
+19,38,52,33112,
+28,35,50,33112,
+2,28,61,33112,
+2,4,67,33112,
+12,42,51,33112,
+16,38,53,33112,
+2,37,56,33112,
+3,30,60,33112,
+32,37,46,33112,
+10,40,53,33112,
+19,28,58,33112,
+21,42,48,33112,
+3,12,66,33112,
+26,32,53,33112,
+15,37,54,33112,
+35,39,42,33148,
+19,30,57,33148,
+10,21,63,33148,
+15,21,62,33148,
+6,35,57,33148,
+28,32,52,33148,
+4,20,64,33148,
+21,34,54,33148,
+6,11,66,33148,
+9,36,56,33148,
+0,47,48,33148,
+12,12,65,33148,
+12,20,63,33148,
+30,42,43,33148,
+17,39,52,33148,
+0,5,67,33148,
+8,15,65,33148,
+28,39,47,33148,
+3,28,61,33148,
+21,37,52,33148,
+1,47,48,33148,
+17,33,56,33148,
+36,37,43,33185,
+32,33,49,33185,
+19,43,48,33185,
+3,32,59,33185,
+3,4,67,33185,
+17,25,60,33185,
+16,17,63,33185,
+0,17,65,33185,
+8,27,61,33185,
+8,43,51,33185,
+20,33,55,33185,
+27,43,44,33185,
+3,37,56,33185,
+23,41,48,33185,
+4,23,63,33185,
+29,37,48,33185,
+5,41,53,33185,
+1,17,65,33185,
+23,31,55,33185,
+11,37,55,33185,
+1,5,67,33185,
+11,13,65,33185,
+13,25,61,33185,
+25,41,47,33185,
+4,12,66,33185,
+24,24,58,33185,
+0,40,54,33185,
+4,30,60,33185,
+24,32,54,33185,
+12,23,62,33185,
+30,41,44,33185,
+2,47,48,33185,
+22,28,57,33185,
+0,46,49,33185,
+14,15,64,33185,
+1,40,54,33185,
+9,44,50,33185,
+6,16,65,33185,
+8,33,58,33185,
+15,34,56,33185,
+8,22,63,33185,
+14,36,55,33185,
+7,42,52,33185,
+2,17,65,33185,
+35,38,43,33220,
+31,34,49,33220,
+9,9,66,33220,
+10,47,47,33220,
+14,29,59,33220,
+22,35,53,33220,
+7,38,55,33220,
+11,26,61,33220,
+2,5,67,33220,
+15,18,63,33220,
+23,25,58,33220,
+9,39,54,33220,
+1,46,49,33220,
+19,26,59,33220,
+13,43,50,33220,
+27,42,45,33220,
+34,41,41,33220,
+7,25,62,33220,
+10,18,64,33220,
+0,34,58,33220,
+2,40,54,33220,
+8,10,66,33220,
+34,40,42,33237,
+10,24,62,33237,
+16,30,58,33237,
+22,30,56,33237,
+10,46,48,33237,
+0,26,62,33237,
+16,42,50,33237,
+24,38,50,33237,
+10,14,65,33237,
+1,34,58,33237,
+2,46,49,33237,
+4,4,67,33237,
+5,20,64,33237,
+34,34,47,33237,
+19,32,56,33237,
+31,38,46,33237,
+4,32,59,33237,
+14,46,47,33237,
+13,16,64,33237,
+14,31,58,33237,
+17,46,46,33237,
+20,20,61,33237,
+4,28,61,33237,
+16,28,59,33237,
+4,37,56,33237,
+26,38,49,33237,
+8,19,64,33237,
+1,26,62,33237,
+25,36,51,33237,
+20,39,51,33237,
+15,24,61,33237,
+3,47,48,33237,
+9,29,60,33237,
+27,33,52,33237,
+19,21,61,33237,
+17,45,47,33237,
+7,35,57,33237,
+3,17,65,33237,
+21,41,49,33237,
+33,35,47,33237,
+25,33,53,33237,
+9,31,59,33237,
+3,5,67,33237,
+5,23,63,33237,
+31,31,51,33237,
+22,26,58,33237,
+2,34,58,33237,
+14,22,62,33237,
+2,26,62,33237,
+18,40,51,33237,
+3,40,54,33237,
+0,6,67,33237,
+0,45,50,33237,
+30,32,51,33237,
+12,30,59,33237,
+27,36,50,33237,
+21,22,60,33237,
+14,45,48,33237,
+30,40,45,33252,
+14,27,60,33252,
+0,13,66,33252,
+5,12,66,33252,
+5,30,60,33252,
+30,35,49,33252,
+34,39,43,33302,
+3,46,49,33302,
+1,6,67,33302,
+19,42,49,33302,
+7,11,66,33302,
+14,39,53,33302,
+27,41,46,33302,
+11,34,57,33302,
+6,41,53,33302,
+1,45,50,33302,
+14,19,63,33302,
+10,45,49,33302,
+1,13,66,33302,
+36,36,44,33319,
+12,28,60,33319,
+17,44,48,33319,
+20,23,60,33319,
+32,36,47,33319,
+12,41,52,33319,
+12,17,64,33319,
+4,47,48,33319,
+18,22,61,33319,
+18,19,62,33319,
+2,6,67,33319,
+25,40,48,33319,
+2,45,50,33319,
+23,36,52,33319,
+2,13,66,33319,
+16,32,57,33319,
+18,29,58,33319,
+15,40,52,33319,
+13,38,54,33319,
+3,34,58,33319,
+22,38,51,33319,
+3,26,62,33319,
+5,32,59,33319,
+35,37,44,33348,
+23,40,49,33348,
+13,35,56,33348,
+4,5,67,33348,
+4,17,65,33348,
+5,28,61,33348,
+11,40,53,33348,
+5,37,56,33348,
+7,16,65,33348,
+9,15,65,33348,
+9,43,51,33348,
+21,29,57,33348,
+11,21,63,33348,
+9,27,61,33348,
+29,33,51,33348,
+10,36,56,33348,
+6,20,64,33348,
+12,32,58,33348,
+8,42,52,33348,
+16,26,60,33348,
+28,38,48,33348,
+4,40,54,33348,
+17,20,62,33348,
+22,32,55,33348,
+14,44,49,33348,
+8,38,55,33348,
+4,46,49,33348,
+8,25,62,33348,
+21,27,58,33348,
+18,27,59,33348,
+33,41,42,33379,
+13,42,51,33379,
+9,33,58,33379,
+18,31,57,33379,
+14,33,57,33379,
+3,13,66,33379,
+23,33,54,33379,
+6,23,63,33379,
+9,22,63,33379,
+22,45,45,33379,
+3,45,50,33379,
+3,6,67,33379,
+4,34,58,33379,
+6,30,60,33379,
+26,34,52,33379,
+10,44,50,33379,
+6,12,66,33379,
+22,44,46,33379,
+4,26,62,33379,
+34,38,44,33398,
+18,36,54,33398,
+30,39,46,33398,
+0,44,51,33398,
+10,39,54,33398,
+24,44,45,33398,
+0,21,64,33398,
+9,10,66,33398,
+19,24,60,33398,
+9,19,64,33398,
+21,31,56,33398,
+13,20,63,33398,
+16,41,51,33398,
+1,21,64,33398,
+5,47,48,33398,
+29,36,49,33398,
+33,40,43,33421,
+12,13,65,33421,
+27,28,55,33421,
+0,7,67,33421,
+27,40,47,33421,
+12,37,55,33421,
+8,35,57,33421,
+1,44,51,33421,
+17,35,55,33421,
+31,37,47,33421,
+29,43,43,33421,
+19,37,53,33421,
+17,43,49,33421,
+7,41,53,33421,
+1,7,67,33421,
+11,47,47,33421,
+17,23,61,33421,
+5,5,67,33421,
+5,17,65,33421,
+23,23,59,33421,
+16,21,62,33421,
+20,35,54,33421,
+2,21,64,33421,
+2,44,51,33421,
+21,40,50,33421,
+11,46,48,33421,
+11,24,62,33421,
+29,42,44,33421,
+6,37,56,33421,
+24,43,46,33421,
+10,29,60,33421,
+8,11,66,33421,
+4,45,50,33421,
+24,34,53,33421,
+4,6,67,33421,
+22,24,59,33421,
+11,18,64,33421,
+26,27,56,33421,
+12,26,61,33421,
+6,32,59,33421,
+28,34,51,33421,
+4,13,66,33421,
+5,40,54,33421,
+28,29,54,33421,
+6,28,61,33421,
+20,45,46,33421,
+16,37,54,33421,
+11,14,65,33421,
+17,38,53,33421,
+10,31,59,33421,
+5,46,49,33421,
+19,41,50,33421,
+2,7,67,33421,
+22,43,47,33421,
+13,23,62,33421,
+26,29,55,33421,
+14,25,61,33421,
+19,34,55,33421,
+5,34,58,33421,
+0,24,63,33421,
+20,44,47,33421,
+5,26,62,33421,
+27,30,54,33421,
+26,37,50,33421,
+8,16,65,33421,
+7,20,64,33421,
+25,28,56,33421,
+0,36,57,33421,
+14,43,50,33421,
+33,39,44,33506,
+24,37,51,33506,
+1,24,63,33506,
+21,36,53,33506,
+0,39,55,33506,
+15,36,55,33506,
+15,15,64,33506,
+35,36,45,33506,
+3,44,51,33506,
+1,36,57,33506,
+3,21,64,33506,
+11,45,49,33506,
+7,23,63,33506,
+1,39,55,33506,
+21,25,59,33506,
+3,7,67,33506,
+25,39,49,33506,
+17,17,63,33506,
+15,29,59,33506,
+29,41,45,33506,
+32,32,50,33506,
+20,28,58,33506,
+14,16,64,33506,
+26,44,44,33506,
+16,34,56,33506,
+20,38,52,33506,
+33,34,48,33506,
+7,12,66,33506,
+18,33,56,33506,
+7,30,60,33506,
+16,18,63,33506,
+18,25,60,33506,
+9,42,52,33506,
+2,24,63,33506,
+12,34,57,33506,
+6,47,48,33506,
+18,39,52,33506,
+24,42,47,33506,
+0,18,65,33506,
+2,36,57,33506,
+20,30,57,33506,
+23,39,50,33506,
+1,18,65,33506,
+9,25,62,33506,
+2,39,55,33506,
+5,45,50,33506,
+26,43,45,33506,
+25,26,57,33506,
+9,38,55,33506,
+6,17,65,33506,
+10,15,65,33506,
+34,37,45,33539,
+15,31,58,33539,
+10,43,51,33539,
+5,13,66,33539,
+5,6,67,33539,
+13,30,59,33539,
+10,27,61,33539,
+25,30,55,33539,
+15,46,47,33539,
+29,30,53,33539,
+31,33,50,33539,
+32,42,42,33553,
+0,14,66,33553,
+22,42,48,33553,
+6,40,54,33553,
+30,38,47,33553,
+4,44,51,33553,
+2,18,65,33553,
+32,35,48,33553,
+10,22,63,33553,
+0,43,52,33553,
+13,28,60,33553,
+20,43,48,33553,
+15,22,62,33553,
+17,42,50,33553,
+26,31,54,33553,
+12,40,53,33553,
+24,29,56,33553,
+0,8,67,33553,
+6,46,49,33553,
+16,24,61,33553,
+11,36,56,33553,
+4,21,64,33553,
+10,33,58,33553,
+17,30,58,33553,
+1,14,66,33553,
+7,28,61,33553,
+13,41,52,33553,
+7,32,59,33553,
+25,35,52,33553,
+3,36,57,33553,
+13,17,64,33553,
+24,27,57,33553,
+32,41,43,33581,
+12,21,63,33581,
+3,24,63,33581,
+8,41,53,33581,
+15,45,48,33581,
+28,37,49,33581,
+1,8,67,33581,
+15,27,60,33581,
+27,39,48,33581,
+4,7,67,33581,
+1,43,52,33581,
+7,37,56,33581,
+17,28,59,33581,
+28,31,53,33581,
+15,19,63,33581,
+3,39,55,33581,
+9,35,57,33581,
+15,39,53,33581,
+27,35,51,33581,
+21,33,55,33581,
+22,34,54,33581,
+30,34,50,33581,
+10,10,66,33581,
+14,38,54,33581,
+18,46,46,33581,
+6,26,62,33581,
+26,42,46,33581,
+6,34,58,33581,
+2,14,66,33581,
+11,44,50,33581,
+14,35,56,33581,
+22,37,52,33581,
+10,19,64,33581,
+2,8,67,33581,
+29,40,46,33581,
+13,32,58,33581,
+2,43,52,33581,
+20,26,59,33581,
+3,18,65,33581,
+11,39,54,33581,
+9,11,66,33581,
+33,38,45,33621,
+18,45,47,33621,
+20,32,56,33621,
+16,40,52,33621,
+32,40,44,33635,
+8,20,64,33635,
+4,24,63,33635,
+4,36,57,33635,
+3,14,66,33635,
+31,36,48,33635,
+14,42,51,33635,
+6,13,66,33635,
+6,45,50,33635,
+24,41,48,33635,
+0,31,60,33635,
+6,6,67,33635,
+4,39,55,33635,
+15,44,49,33635,
+27,32,53,33635,
+23,28,57,33635,
+5,21,64,33635,
+3,8,67,33635,
+7,47,48,33635,
+19,40,51,33635,
+17,32,57,33635,
+20,21,61,33635,
+3,43,52,33635,
+24,31,55,33635,
+5,44,51,33635,
+9,16,65,33635,
+8,23,63,33635,
+0,29,61,33635,
+12,47,47,33635,
+11,29,60,33635,
+1,31,60,33635,
+13,13,65,33635,
+15,33,57,33635,
+23,35,53,33635,
+13,37,55,33635,
+11,31,59,33635,
+39,39,39,33682,
+7,17,65,33682,
+5,7,67,33682,
+21,39,51,33682,
+1,29,61,33682,
+8,30,60,33682,
+12,46,48,33682,
+18,44,48,33682,
+12,18,64,33682,
+8,12,66,33682,
+12,24,62,33682,
+2,31,60,33682,
+20,42,49,33682,
+4,18,65,33682,
+30,31,52,33682,
+25,32,54,33682,
+24,25,58,33682,
+23,30,56,33682,
+12,14,65,33682,
+38,39,40,33715,
+17,26,60,33715,
+14,20,63,33715,
+7,40,54,33715,
+7,46,49,33715,
+29,35,50,33715,
+22,41,49,33715,
+26,41,47,33715,
+19,22,61,33715,
+35,35,46,33715,
+19,19,62,33715,
+2,29,61,33715,
+13,26,61,33715,
+19,29,58,33715,
+10,42,52,33715,
+22,22,60,33715,
+34,36,46,33715,
+18,20,62,33715,
+4,14,66,33715,
+28,43,44,33715,
+8,28,61,33715,
+10,38,55,33715,
+4,8,67,33715,
+7,34,58,33715,
+38,38,41,33759,
+8,37,56,33759,
+8,32,59,33759,
+37,40,40,33759,
+25,38,50,33759,
+14,23,62,33759,
+7,26,62,33759,
+4,43,52,33759,
+10,25,62,33759,
+23,26,58,33759,
+29,32,52,33759,
+3,31,60,33759,
+0,33,59,33759,
+32,39,45,33759,
+21,23,60,33759,
+5,36,57,33759,
+12,45,49,33759,
+5,24,63,33759,
+0,9,67,33759,
+19,31,57,33759,
+1,33,59,33759,
+3,29,61,33759,
+9,41,53,33759,
+29,39,47,33759,
+5,39,55,33759,
+17,41,51,33759,
+11,15,65,33759,
+1,9,67,33759,
+11,27,61,33759,
+15,25,61,33759,
+37,39,41,33786,
+19,27,59,33786,
+11,43,51,33786,
+0,42,53,33786,
+26,36,51,33786,
+6,21,64,33786,
+30,37,48,33786,
+28,42,45,33786,
+19,36,54,33786,
+6,44,51,33786,
+0,27,62,33786,
+1,27,62,33786,
+27,38,49,33786,
+26,33,53,33786,
+10,35,57,33786,
+2,9,67,33786,
+11,33,58,33786,
+23,38,51,33786,
+11,22,63,33786,
+17,37,54,33786,
+2,33,59,33786,
+5,18,65,33786,
+13,34,57,33786,
+1,42,53,33786,
+15,43,50,33786,
+6,7,67,33786,
+33,37,46,33786,
+7,13,66,33786,
+18,43,49,33786,
+18,35,55,33786,
+18,23,61,33786,
+7,45,50,33786,
+22,29,57,33786,
+31,42,43,33786,
+17,21,62,33786,
+20,24,60,33786,
+12,36,56,33786,
+24,36,52,33786,
+15,16,64,33786,
+5,14,66,33786,
+16,36,55,33786,
+36,40,41,33836,
+18,38,53,33836,
+37,38,42,33836,
+2,42,53,33836,
+8,47,48,33836,
+22,27,58,33836,
+10,11,66,33836,
+28,33,52,33836,
+14,30,59,33836,
+24,40,49,33836,
+4,31,60,33836,
+9,20,64,33836,
+2,27,62,33836,
+23,32,55,33836,
+8,17,65,33836,
+5,43,52,33836,
+16,29,59,33836,
+31,41,44,33836,
+13,40,53,33836,
+20,37,53,33836,
+11,19,64,33836,
+4,29,61,33836,
+5,8,67,33836,
+33,33,49,33836,
+3,33,59,33836,
+3,9,67,33836,
+23,45,45,33836,
+13,21,63,33836,
+9,23,63,33836,
+12,44,50,33836,
+14,28,60,33836,
+26,40,48,33836,
+8,40,54,33836,
+0,22,64,33836,
+28,36,50,33836,
+0,38,56,33836,
+8,46,49,33836,
+20,34,55,33836,
+16,46,47,33836,
+6,36,57,33836,
+1,38,56,33836,
+23,44,46,33836,
+1,22,64,33836,
+24,33,54,33836,
+0,15,66,33836,
+9,12,66,33836,
+28,41,46,33836,
+12,39,54,33836,
+14,17,64,33836,
+6,24,63,33836,
+20,41,50,33836,
+22,31,56,33836,
+36,39,42,33878,
+32,34,49,33878,
+17,34,56,33878,
+10,16,65,33878,
+14,41,52,33878,
+16,31,58,33878,
+9,30,60,33878,
+17,18,63,33878,
+21,45,46,33878,
+3,42,53,33878,
+6,39,55,33878,
+3,27,62,33878,
+1,15,66,33878,
+21,35,54,33878,
+16,22,62,33878,
+32,38,46,33878,
+8,34,58,33878,
+14,32,58,33878,
+2,38,56,33878,
+22,40,50,33878,
+8,26,62,33878,
+2,22,64,33878,
+16,27,60,33878,
+16,45,48,33878,
+12,29,60,33878,
+6,18,65,33878,
+15,38,54,33878,
+2,15,66,33878,
+17,24,61,33878,
+31,40,45,33886,
+23,24,59,33886,
+19,33,56,33886,
+7,44,51,33886,
+15,35,56,33886,
+25,44,45,33886,
+9,28,61,33886,
+4,33,59,33886,
+9,32,59,33886,
+7,21,64,33886,
+19,25,60,33886,
+5,31,60,33886,
+16,19,63,33886,
+9,37,56,33886,
+4,9,67,33886,
+12,31,59,33886,
+21,44,47,33886,
+16,39,53,33886,
+19,39,52,33886,
+0,19,65,33886,
+31,32,51,33886,
+7,7,67,33886,
+37,37,43,33948,
+5,29,61,33948,
+31,35,49,33948,
+13,47,47,33948,
+23,43,47,33948,
+35,41,41,33948,
+1,19,65,33948,
+18,42,50,33948,
+18,30,58,33948,
+6,14,66,33948,
+21,28,58,33948,
+18,28,59,33948,
+6,8,67,33948,
+21,38,52,33948,
+6,43,52,33948,
+0,10,67,33948,
+22,36,53,33948,
+11,42,52,33948,
+3,38,56,33948,
+4,42,53,33948,
+36,38,43,33970,
+8,13,66,33970,
+35,40,42,33970,
+27,34,52,33970,
+8,45,50,33970,
+4,27,62,33970,
+29,38,48,33970,
+0,35,58,33970,
+13,24,62,33970,
+3,22,64,33970,
+13,46,48,33970,
+13,18,64,33970,
+13,14,65,33970,
+10,41,53,33970,
+11,38,55,33970,
+1,10,67,33970,
+21,30,57,33970,
+25,43,46,33970,
+34,35,47,33970,
+22,25,59,33970,
+15,42,51,33970,
+30,33,51,33970,
+3,15,66,33970,
+25,34,53,33970,
+1,35,58,33970,
+14,37,55,33970,
+2,19,65,33970,
+11,25,62,33970,
+2,35,58,33970,
+28,28,55,33970,
+16,44,49,33970,
+28,40,47,33970,
+14,26,61,33970,
+2,10,67,33970,
+19,46,46,33970,
+17,40,52,33970,
+15,20,63,33970,
+7,36,57,33970,
+12,15,65,33970,
+16,33,57,33970,
+27,27,56,33970,
+0,25,63,33970,
+33,36,47,33983,
+7,24,63,33983,
+12,27,61,33983,
+21,43,48,33983,
+9,47,48,33983,
+12,43,51,33983,
+3,19,65,33983,
+27,29,55,33983,
+5,9,67,33983,
+1,25,63,33983,
+7,39,55,33983,
+13,45,49,33983,
+9,17,65,33983,
+35,39,43,34029,
+25,37,51,34029,
+19,45,47,34029,
+11,35,57,34029,
+5,33,59,34029,
+4,38,56,34029,
+10,20,64,34029,
+4,22,64,34029,
+26,28,56,34029,
+18,32,57,34029,
+12,22,63,34029,
+12,33,58,34029,
+24,39,50,34029,
+6,31,60,34029,
+30,36,49,34029,
+0,41,54,34029,
+9,40,54,34029,
+4,15,66,34029,
+23,42,48,34029,
+31,39,46,34029,
+10,23,63,34029,
+30,43,43,34029,
+9,46,49,34029,
+1,41,54,34029,
+5,27,62,34029,
+11,11,66,34029,
+29,34,51,34029,
+25,42,47,34029,
+21,26,59,34029,
+3,10,67,34029,
+29,29,54,34029,
+7,18,65,34029,
+15,23,62,34029,
+3,35,58,34029,
+27,37,50,34029,
+6,29,61,34029,
+26,39,49,34029,
+22,33,55,34029,
+2,25,63,34029,
+5,42,53,34029,
+30,42,44,34037,
+28,30,54,34037,
+10,30,60,34037,
+10,12,66,34037,
+18,26,60,34037,
+26,26,57,34037,
+14,34,57,34037,
+27,44,44,34037,
+34,41,42,34092,
+9,34,58,34092,
+21,32,56,34092,
+12,19,64,34092,
+19,44,48,34092,
+23,34,54,34092,
+36,37,44,34092,
+8,44,51,34092,
+26,30,55,34092,
+9,26,62,34092,
+2,41,54,34092,
+13,36,56,34092,
+8,21,64,34092,
+7,14,66,34092,
+20,40,51,34092,
+7,8,67,34092,
+25,29,56,34092,
+32,37,47,34092,
+7,43,52,34092,
+16,25,61,34092,
+23,37,52,34092,
+4,19,65,34092,
+11,16,65,34092,
+3,25,63,34092,
+21,21,61,34092,
+25,27,57,34092,
+27,43,45,34092,
+20,22,61,34092,
+4,35,58,34092,
+35,38,44,34125,
+5,38,56,34125,
+16,43,50,34125,
+4,10,67,34125,
+5,22,64,34125,
+10,28,61,34125,
+14,40,53,34125,
+10,37,56,34125,
+19,20,62,34125,
+34,40,43,34125,
+10,32,59,34125,
+26,35,52,34125,
+13,44,50,34125,
+20,29,58,34125,
+27,31,54,34125,
+14,21,63,34125,
+9,45,50,34125,
+3,41,54,34125,
+15,30,59,34125,
+18,41,51,34125,
+5,15,66,34125,
+6,33,59,34125,
+9,13,66,34125,
+13,39,54,34125,
+30,41,45,34125,
+21,42,49,34125,
+22,39,51,34125,
+6,9,67,34125,
+16,16,64,34125,
+0,48,48,34125,
+30,30,53,34125,
+15,28,60,34125,
+8,36,57,34125,
+18,21,62,34125,
+28,39,48,34125,
+6,27,62,34125,
+8,24,63,34125,
+18,37,54,34125,
+1,48,48,34125,
+6,42,53,34125,
+27,42,46,34125,
+24,28,57,34125,
+7,31,60,34125,
+20,31,57,34125,
+0,11,67,34125,
+24,35,53,34125,
+4,25,63,34125,
+8,39,55,34125,
+15,17,64,34125,
+28,35,51,34125,
+17,36,55,34125,
+25,41,48,34125,
+0,47,49,34125,
+13,29,60,34125,
+15,41,52,34125,
+20,27,59,34125,
+1,11,67,34125,
+19,35,55,34125,
+11,41,53,34125,
+17,29,59,34125,
+19,43,49,34125,
+25,31,55,34125,
+7,29,61,34125,
+1,47,49,34125,
+5,19,65,34125,
+23,41,49,34125,
+19,23,61,34125,
+29,37,49,34125,
+29,31,53,34125,
+13,31,59,34125,
+12,42,52,34125,
+24,30,56,34125,
+0,16,66,34125,
+20,36,54,34125,
+2,48,48,34125,
+8,18,65,34125,
+12,38,55,34125,
+32,33,50,34125,
+22,23,60,34125,
+12,25,62,34125,
+10,47,48,34125,
+1,16,66,34125,
+4,41,54,34125,
+34,39,44,34183,
+15,32,58,34183,
+2,11,67,34183,
+10,17,65,34183,
+19,38,53,34183,
+17,31,58,34183,
+25,25,58,34183,
+31,38,47,34183,
+17,46,47,34183,
+2,47,49,34183,
+5,35,58,34183,
+5,10,67,34183,
+14,47,47,34183,
+26,32,54,34183,
+18,34,56,34183,
+14,18,64,34183,
+8,14,66,34183,
+34,34,48,34183,
+2,16,66,34183,
+30,40,46,34183,
+14,24,62,34183,
+6,22,64,34183,
+6,38,56,34183,
+14,46,48,34183,
+24,26,58,34183,
+16,38,54,34183,
+10,40,54,34183,
+0,46,50,34183,
+31,34,50,34183,
+36,36,45,34228,
+18,18,63,34228,
+1,46,50,34228,
+11,20,64,34228,
+21,24,60,34228,
+8,8,67,34228,
+14,14,65,34228,
+33,42,42,34228,
+16,35,56,34228,
+10,46,49,34228,
+28,32,53,34228,
+17,22,62,34228,
+3,48,48,34228,
+8,43,52,34228,
+6,15,66,34228,
+9,21,64,34228,
+9,44,51,34228,
+0,37,57,34228,
+17,45,48,34228,
+12,35,57,34228,
+33,35,48,34228,
+17,27,60,34228,
+15,37,55,34228,
+11,23,63,34228,
+33,41,43,34254,
+35,37,45,34254,
+21,37,53,34254,
+5,25,63,34254,
+17,39,53,34254,
+13,15,65,34254,
+7,33,59,34254,
+23,29,57,34254,
+1,37,57,34254,
+3,47,49,34254,
+27,41,47,34254,
+17,19,63,34254,
+7,9,67,34254,
+13,27,61,34254,
+3,11,67,34254,
+13,43,51,34254,
+10,34,58,34254,
+2,46,50,34254,
+26,38,50,34254,
+10,26,62,34254,
+16,42,51,34254,
+0,30,61,34254,
+3,16,66,34254,
+11,30,60,34254,
+11,12,66,34254,
+18,24,61,34254,
+24,38,51,34254,
+21,41,50,34254,
+21,34,55,34254,
+1,30,61,34254,
+23,27,58,34254,
+5,41,54,34254,
+13,22,63,34254,
+15,26,61,34254,
+6,19,65,34254,
+14,45,49,34254,
+7,42,53,34254,
+2,37,57,34254,
+13,33,58,34254,
+7,27,62,34254,
+32,36,48,34260,
+4,48,48,34260,
+0,32,60,34260,
+0,0,68,34260,
+10,13,66,34260,
+24,32,55,34260,
+34,38,45,34308,
+19,30,58,34308,
+0,23,64,34308,
+8,31,60,34308,
+6,35,58,34308,
+2,30,61,34308,
+25,36,52,34308,
+30,35,50,34308,
+19,42,50,34308,
+16,20,63,34308,
+6,10,67,34308,
+0,40,55,34308,
+33,40,44,34308,
+20,39,52,34308,
+3,46,50,34308,
+0,20,65,34308,
+20,33,56,34308,
+10,45,50,34308,
+12,16,65,34308,
+22,45,46,34308,
+22,35,54,34308,
+1,32,60,34308,
+20,25,60,34308,
+0,1,68,34308,
+13,19,64,34308,
+9,36,57,34308,
+23,31,56,34308,
+1,1,68,34308,
+11,37,56,34308,
+1,40,55,34308,
+9,24,63,34308,
+11,32,59,34308,
+29,43,44,34308,
+31,31,52,34308,
+19,28,59,34308,
+4,11,67,34308,
+1,20,65,34308,
+11,28,61,34308,
+24,45,45,34308,
+1,23,64,34308,
+0,45,51,34308,
+25,40,49,34308,
+27,36,51,34308,
+8,29,61,34308,
+17,44,49,34308,
+4,47,49,34308,
+9,39,55,34308,
+27,33,53,34308,
+1,45,51,34308,
+17,33,57,34308,
+3,37,57,34308,
+30,32,52,34308,
+0,2,68,34308,
+2,32,60,34308,
+18,40,52,34308,
+0,28,62,34308,
+14,36,56,34308,
+4,16,66,34308,
+24,44,46,34308,
+23,40,50,34308,
+2,40,55,34308,
+7,22,64,34308,
+7,38,56,34308,
+22,44,47,34308,
+16,23,62,34308,
+28,38,49,34308,
+2,23,64,34308,
+2,20,65,34308,
+1,2,68,34308,
+1,28,62,34308,
+3,30,61,34308,
+6,25,63,34308,
+15,34,57,34308,
+9,18,65,34308,
+29,42,45,34328,
+30,39,47,34328,
+25,33,54,34328,
+7,15,66,34328,
+2,45,51,34328,
+14,44,50,34328,
+22,28,58,34328,
+20,46,46,34328,
+2,28,62,34328,
+4,46,50,34328,
+2,2,68,34328,
+22,38,52,34328,
+5,48,48,34328,
+24,24,59,34328,
+6,41,54,34328,
+14,39,54,34328,
+27,40,48,34328,
+0,3,68,34328,
+3,32,60,34328,
+9,14,66,34328,
+0,12,67,34328,
+22,30,57,34328,
+1,3,68,34328,
+23,36,53,34328,
+29,33,52,34328,
+24,43,47,34328,
+31,37,48,34367,
+8,9,67,34367,
+12,41,53,34367,
+3,20,65,34367,
+11,47,48,34367,
+3,40,55,34367,
+9,43,52,34367,
+15,40,53,34367,
+1,12,67,34367,
+3,23,64,34367,
+4,37,57,34367,
+8,33,59,34367,
+20,45,47,34367,
+19,32,57,34367,
+11,17,65,34367,
+23,25,59,34367,
+5,47,49,34367,
+17,25,61,34367,
+33,39,45,34410,
+5,11,67,34410,
+15,21,63,34410,
+7,19,65,34410,
+3,45,51,34410,
+0,34,59,34410,
+13,42,52,34410,
+32,42,43,34426,
+3,28,62,34426,
+19,26,60,34426,
+8,42,53,34426,
+8,27,62,34426,
+2,3,68,34426,
+5,16,66,34426,
+10,21,64,34426,
+11,40,54,34426,
+14,29,60,34426,
+4,30,61,34426,
+35,36,46,34426,
+26,44,45,34426,
+29,36,50,34426,
+16,30,59,34426,
+10,44,51,34426,
+2,12,67,34426,
+22,43,48,34426,
+1,34,59,34426,
+17,43,50,34426,
+13,25,62,34426,
+14,31,59,34426,
+7,35,58,34426,
+11,46,49,34426,
+7,10,67,34426,
+29,41,46,34426,
+13,38,55,34426,
+12,20,64,34426,
+4,32,60,34426,
+0,4,68,34426,
+0,44,52,34426,
+20,44,48,34426,
+16,28,60,34426,
+26,34,53,34426,
+16,17,64,34426,
+2,34,59,34426,
+16,41,52,34426,
+4,40,55,34426,
+1,4,68,34426,
+5,46,50,34426,
+32,41,44,34460,
+4,23,64,34460,
+34,37,46,34460,
+11,34,58,34460,
+4,20,65,34460,
+1,44,52,34460,
+22,26,59,34460,
+26,43,46,34460,
+11,26,62,34460,
+9,31,60,34460,
+3,3,68,34460,
+4,45,51,34460,
+12,23,63,34460,
+3,12,67,34460,
+39,39,40,34527,
+21,40,51,34527,
+19,41,51,34527,
+5,37,57,34527,
+7,25,63,34527,
+15,47,47,34527,
+9,29,61,34527,
+23,33,55,34527,
+13,35,57,34527,
+16,32,58,34527,
+8,38,56,34527,
+2,44,52,34527,
+20,20,62,34527,
+8,22,64,34527,
+12,30,60,34527,
+6,48,48,34527,
+2,4,68,34527,
+12,12,66,34527,
+28,34,52,34527,
+4,28,62,34527,
+24,42,48,34527,
+38,40,40,34531,
+22,32,56,34531,
+8,15,66,34531,
+15,46,48,34531,
+10,36,57,34531,
+10,24,63,34531,
+18,36,55,34531,
+15,18,64,34531,
+15,24,62,34531,
+0,17,66,34531,
+0,26,63,34531,
+21,29,58,34531,
+19,37,54,34531,
+14,43,51,34531,
+21,22,61,34531,
+14,15,65,34531,
+14,27,61,34531,
+6,11,67,34531,
+6,47,49,34531,
+10,39,55,34531,
+7,41,54,34531,
+19,21,62,34531,
+11,13,66,34531,
+33,34,49,34531,
+3,34,59,34531,
+1,26,63,34531,
+5,30,61,34531,
+26,37,51,34531,
+1,17,66,34531,
+11,45,50,34531,
+38,39,41,34569,
+18,29,59,34569,
+25,39,50,34569,
+30,38,48,34569,
+24,34,54,34569,
+6,16,66,34569,
+2,26,63,34569,
+3,4,68,34569,
+10,18,65,34569,
+2,17,66,34569,
+32,32,51,34569,
+0,5,68,34569,
+24,37,52,34569,
+14,33,58,34569,
+17,38,54,34569,
+12,28,61,34569,
+3,44,52,34569,
+33,38,46,34569,
+27,28,56,34569,
+22,42,49,34569,
+14,22,63,34569,
+12,32,59,34569,
+26,42,47,34569,
+18,46,47,34569,
+12,37,56,34569,
+4,12,67,34569,
+5,32,60,34569,
+18,31,58,34569,
+32,40,45,34569,
+16,37,55,34569,
+5,40,55,34569,
+37,40,41,34606,
+32,35,49,34606,
+17,35,56,34606,
+29,40,47,34606,
+20,35,55,34606,
+20,43,49,34606,
+5,23,64,34606,
+20,23,61,34606,
+28,29,55,34606,
+5,20,65,34606,
+13,16,65,34606,
+1,5,68,34606,
+8,19,65,34606,
+21,27,59,34606,
+21,31,57,34606,
+15,45,49,34606,
+27,39,49,34606,
+9,9,67,34606,
+9,33,59,34606,
+23,39,51,34606,
+5,45,51,34606,
+31,33,51,34606,
+10,14,66,34606,
+18,22,62,34606,
+38,38,42,34612,
+6,46,50,34612,
+10,43,52,34612,
+8,10,67,34612,
+4,34,59,34612,
+21,36,54,34612,
+2,5,68,34612,
+28,37,50,34612,
+18,27,60,34612,
+5,28,62,34612,
+16,26,61,34612,
+8,35,58,34612,
+26,29,56,34612,
+19,34,56,34612,
+20,38,53,34612,
+18,45,48,34612,
+14,19,64,34612,
+18,19,63,34612,
+3,26,63,34612,
+17,42,51,34612,
+9,27,62,34612,
+9,42,53,34612,
+18,39,53,34612,
+26,27,57,34612,
+3,17,66,34612,
+37,39,42,34636,
+6,37,57,34636,
+27,30,55,34636,
+28,44,44,34636,
+4,4,68,34636,
+4,44,52,34636,
+7,48,48,34636,
+29,30,54,34636,
+15,36,56,34636,
+6,30,61,34636,
+0,39,56,34636,
+30,34,51,34636,
+12,47,48,34636,
+27,35,52,34636,
+0,13,67,34636,
+0,43,53,34636,
+23,23,60,34636,
+25,28,57,34636,
+17,20,63,34636,
+1,39,56,34636,
diff --git a/src/cf_interface.h b/src/cf_interface.h
new file mode 100644
index 0000000..95809b0
--- /dev/null
+++ b/src/cf_interface.h
@@ -0,0 +1,23 @@
+#ifndef CF_INTERFACE_H
+#define CF_INTERFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_CF_INTERFACE
+
+#ifndef __CFORTRAN_LOADED
+#ifdef __clang__
+#  pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wreserved-id-macro"
+#  endif
+#  include "cfortran.h"
+#  ifdef __clang__
+#    pragma GCC diagnostic pop
+#  endif
+#endif
+
+#endif
+
+#endif
diff --git a/src/cfortran.h b/src/cfortran.h
new file mode 100644
index 0000000..222faba
--- /dev/null
+++ b/src/cfortran.h
@@ -0,0 +1,2559 @@
+/* cfortran.h  4.4 */
+/* http://www-zeus.desy.de/~burow/cfortran/                   */
+/* Burkhard Burow  burow at desy.de                 1990 - 2002. */
+
+#ifndef __CFORTRAN_LOADED
+#define __CFORTRAN_LOADED
+
+/* 
+   THIS FILE IS PROPERTY OF BURKHARD BUROW. IF YOU ARE USING THIS FILE YOU
+   SHOULD ALSO HAVE ACCESS TO CFORTRAN.DOC WHICH PROVIDES TERMS FOR USING,
+   MODIFYING, COPYING AND DISTRIBUTING THE CFORTRAN.H PACKAGE.
+*/
+
+/* THIS PACKAGE, I.E. CFORTRAN.H, THIS DOCUMENT, AND THE CFORTRAN.H EXAMPLE
+PROGRAMS ARE PROPERTY OF THE AUTHOR WHO RESERVES ALL RIGHTS. THIS PACKAGE AND
+THE CODE IT PRODUCES MAY BE FREELY DISTRIBUTED WITHOUT FEES, SUBJECT
+(AT YOUR CHOICE) EITHER TO THE GNU LIBRARY GENERAL PUBLIC LICENSE
+AT http://www.gnu.org/licenses/lgpl.html OR TO THE FOLLOWING RESTRICTIONS:
+- YOU MUST ACCOMPANY ANY COPIES OR DISTRIBUTION WITH THIS (UNALTERED) NOTICE.
+- YOU MAY NOT RECEIVE MONEY FOR THE DISTRIBUTION OR FOR ITS MEDIA 
+  (E.G. TAPE, DISK, COMPUTER, PAPER.)
+- YOU MAY NOT PREVENT OTHERS FROM COPYING IT FREELY.
+- YOU MAY NOT DISTRIBUTE MODIFIED VERSIONS WITHOUT CLEARLY DOCUMENTING YOUR
+  CHANGES AND NOTIFYING THE AUTHOR.
+- YOU MAY NOT MISREPRESENTED THE ORIGIN OF THIS SOFTWARE, EITHER BY EXPLICIT
+  CLAIM OR BY OMISSION.
+
+THE INTENT OF THE ABOVE TERMS IS TO ENSURE THAT THE CFORTRAN.H PACKAGE NOT BE
+USED FOR PROFIT MAKING ACTIVITIES UNLESS SOME ROYALTY ARRANGEMENT IS ENTERED
+INTO WITH ITS AUTHOR.
+              
+THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST
+OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. THE AUTHOR IS NOT RESPONSIBLE
+FOR ANY SUPPORT OR SERVICE OF THE CFORTRAN.H PACKAGE.
+
+                                              Burkhard Burow 
+                                              burow at desy.de
+*/
+
+/* The following modifications were made by the authors of CFITSIO or by me. 
+ * They are flagged below with CFITSIO, the author's initials, or KMCCARTY.
+ * PDW = Peter Wilson
+ * DM  = Doug Mink
+ * LEB = Lee E Brotzman
+ * MR  = Martin Reinecke
+ * WDP = William D Pence
+ * BR  = Bastien ROUCARIES
+ * -- Kevin McCarty, for Debian (19 Dec. 2005) */
+
+/*******
+   Modifications:
+      Oct 1997: Changed symbol name extname to appendus (PDW/HSTX)
+                (Conflicted with a common variable name in FTOOLS)
+      Nov 1997: If g77Fortran defined, also define f2cFortran (PDW/HSTX)
+      Feb 1998: Let VMS see the NUM_ELEMS code. Lets programs treat
+                single strings as vectors with single elements
+      Nov 1999: If macintoxh defined, also define f2cfortran (for Mac OS-X)
+      Apr 2000: If WIN32 defined, also define PowerStationFortran and
+                VISUAL_CPLUSPLUS (Visual C++)
+      Jun 2000: If __GNUC__ and linux defined, also define f2cFortran
+                (linux/gcc environment detection)
+      Apr 2002: If __CYGWIN__ is defined, also define f2cFortran
+      Nov 2002: If __APPLE__ defined, also define f2cfortran (for Mac OS-X)
+
+      Nov 2003: If __INTEL_COMPILER or INTEL_COMPILER defined, also define
+                f2cFortran (KMCCARTY)
+      Dec 2005: If f2cFortran is defined, enforce REAL functions in FORTRAN
+                returning "double" in C.  This was one of the items on
+		Burkhard's TODO list. (KMCCARTY)
+      Dec 2005: Modifications to support 8-byte integers. (MR)
+		USE AT YOUR OWN RISK!
+      Feb 2006  Added logic to typedef the symbol 'LONGLONG' to an appropriate
+                intrinsic 8-byte integer datatype  (WDP)
+      Apr 2006: Modifications to support gfortran (and g77 with -fno-f2c flag)
+                since by default it returns "float" for FORTRAN REAL function.
+                (KMCCARTY)
+      May 2008: Revert commenting out of "extern" in COMMON_BLOCK_DEF macro.
+		Add braces around do-nothing ";" in 3 empty while blocks to
+		get rid of compiler warnings.  Thanks to ROOT developers
+		Jacek Holeczek and Rene Brun for these suggestions. (KMCCARTY)
+      Aug 2008: If __GNUC__ is defined and no FORTRAN compiler is specified
+		via a #define or -D, default to gfortran behavior rather than
+		g77 behavior. (KMCCARTY)
+      Oct 2009: Add warning if guessing default fortran. Move g77 above guessing bloc
+ *******/
+
+/* 
+  Avoid symbols already used by compilers and system *.h:
+  __ - OSF1 zukal06 V3.0 347 alpha, cc -c -std1 cfortest.c
+
+*/
+
+/* 
+   Determine what 8-byte integer data type is available.
+  'long long' is now supported by most compilers, but older
+  MS Visual C++ compilers before V7.0 use '__int64' instead. (WDP)
+*/
+
+#ifndef LONGLONG_TYPE   /* this may have been previously defined */
+#if defined(_MSC_VER)   /* Microsoft Visual C++ */
+
+#if (_MSC_VER < 1300)   /* versions earlier than V7.0 do not have 'long long' */
+    typedef __int64 LONGLONG;
+#else                   /* newer versions do support 'long long' */
+    typedef long long LONGLONG; 
+#endif
+
+#else
+    typedef long long LONGLONG; 
+#endif
+
+#define LONGLONG_TYPE
+#endif  
+
+
+/* First prepare for the C compiler. */
+
+#ifndef ANSI_C_preprocessor /* i.e. user can override. */
+#ifdef __CF__KnR
+#define ANSI_C_preprocessor 0
+#else
+#ifdef __STDC__
+#define ANSI_C_preprocessor 1
+#else
+#define _cfleft             1
+#define _cfright 
+#define _cfleft_cfright     0
+#define ANSI_C_preprocessor _cfleft/**/_cfright
+#endif
+#endif
+#endif
+
+#if ANSI_C_preprocessor
+#define _0(A,B)   A##B
+#define  _(A,B)   _0(A,B)  /* see cat,xcat of K&R ANSI C p. 231 */
+#define _2(A,B)   A##B     /* K&R ANSI C p.230: .. identifier is not replaced */
+#define _3(A,B,C) _(A,_(B,C))
+#else                      /* if it turns up again during rescanning.         */
+#define  _(A,B)   A/**/B
+#define _2(A,B)   A/**/B
+#define _3(A,B,C) A/**/B/**/C
+#endif
+
+#if (defined(vax)&&defined(unix)) || (defined(__vax__)&&defined(__unix__))
+#define VAXUltrix
+#endif
+
+#include <stdio.h>     /* NULL [in all machines stdio.h]                      */
+#include <string.h>    /* strlen, memset, memcpy, memchr.                     */
+#if !( defined(VAXUltrix) || defined(sun) || (defined(apollo)&&!defined(__STDCPP__)) )
+#include <stdlib.h>    /* malloc,free                                         */
+#else
+#include <malloc.h>    /* Had to be removed for DomainOS h105 10.4 sys5.3 425t*/
+#ifdef apollo
+#define __CF__APOLLO67 /* __STDCPP__ is in Apollo 6.8 (i.e. ANSI) and onwards */
+#endif
+#endif
+
+#if !defined(__GNUC__) && !defined(__sun) && (defined(sun)||defined(VAXUltrix)||defined(lynx))
+#define __CF__KnR     /* Sun, LynxOS and VAX Ultrix cc only supports K&R.     */
+                      /* Manually define __CF__KnR for HP if desired/required.*/
+#endif                /*       i.e. We will generate Kernighan and Ritchie C. */
+/* Note that you may define __CF__KnR before #include cfortran.h, in order to
+generate K&R C instead of the default ANSI C. The differences are mainly in the
+function prototypes and declarations. All machines, except the Apollo, work
+with either style. The Apollo's argument promotion rules require ANSI or use of
+the obsolete std_$call which we have not implemented here. Hence on the Apollo,
+only C calling FORTRAN subroutines will work using K&R style.*/
+
+
+/* Remainder of cfortran.h depends on the Fortran compiler. */
+
+/* 11/29/2003 (KMCCARTY): add *INTEL_COMPILER symbols here */
+/* 04/05/2006 (KMCCARTY): add gFortran symbol here */
+#if defined(CLIPPERFortran) || defined(pgiFortran) || defined(__INTEL_COMPILER) || defined(INTEL_COMPILER) || defined(gFortran)
+#define f2cFortran
+#endif
+
+#if defined(g77Fortran)                        /* 11/03/97 PDW (CFITSIO) */
+#define f2cFortran
+#endif
+
+/* VAX/VMS does not let us \-split long #if lines. */ 
+/* Split #if into 2 because some HP-UX can't handle long #if */
+#if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
+#if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
+/* If no Fortran compiler is given, we choose one for the machines we know.   */
+#if defined(__GNUC__) || defined(WIN32) /* 10/2009 BR: warm if guess */
+#warning "Please specify the fortran compiler using -D flags. Try to guess the compiler used"
+#endif
+#if defined(lynx) || defined(VAXUltrix)
+#define f2cFortran    /* Lynx:      Only support f2c at the moment.
+                         VAXUltrix: f77 behaves like f2c.
+                           Support f2c or f77 with gcc, vcc with f2c. 
+                           f77 with vcc works, missing link magic for f77 I/O.*/
+#endif
+/* 04/13/00 DM (CFITSIO): Add these lines for NT */
+/*   with PowerStationFortran and and Visual C++ */
+#if defined(WIN32) && !defined(__CYGWIN__)
+#define PowerStationFortran   
+#define VISUAL_CPLUSPLUS
+#endif
+#if        defined(__CYGWIN__)                 /* 04/11/02 LEB (CFITSIO) */
+#define       f2cFortran 
+#define	      gFortran /* 8/26/08 (KMCCARTY) */
+#endif
+#if        defined(__GNUC__) && defined(linux) /* 06/21/00 PDW (CFITSIO) */
+#define       f2cFortran 
+#define	      gFortran /* 8/26/08 (KMCCARTY) */
+#endif
+#if defined(macintosh)                         /* 11/1999 (CFITSIO) */
+#define f2cFortran
+#define	      gFortran /* 8/26/08 (KMCCARTY) */
+#endif
+#if defined(__APPLE__)                         /* 11/2002 (CFITSIO) */
+#define f2cFortran
+#define	      gFortran /* 8/26/08 (KMCCARTY) */
+#endif
+#if defined(__hpux)             /* 921107: Use __hpux instead of __hp9000s300 */
+#define       hpuxFortran       /*         Should also allow hp9000s7/800 use.*/
+#endif
+#if       defined(apollo)
+#define           apolloFortran /* __CF__APOLLO67 also defines some behavior. */
+#endif
+#if          defined(sun) || defined(__sun) 
+#define              sunFortran
+#endif
+#if       defined(_IBMR2)
+#define            IBMR2Fortran
+#endif
+#if        defined(_CRAY)
+#define             CRAYFortran /*       _CRAYT3E also defines some behavior. */
+#endif
+#if        defined(_SX)
+#define               SXFortran
+#endif
+#if         defined(mips) || defined(__mips)
+#define             mipsFortran
+#endif
+#if          defined(vms) || defined(__vms)
+#define              vmsFortran
+#endif
+#if      defined(__alpha) && defined(__unix__)
+#define              DECFortran
+#endif
+#if   defined(__convex__)
+#define           CONVEXFortran
+#endif
+#if   defined(VISUAL_CPLUSPLUS)
+#define     PowerStationFortran
+#endif
+#endif /* ...Fortran */
+#endif /* ...Fortran */
+
+/* Split #if into 2 because some HP-UX can't handle long #if */
+#if !(defined(NAGf90Fortran)||defined(f2cFortran)||defined(hpuxFortran)||defined(apolloFortran)||defined(sunFortran)||defined(IBMR2Fortran)||defined(CRAYFortran))
+#if !(defined(mipsFortran)||defined(DECFortran)||defined(vmsFortran)||defined(CONVEXFortran)||defined(PowerStationFortran)||defined(AbsoftUNIXFortran)||defined(AbsoftProFortran)||defined(SXFortran))
+/* If your compiler barfs on ' #error', replace # with the trigraph for #     */
+ #error "cfortran.h:  Can't find your environment among:\
+    - GNU gcc (gfortran) on Linux.                                       \
+    - MIPS cc and f77 2.0. (e.g. Silicon Graphics, DECstations, ...)     \
+    - IBM AIX XL C and FORTRAN Compiler/6000 Version 01.01.0000.0000     \
+    - VAX   VMS CC 3.1 and FORTRAN 5.4.                                  \
+    - Alpha VMS DEC C 1.3 and DEC FORTRAN 6.0.                           \
+    - Alpha OSF DEC C and DEC Fortran for OSF/1 AXP Version 1.2          \
+    - Apollo DomainOS 10.2 (sys5.3) with f77 10.7 and cc 6.7.            \
+    - CRAY                                                               \
+    - NEC SX-4 SUPER-UX                                                  \
+    - CONVEX                                                             \
+    - Sun                                                                \
+    - PowerStation Fortran with Visual C++                               \
+    - HP9000s300/s700/s800 Latest test with: HP-UX A.08.07 A 9000/730    \
+    - LynxOS: cc or gcc with f2c.                                        \
+    - VAXUltrix: vcc,cc or gcc with f2c. gcc or cc with f77.             \
+    -            f77 with vcc works; but missing link magic for f77 I/O. \
+    -            NO fort. None of gcc, cc or vcc generate required names.\
+    - f2c/g77:   Use #define    f2cFortran, or cc -Df2cFortran           \
+    - gfortran:  Use #define    gFortran,   or cc -DgFortran             \
+                 (also necessary for g77 with -fno-f2c option)           \
+    - NAG f90: Use #define NAGf90Fortran, or cc -DNAGf90Fortran          \
+    - Absoft UNIX F77: Use #define AbsoftUNIXFortran or cc -DAbsoftUNIXFortran \
+    - Absoft Pro Fortran: Use #define AbsoftProFortran \
+    - Portland Group Fortran: Use #define pgiFortran \
+    - Intel Fortran: Use #define INTEL_COMPILER"
+/* Compiler must throw us out at this point! */
+#endif
+#endif
+
+
+#if defined(VAXC) && !defined(__VAXC)
+#define OLD_VAXC
+#pragma nostandard                       /* Prevent %CC-I-PARAMNOTUSED.       */
+#endif
+
+/* Throughout cfortran.h we use: UN = Uppercase Name.  LN = Lowercase Name.   */
+
+/* "extname" changed to "appendus" below (CFITSIO) */
+#if defined(f2cFortran) || defined(NAGf90Fortran) || defined(DECFortran) || defined(mipsFortran) || defined(apolloFortran) || defined(sunFortran) || defined(CONVEXFortran) || defined(SXFortran) || defined(appendus)
+#define CFC_(UN,LN)            _(LN,_)      /* Lowercase FORTRAN symbols.     */
+#define orig_fcallsc(UN,LN)    CFC_(UN,LN)
+#else 
+#if defined(CRAYFortran) || defined(PowerStationFortran) || defined(AbsoftProFortran)
+#ifdef _CRAY          /* (UN), not UN, circumvents CRAY preprocessor bug.     */
+#define CFC_(UN,LN)            (UN)         /* Uppercase FORTRAN symbols.     */
+#else                 /* At least VISUAL_CPLUSPLUS barfs on (UN), so need UN. */
+#define CFC_(UN,LN)            UN           /* Uppercase FORTRAN symbols.     */
+#endif
+#define orig_fcallsc(UN,LN)    CFC_(UN,LN)  /* CRAY insists on arg.'s here.   */
+#else  /* For following machines one may wish to change the fcallsc default.  */
+#define CF_SAME_NAMESPACE
+#ifdef vmsFortran
+#define CFC_(UN,LN)            LN           /* Either case FORTRAN symbols.   */
+     /* BUT we usually use UN for C macro to FORTRAN routines, so use LN here,*/
+     /* because VAX/VMS doesn't do recursive macros.                          */
+#define orig_fcallsc(UN,LN)    UN
+#else      /* HP-UX without +ppu or IBMR2 without -qextname. NOT reccomended. */
+#define CFC_(UN,LN)            LN           /* Lowercase FORTRAN symbols.     */
+#define orig_fcallsc(UN,LN)    CFC_(UN,LN)
+#endif /*  vmsFortran */
+#endif /* CRAYFortran PowerStationFortran */
+#endif /* ....Fortran */
+
+#define fcallsc(UN,LN)               orig_fcallsc(UN,LN)
+#define preface_fcallsc(P,p,UN,LN)   CFC_(_(P,UN),_(p,LN))
+#define  append_fcallsc(P,p,UN,LN)   CFC_(_(UN,P),_(LN,p))
+
+#define C_FUNCTION(UN,LN)            fcallsc(UN,LN)      
+#define FORTRAN_FUNCTION(UN,LN)      CFC_(UN,LN)
+
+#ifndef COMMON_BLOCK
+#ifndef CONVEXFortran
+#ifndef CLIPPERFortran
+#if     !(defined(AbsoftUNIXFortran)||defined(AbsoftProFortran))
+#define COMMON_BLOCK(UN,LN)          CFC_(UN,LN)
+#else
+#define COMMON_BLOCK(UN,LN)          _(_C,LN)
+#endif  /* AbsoftUNIXFortran or AbsoftProFortran */
+#else
+#define COMMON_BLOCK(UN,LN)          _(LN,__)
+#endif  /* CLIPPERFortran */
+#else
+#define COMMON_BLOCK(UN,LN)          _3(_,LN,_)
+#endif  /* CONVEXFortran */
+#endif  /* COMMON_BLOCK */
+
+#ifndef DOUBLE_PRECISION
+#if defined(CRAYFortran) && !defined(_CRAYT3E)
+#define DOUBLE_PRECISION long double
+#else
+#define DOUBLE_PRECISION double
+#endif
+#endif
+
+#ifndef FORTRAN_REAL
+#if defined(CRAYFortran) &&  defined(_CRAYT3E)
+#define FORTRAN_REAL double
+#else
+#define FORTRAN_REAL float
+#endif
+#endif
+
+#ifdef CRAYFortran
+#ifdef _CRAY
+#include <fortran.h>
+#else
+#include "fortran.h"  /* i.e. if crosscompiling assume user has file. */
+#endif
+#define FLOATVVVVVVV_cfPP (FORTRAN_REAL *)   /* Used for C calls FORTRAN.     */
+/* CRAY's double==float but CRAY says pointers to doubles and floats are diff.*/
+#define VOIDP  (void *)  /* When FORTRAN calls C, we don't know if C routine 
+                            arg.'s have been declared float *, or double *.   */
+#else
+#define FLOATVVVVVVV_cfPP
+#define VOIDP
+#endif
+
+#ifdef vmsFortran
+#if    defined(vms) || defined(__vms)
+#include <descrip.h>
+#else
+#include "descrip.h"  /* i.e. if crosscompiling assume user has file. */
+#endif
+#endif
+
+#ifdef sunFortran
+#if defined(sun) || defined(__sun)
+#include <math.h>     /* Sun's FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT.  */
+#else
+#include "math.h"     /* i.e. if crosscompiling assume user has file. */
+#endif
+/* At least starting with the default C compiler SC3.0.1 of SunOS 5.3,
+ * FLOATFUNCTIONTYPE, ASSIGNFLOAT, RETURNFLOAT are not required and not in
+ * <math.h>, since sun C no longer promotes C float return values to doubles.
+ * Therefore, only use them if defined.
+ * Even if gcc is being used, assume that it exhibits the Sun C compiler
+ * behavior in order to be able to use *.o from the Sun C compiler.
+ * i.e. If FLOATFUNCTIONTYPE, etc. are in math.h, they required by gcc.
+ */
+#endif
+
+#ifndef apolloFortran
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) extern DEFINITION NAME
+#define CF_NULL_PROTO
+#else                                         /* HP doesn't understand #elif. */
+/* Without ANSI prototyping, Apollo promotes float functions to double.    */
+/* Note that VAX/VMS, IBM, Mips choke on 'type function(...);' prototypes. */
+#define CF_NULL_PROTO ...
+#ifndef __CF__APOLLO67
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) \
+ DEFINITION NAME __attribute((__section(NAME)))
+#else
+#define COMMON_BLOCK_DEF(DEFINITION, NAME) \
+ DEFINITION NAME #attribute[section(NAME)]
+#endif
+#endif
+
+#ifdef __cplusplus
+#undef  CF_NULL_PROTO
+#define CF_NULL_PROTO  ...
+#endif
+
+
+#ifndef USE_NEW_DELETE
+#ifdef __cplusplus
+#define USE_NEW_DELETE 1
+#else
+#define USE_NEW_DELETE 0
+#endif
+#endif
+#if USE_NEW_DELETE
+#define _cf_malloc(N) new char[N]
+#define _cf_free(P)   delete[] P
+#else
+#define _cf_malloc(N) (char *)malloc(N)
+#define _cf_free(P)   free(P)
+#endif
+
+#ifdef mipsFortran
+#define CF_DECLARE_GETARG         int f77argc; char **f77argv
+#define CF_SET_GETARG(ARGC,ARGV)  f77argc = ARGC; f77argv = ARGV
+#else
+#define CF_DECLARE_GETARG
+#define CF_SET_GETARG(ARGC,ARGV)
+#endif
+
+#ifdef OLD_VAXC                          /* Allow %CC-I-PARAMNOTUSED.         */
+#pragma standard                         
+#endif
+
+#define AcfCOMMA ,
+#define AcfCOLON ;
+
+/*-------------------------------------------------------------------------*/
+
+/*               UTILITIES USED WITHIN CFORTRAN.H                          */
+
+#define _cfMIN(A,B) (A<B?A:B)
+
+/* 970211 - XIX.145:
+   firstindexlength  - better name is all_but_last_index_lengths
+   secondindexlength - better name is         last_index_length
+ */
+#define  firstindexlength(A) (sizeof(A[0])==1 ? 1 : (sizeof(A) / sizeof(A[0])) )
+#define secondindexlength(A) (sizeof(A[0])==1 ?      sizeof(A) : sizeof(A[0])  )
+
+/* Behavior of FORTRAN LOGICAL. All machines' LOGICAL is same size as C's int.
+Conversion is automatic except for arrays which require F2CLOGICALV/C2FLOGICALV.
+f2c, MIPS f77 [DECstation, SGI], VAX Ultrix f77,
+HP-UX f77                                        : as in C.
+VAX/VMS FORTRAN, VAX Ultrix fort,
+Absoft Unix Fortran, IBM RS/6000 xlf             : LS Bit = 0/1 = TRUE/FALSE.
+Apollo                                           : neg.   = TRUE, else FALSE. 
+[Apollo accepts -1 as TRUE for function values, but NOT all other neg. values.]
+[DECFortran for Ultrix RISC is also called f77 but is the same as VAX/VMS.]   
+[MIPS f77 treats .eqv./.neqv. as .eq./.ne. and hence requires LOGICAL_STRICT.]*/
+
+#if defined(NAGf90Fortran) || defined(f2cFortran) || defined(mipsFortran) || defined(PowerStationFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran) || defined(SXFortran)
+/* SX/PowerStationFortran have 0 and 1 defined, others are neither T nor F.   */
+/* hpuxFortran800 has 0 and 0x01000000 defined. Others are unknown.           */
+#define LOGICAL_STRICT      /* Other Fortran have .eqv./.neqv. == .eq./.ne.   */
+#endif
+
+#define C2FLOGICALV(A,I) \
+ do {int __i; for(__i=0;__i<I;__i++) A[__i]=C2FLOGICAL(A[__i]); } while (0)
+#define F2CLOGICALV(A,I) \
+ do {int __i; for(__i=0;__i<I;__i++) A[__i]=F2CLOGICAL(A[__i]); } while (0)
+
+#if defined(apolloFortran)
+#define C2FLOGICAL(L) ((L)?-1:(L)&~((unsigned)1<<sizeof(int)*8-1))
+#define F2CLOGICAL(L) ((L)<0?(L):0) 
+#else
+#if defined(CRAYFortran)
+#define C2FLOGICAL(L) _btol(L)
+#define F2CLOGICAL(L) _ltob(&(L))     /* Strangely _ltob() expects a pointer. */
+#else
+#if defined(IBMR2Fortran) || defined(vmsFortran) || defined(DECFortran) || defined(AbsoftUNIXFortran)
+/* How come no AbsoftProFortran ? */
+#define C2FLOGICAL(L) ((L)?(L)|1:(L)&~(int)1)
+#define F2CLOGICAL(L) ((L)&1?(L):0)
+#else
+#if defined(CONVEXFortran)
+#define C2FLOGICAL(L) ((L) ? ~0 : 0 )
+#define F2CLOGICAL(L) (L)
+#else   /* others evaluate LOGICALs as for C. */
+#define C2FLOGICAL(L) (L)
+#define F2CLOGICAL(L) (L)
+#ifndef LOGICAL_STRICT
+#undef  C2FLOGICALV
+#undef  F2CLOGICALV
+#define C2FLOGICALV(A,I)
+#define F2CLOGICALV(A,I)
+#endif  /* LOGICAL_STRICT                     */
+#endif  /* CONVEXFortran || All Others        */
+#endif  /* IBMR2Fortran vmsFortran DECFortran AbsoftUNIXFortran */
+#endif  /* CRAYFortran                        */
+#endif  /* apolloFortran                      */
+
+/* 970514 - In addition to CRAY, there may be other machines
+            for which LOGICAL_STRICT makes no sense. */
+#if defined(LOGICAL_STRICT) && !defined(CRAYFortran)
+/* Force C2FLOGICAL to generate only the values for either .TRUE. or .FALSE.
+   SX/PowerStationFortran only have 0 and 1 defined.
+   Elsewhere, only needed if you want to do:
+     logical lvariable
+     if (lvariable .eq.  .true.) then       ! (1)
+   instead of
+     if (lvariable .eqv. .true.) then       ! (2)
+   - (1) may not even be FORTRAN/77 and that Apollo's f77 and IBM's xlf
+     refuse to compile (1), so you are probably well advised to stay away from 
+     (1) and from LOGICAL_STRICT.
+   - You pay a (slight) performance penalty for using LOGICAL_STRICT. */
+#undef  C2FLOGICAL
+#ifdef hpuxFortran800
+#define C2FLOGICAL(L) ((L)?0x01000000:0)
+#else
+#if defined(apolloFortran) || defined(vmsFortran) || defined(DECFortran)
+#define C2FLOGICAL(L) ((L)?-1:0) /* These machines use -1/0 for .true./.false.*/
+#else
+#define C2FLOGICAL(L) ((L)? 1:0) /* All others     use +1/0 for .true./.false.*/
+#endif
+#endif
+#endif /* LOGICAL_STRICT */
+
+/* Convert a vector of C strings into FORTRAN strings. */
+#ifndef __CF__KnR
+static char *c2fstrv(char* cstr, char *fstr, int elem_len, int sizeofcstr)
+#else
+static char *c2fstrv(      cstr,       fstr,     elem_len,     sizeofcstr)
+                     char* cstr; char *fstr; int elem_len; int sizeofcstr;
+#endif
+{ int i,j;
+/* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
+   Useful size of string must be the same in both languages. */
+for (i=0; i<sizeofcstr/elem_len; i++) {
+  for (j=1; j<elem_len && *cstr; j++) *fstr++ = *cstr++;
+  cstr += 1+elem_len-j;
+  for (; j<elem_len; j++) *fstr++ = ' ';
+} /* 95109 - Seems to be returning the original fstr. */
+return fstr-sizeofcstr+sizeofcstr/elem_len; }
+
+/* Convert a vector of FORTRAN strings into C strings. */
+#ifndef __CF__KnR
+static char *f2cstrv(char *fstr, char* cstr, int elem_len, int sizeofcstr)
+#else
+static char *f2cstrv(      fstr,       cstr,     elem_len,     sizeofcstr)
+                     char *fstr; char* cstr; int elem_len; int sizeofcstr; 
+#endif
+{ int i,j;
+/* elem_len includes \0 for C strings. Fortran strings don't have term. \0.
+   Useful size of string must be the same in both languages. */
+cstr += sizeofcstr;
+fstr += sizeofcstr - sizeofcstr/elem_len;
+for (i=0; i<sizeofcstr/elem_len; i++) {
+  *--cstr = '\0';
+  for (j=1; j<elem_len; j++) *--cstr = *--fstr;
+} return cstr; }
+
+/* kill the trailing char t's in string s. */
+#ifndef __CF__KnR
+static char *kill_trailing(char *s, char t)
+#else
+static char *kill_trailing(      s,      t) char *s; char t;
+#endif
+{char *e; 
+e = s + strlen(s);
+if (e>s) {                           /* Need this to handle NULL string.*/
+  while (e>s && *--e==t) {;}         /* Don't follow t's past beginning. */
+  e[*e==t?0:1] = '\0';               /* Handle s[0]=t correctly.       */
+} return s; }
+
+#ifndef __CF__KnR
+static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term);
+#endif
+/* kill_trailingn(s,t,e) will kill the trailing t's in string s. e normally 
+points to the terminating '\0' of s, but may actually point to anywhere in s.
+s's new '\0' will be placed at e or earlier in order to remove any trailing t's.
+If e<s string s is left unchanged. */ 
+#ifndef __CF__KnR
+static char *kill_trailingn(char *s, char t, char *e)
+#else
+static char *kill_trailingn(      s,      t,       e) char *s; char t; char *e;
+#endif
+{ 
+if (e==s) *e = '\0';                 /* Kill the string makes sense here.*/
+else if (e>s) {                      /* Watch out for neg. length string.*/
+  while (e>s && *--e==t){;}          /* Don't follow t's past beginning. */
+  e[*e==t?0:1] = '\0';               /* Handle s[0]=t correctly.       */
+}
+(void)num_elem;  /* to prevent not used warnings in gcc (added by TJ) */
+
+ return s; }
+
+/* Note the following assumes that any element which has t's to be chopped off,
+does indeed fill the entire element. */
+#ifndef __CF__KnR
+static char *vkill_trailing(char* cstr, int elem_len, int sizeofcstr, char t)
+#else
+static char *vkill_trailing(      cstr,     elem_len,     sizeofcstr,      t)
+                            char* cstr; int elem_len; int sizeofcstr; char t;
+#endif
+{ int i;
+for (i=0; i<sizeofcstr/elem_len; i++) /* elem_len includes \0 for C strings. */
+  kill_trailingn(cstr+elem_len*i,t,cstr+elem_len*(i+1)-1);
+return cstr; }
+
+#ifdef vmsFortran
+typedef struct dsc$descriptor_s fstring;
+#define DSC$DESCRIPTOR_A(DIMCT)  		                               \
+struct {                                                                       \
+  unsigned short dsc$w_length;	        unsigned char	 dsc$b_dtype;	       \
+  unsigned char	 dsc$b_class;	                 char	*dsc$a_pointer;	       \
+           char	 dsc$b_scale;	        unsigned char	 dsc$b_digits;         \
+  struct {                                                                     \
+    unsigned		       : 3;	  unsigned dsc$v_fl_binscale : 1;      \
+    unsigned dsc$v_fl_redim    : 1;       unsigned dsc$v_fl_column   : 1;      \
+    unsigned dsc$v_fl_coeff    : 1;       unsigned dsc$v_fl_bounds   : 1;      \
+  } dsc$b_aflags;	                                                       \
+  unsigned char	 dsc$b_dimct;	        unsigned long	 dsc$l_arsize;	       \
+           char	*dsc$a_a0;	                 long	 dsc$l_m [DIMCT];      \
+  struct {                                                                     \
+    long dsc$l_l;                         long dsc$l_u;                        \
+  } dsc$bounds [DIMCT];                                                        \
+}
+typedef DSC$DESCRIPTOR_A(1) fstringvector;
+/*typedef DSC$DESCRIPTOR_A(2) fstringarrarr;
+  typedef DSC$DESCRIPTOR_A(3) fstringarrarrarr;*/
+#define initfstr(F,C,ELEMNO,ELEMLEN)                                           \
+( (F).dsc$l_arsize=  ( (F).dsc$w_length                        =(ELEMLEN) )    \
+                    *( (F).dsc$l_m[0]=(F).dsc$bounds[0].dsc$l_u=(ELEMNO)  ),   \
+  (F).dsc$a_a0    =  ( (F).dsc$a_pointer=(C) ) - (F).dsc$w_length          ,(F))
+
+#endif      /* PDW: 2/10/98 (CFITSIO) -- Let VMS see NUM_ELEMS definitions */
+#define _NUM_ELEMS      -1
+#define _NUM_ELEM_ARG   -2
+#define NUM_ELEMS(A)    A,_NUM_ELEMS
+#define NUM_ELEM_ARG(B) *_2(A,B),_NUM_ELEM_ARG
+#define TERM_CHARS(A,B) A,B
+#ifndef __CF__KnR
+static int num_elem(const char *strv, unsigned elem_len, int term_char, int num_term)
+#else
+static int num_elem(      strv,          elem_len,     term_char,     num_term)
+                    char *strv; unsigned elem_len; int term_char; int num_term;
+#endif
+/* elem_len is the number of characters in each element of strv, the FORTRAN
+vector of strings. The last element of the vector must begin with at least
+num_term term_char characters, so that this routine can determine how 
+many elements are in the vector. */
+{
+unsigned num,i;
+if (num_term == _NUM_ELEMS || num_term == _NUM_ELEM_ARG) 
+  return term_char;
+if (num_term <=0) num_term = (int)elem_len;
+for (num=0; ; num++) {
+  for (i=0; i<(unsigned)num_term && *strv==term_char; i++,strv++){;}
+  if (i==(unsigned)num_term) break;
+  else strv += elem_len-i;
+}
+/* to prevent not used warnings in gcc (added by ROOT, changed by TJ
+ * because of unreachable warnings from clang) */
+(void)c2fstrv; (void)f2cstrv; (void)kill_trailing;
+(void)vkill_trailing; (void)num_elem;
+return (int)num;
+}
+/* #endif removed 2/10/98 (CFITSIO) */
+
+/*-------------------------------------------------------------------------*/
+
+/*           UTILITIES FOR C TO USE STRINGS IN FORTRAN COMMON BLOCKS       */
+
+/* C string TO Fortran Common Block STRing. */
+/* DIM is the number of DIMensions of the array in terms of strings, not
+   characters. e.g. char a[12] has DIM = 0, char a[12][4] has DIM = 1, etc. */
+#define C2FCBSTR(CSTR,FSTR,DIM)                                                \
+ c2fstrv((char *)CSTR, (char *)FSTR, sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,    \
+         sizeof(FSTR)+cfelementsof(FSTR,DIM))
+
+/* Fortran Common Block string TO C STRing. */
+#define FCB2CSTR(FSTR,CSTR,DIM)                                                \
+ vkill_trailing(f2cstrv((char *)FSTR, (char *)CSTR,                            \
+                        sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,                 \
+                        sizeof(FSTR)+cfelementsof(FSTR,DIM)),                  \
+                sizeof(FSTR)/cfelementsof(FSTR,DIM)+1,                         \
+                sizeof(FSTR)+cfelementsof(FSTR,DIM), ' ')
+
+#define cfDEREFERENCE0
+#define cfDEREFERENCE1 *
+#define cfDEREFERENCE2 **
+#define cfDEREFERENCE3 ***
+#define cfDEREFERENCE4 ****
+#define cfDEREFERENCE5 *****
+#define cfelementsof(A,D) (sizeof(A)/sizeof(_(cfDEREFERENCE,D)(A)))
+
+/*-------------------------------------------------------------------------*/
+
+/*               UTILITIES FOR C TO CALL FORTRAN SUBROUTINES               */
+
+/* Define lookup tables for how to handle the various types of variables.  */
+
+#ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#define ZTRINGV_NUM(I)       I
+#define ZTRINGV_ARGFP(I) (*(_2(A,I))) /* Undocumented. For PINT, etc. */
+#define ZTRINGV_ARGF(I) _2(A,I)
+#ifdef CFSUBASFUN
+#define ZTRINGV_ARGS(I) ZTRINGV_ARGF(I)
+#else
+#define ZTRINGV_ARGS(I) _2(B,I)
+#endif
+
+#define    PBYTE_cfVP(A,B) PINT_cfVP(A,B)
+#define  PDOUBLE_cfVP(A,B)
+#define   PFLOAT_cfVP(A,B)
+#ifdef ZTRINGV_ARGS_allows_Pvariables
+/* This allows Pvariables for ARGS. ARGF machinery is above ARGFP.
+ * B is not needed because the variable may be changed by the Fortran routine,
+ * but because B is the only way to access an arbitrary macro argument.       */
+#define     PINT_cfVP(A,B) int  B = (int)A;              /* For ZSTRINGV_ARGS */
+#else
+#define     PINT_cfVP(A,B)
+#endif
+#define PLOGICAL_cfVP(A,B) int *B;      /* Returning LOGICAL in FUNn and SUBn */
+#define    PLONG_cfVP(A,B) PINT_cfVP(A,B)
+#define   PSHORT_cfVP(A,B) PINT_cfVP(A,B)
+
+#define        VCF_INT_S(T,A,B) _(T,VVVVVVV_cfTYPE) B = A;
+#define        VCF_INT_F(T,A,B) _(T,_cfVCF)(A,B)
+/* _cfVCF table is directly mapped to _cfCCC table. */
+#define     BYTE_cfVCF(A,B)
+#define   DOUBLE_cfVCF(A,B)
+#if !defined(__CF__KnR)
+#define    FLOAT_cfVCF(A,B)
+#else
+#define    FLOAT_cfVCF(A,B) FORTRAN_REAL B = A;
+#endif
+#define      INT_cfVCF(A,B)
+#define  LOGICAL_cfVCF(A,B)
+#define     LONG_cfVCF(A,B)
+#define    SHORT_cfVCF(A,B)
+
+/* 980416
+   Cast (void (*)(CF_NULL_PROTO)) causes SunOS CC 4.2 occasionally to barf,
+   while the following equivalent typedef is fine.
+   For consistency use the typedef on all machines.
+ */
+typedef void (*cfCAST_FUNCTION)(CF_NULL_PROTO);
+
+#define VCF(TN,I)       _Icf4(4,V,TN,_(A,I),_(B,I),F)
+#define VVCF(TN,AI,BI)  _Icf4(4,V,TN,AI,BI,S)
+#define        INT_cfV(T,A,B,F) _(VCF_INT_,F)(T,A,B)
+#define       INTV_cfV(T,A,B,F)
+#define      INTVV_cfV(T,A,B,F)
+#define     INTVVV_cfV(T,A,B,F)
+#define    INTVVVV_cfV(T,A,B,F)
+#define   INTVVVVV_cfV(T,A,B,F)
+#define  INTVVVVVV_cfV(T,A,B,F)
+#define INTVVVVVVV_cfV(T,A,B,F)
+#define PINT_cfV(      T,A,B,F) _(T,_cfVP)(A,B)
+#define PVOID_cfV(     T,A,B,F)
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define    ROUTINE_cfV(T,A,B,F) void (*B)(CF_NULL_PROTO) = (cfCAST_FUNCTION)A;
+#else
+#define    ROUTINE_cfV(T,A,B,F)
+#endif
+#define     SIMPLE_cfV(T,A,B,F)
+#ifdef vmsFortran
+#define     STRING_cfV(T,A,B,F) static struct {fstring f; unsigned clen;} B =  \
+                                       {{0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL},0};
+#define    PSTRING_cfV(T,A,B,F) static fstring B={0,DSC$K_DTYPE_T,DSC$K_CLASS_S,NULL};
+#define    STRINGV_cfV(T,A,B,F) static fstringvector B =                       \
+  {sizeof(A),DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
+#define   PSTRINGV_cfV(T,A,B,F) static fstringvector B =                       \
+          {0,DSC$K_DTYPE_T,DSC$K_CLASS_A,NULL,0,0,{0,0,1,1,1},1,0,NULL,0,{1,0}};
+#else
+#define     STRING_cfV(T,A,B,F) struct {unsigned int clen, flen; char *nombre;} B;
+#define    STRINGV_cfV(T,A,B,F) struct {char *s, *fs; unsigned flen; char *nombre;} B;
+#define    PSTRING_cfV(T,A,B,F) int     B;
+#define   PSTRINGV_cfV(T,A,B,F) struct{char *fs; unsigned int sizeofA,flen;}B;
+#endif
+#define    ZTRINGV_cfV(T,A,B,F)  STRINGV_cfV(T,A,B,F)
+#define   PZTRINGV_cfV(T,A,B,F) PSTRINGV_cfV(T,A,B,F)
+
+/* Note that the actions of the A table were performed inside the AA table.
+   VAX Ultrix vcc, and HP-UX cc, didn't evaluate arguments to functions left to
+   right, so we had to split the original table into the current robust two. */
+#define ACF(NAME,TN,AI,I)      _(TN,_cfSTR)(4,A,NAME,I,AI,_(B,I),0)
+#define   DEFAULT_cfA(M,I,A,B)
+#define   LOGICAL_cfA(M,I,A,B) B=C2FLOGICAL(B);
+#define  PLOGICAL_cfA(M,I,A,B) A=C2FLOGICAL(A);
+#define    STRING_cfA(M,I,A,B)  STRING_cfC(M,I,A,B,sizeof(A))
+#define   PSTRING_cfA(M,I,A,B) PSTRING_cfC(M,I,A,B,sizeof(A))
+#ifdef vmsFortran
+#define  AATRINGV_cfA(    A,B, sA,filA,silA)                                   \
+ initfstr(B,_cf_malloc((sA)-(filA)),(filA),(silA)-1),                          \
+          c2fstrv(A,B.dsc$a_pointer,(silA),(sA));
+#define APATRINGV_cfA(    A,B, sA,filA,silA)                                   \
+ initfstr(B,A,(filA),(silA)-1),c2fstrv(A,A,(silA),(sA));
+#else
+#define  AATRINGV_cfA(    A,B, sA,filA,silA)                                   \
+     (B.s=_cf_malloc((sA)-(filA)),B.fs=c2fstrv(A,B.s,(B.flen=(silA)-1)+1,(sA)));
+#define APATRINGV_cfA(    A,B, sA,filA,silA)                                   \
+ B.fs=c2fstrv(A,A,(B.flen=(silA)-1)+1,B.sizeofA=(sA));
+#endif
+#define   STRINGV_cfA(M,I,A,B)                                                 \
+    AATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
+#define  PSTRINGV_cfA(M,I,A,B)                                                 \
+   APATRINGV_cfA((char *)A,B,sizeof(A),firstindexlength(A),secondindexlength(A))
+#define   ZTRINGV_cfA(M,I,A,B)  AATRINGV_cfA( (char *)A,B,                     \
+                    (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1),                \
+                              (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
+#define  PZTRINGV_cfA(M,I,A,B) APATRINGV_cfA( (char *)A,B,                     \
+                    (_3(M,_ELEMS_,I))*(( _3(M,_ELEMLEN_,I))+1),                \
+                              (_3(M,_ELEMS_,I)),(_3(M,_ELEMLEN_,I))+1)
+
+#define    PBYTE_cfAAP(A,B) &A
+#define  PDOUBLE_cfAAP(A,B) &A
+#define   PFLOAT_cfAAP(A,B) FLOATVVVVVVV_cfPP &A
+#define     PINT_cfAAP(A,B) &A
+#define PLOGICAL_cfAAP(A,B) B= &A         /* B used to keep a common W table. */
+#define    PLONG_cfAAP(A,B) &A
+#define   PSHORT_cfAAP(A,B) &A
+
+#define AACF(TN,AI,I,C) _SEP_(TN,C,cfCOMMA) _Icf(3,AA,TN,AI,_(B,I))
+#define        INT_cfAA(T,A,B) &B
+#define       INTV_cfAA(T,A,B) _(T,VVVVVV_cfPP) A
+#define      INTVV_cfAA(T,A,B) _(T,VVVVV_cfPP)  A[0]
+#define     INTVVV_cfAA(T,A,B) _(T,VVVV_cfPP)   A[0][0]
+#define    INTVVVV_cfAA(T,A,B) _(T,VVV_cfPP)    A[0][0][0]
+#define   INTVVVVV_cfAA(T,A,B) _(T,VV_cfPP)     A[0][0][0][0]
+#define  INTVVVVVV_cfAA(T,A,B) _(T,V_cfPP)      A[0][0][0][0][0]
+#define INTVVVVVVV_cfAA(T,A,B) _(T,_cfPP)       A[0][0][0][0][0][0]
+#define       PINT_cfAA(T,A,B) _(T,_cfAAP)(A,B)
+#define      PVOID_cfAA(T,A,B) (void *) A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define    ROUTINE_cfAA(T,A,B) &B
+#else
+#define    ROUTINE_cfAA(T,A,B) (cfCAST_FUNCTION)A
+#endif
+#define     STRING_cfAA(T,A,B)  STRING_cfCC(T,A,B)
+#define    PSTRING_cfAA(T,A,B) PSTRING_cfCC(T,A,B)
+#ifdef vmsFortran
+#define    STRINGV_cfAA(T,A,B) &B
+#else
+#ifdef CRAYFortran
+#define    STRINGV_cfAA(T,A,B) _cptofcd(B.fs,B.flen)
+#else
+#define    STRINGV_cfAA(T,A,B) B.fs
+#endif
+#endif
+#define   PSTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+#define    ZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+#define   PZTRINGV_cfAA(T,A,B) STRINGV_cfAA(T,A,B)
+
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define JCF(TN,I)
+#define KCF(TN,I)
+#else
+#define JCF(TN,I)    _(TN,_cfSTR)(1,J,_(B,I), 0,0,0,0)
+#if defined(AbsoftUNIXFortran)
+#define  DEFAULT_cfJ(B) ,0
+#else
+#define  DEFAULT_cfJ(B)
+#endif
+#define  LOGICAL_cfJ(B) DEFAULT_cfJ(B)
+#define PLOGICAL_cfJ(B) DEFAULT_cfJ(B)
+#define   STRING_cfJ(B) ,B.flen
+#define  PSTRING_cfJ(B) ,B
+#define  STRINGV_cfJ(B) STRING_cfJ(B)
+#define PSTRINGV_cfJ(B) STRING_cfJ(B)
+#define  ZTRINGV_cfJ(B) STRING_cfJ(B)
+#define PZTRINGV_cfJ(B) STRING_cfJ(B)
+
+/* KCF is identical to DCF, except that KCF ZTRING is not empty. */
+#define KCF(TN,I)    _(TN,_cfSTR)(1,KK,_(B,I), 0,0,0,0)
+#if defined(AbsoftUNIXFortran)
+#define  DEFAULT_cfKK(B) , unsigned B
+#else
+#define  DEFAULT_cfKK(B)
+#endif
+#define  LOGICAL_cfKK(B) DEFAULT_cfKK(B)
+#define PLOGICAL_cfKK(B) DEFAULT_cfKK(B)
+#define   STRING_cfKK(B) , unsigned B
+#define  PSTRING_cfKK(B) STRING_cfKK(B)
+#define  STRINGV_cfKK(B) STRING_cfKK(B)
+#define PSTRINGV_cfKK(B) STRING_cfKK(B)
+#define  ZTRINGV_cfKK(B) STRING_cfKK(B)
+#define PZTRINGV_cfKK(B) STRING_cfKK(B)
+#endif
+
+#define WCF(TN,AN,I)      _(TN,_cfSTR)(2,W,AN,_(B,I), 0,0,0)
+#define  DEFAULT_cfW(A,B)
+#define  LOGICAL_cfW(A,B)
+#define PLOGICAL_cfW(A,B) *B=F2CLOGICAL(*B);
+#define   STRING_cfW(A,B) (B.nombre=A,B.nombre[B.clen]!='\0'?B.nombre[B.clen]='\0':0); /* A?="constnt"*/
+#define  PSTRING_cfW(A,B) kill_trailing(A,' ');
+#ifdef vmsFortran
+#define  STRINGV_cfW(A,B) _cf_free(B.dsc$a_pointer);
+#define PSTRINGV_cfW(A,B)                                                      \
+  vkill_trailing(f2cstrv((char*)A, (char*)A,                                   \
+                           B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0]),     \
+                   B.dsc$w_length+1, B.dsc$l_arsize+B.dsc$l_m[0], ' ');
+#else
+#define  STRINGV_cfW(A,B) _cf_free(B.s);
+#define PSTRINGV_cfW(A,B) vkill_trailing(                                      \
+         f2cstrv((char*)A,(char*)A,B.flen+1,B.sizeofA), B.flen+1,B.sizeofA,' ');
+#endif
+#define  ZTRINGV_cfW(A,B)      STRINGV_cfW(A,B)
+#define PZTRINGV_cfW(A,B)     PSTRINGV_cfW(A,B)
+
+#define   NCF(TN,I,C)       _SEP_(TN,C,cfCOMMA) _Icf(2,N,TN,_(A,I),0) 
+#define  NNCF(TN,I,C)        UUCF(TN,I,C)
+#define NNNCF(TN,I,C)       _SEP_(TN,C,cfCOLON) _Icf(2,N,TN,_(A,I),0) 
+#define        INT_cfN(T,A) _(T,VVVVVVV_cfTYPE) * A
+#define       INTV_cfN(T,A) _(T,VVVVVV_cfTYPE)  * A
+#define      INTVV_cfN(T,A) _(T,VVVVV_cfTYPE)   * A
+#define     INTVVV_cfN(T,A) _(T,VVVV_cfTYPE)    * A
+#define    INTVVVV_cfN(T,A) _(T,VVV_cfTYPE)     * A
+#define   INTVVVVV_cfN(T,A) _(T,VV_cfTYPE)      * A
+#define  INTVVVVVV_cfN(T,A) _(T,V_cfTYPE)       * A
+#define INTVVVVVVV_cfN(T,A) _(T,_cfTYPE)        * A
+#define       PINT_cfN(T,A) _(T,_cfTYPE)        * A
+#define      PVOID_cfN(T,A) void *                A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define    ROUTINE_cfN(T,A) void (**A)(CF_NULL_PROTO)
+#else
+#define    ROUTINE_cfN(T,A) void ( *A)(CF_NULL_PROTO)
+#endif
+#ifdef vmsFortran
+#define     STRING_cfN(T,A) fstring *             A
+#define    STRINGV_cfN(T,A) fstringvector *       A
+#else
+#ifdef CRAYFortran
+#define     STRING_cfN(T,A) _fcd                  A
+#define    STRINGV_cfN(T,A) _fcd                  A
+#else
+#define     STRING_cfN(T,A) char *                A
+#define    STRINGV_cfN(T,A) char *                A
+#endif
+#endif
+#define    PSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define   PNSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define   PPSTRING_cfN(T,A)   STRING_cfN(T,A) /* CRAY insists on arg.'s here. */
+#define   PSTRINGV_cfN(T,A)  STRINGV_cfN(T,A)
+#define    ZTRINGV_cfN(T,A)  STRINGV_cfN(T,A)
+#define   PZTRINGV_cfN(T,A) PSTRINGV_cfN(T,A)
+
+
+/* Apollo 6.7, CRAY, old Sun, VAX/Ultrix vcc/cc and new ultrix
+   can't hack more than 31 arg's.
+   e.g. ultrix >= 4.3 gives message:
+       zow35> cc -c -DDECFortran cfortest.c
+       cfe: Fatal: Out of memory: cfortest.c
+       zow35>
+   Old __hpux had the problem, but new 'HP-UX A.09.03 A 9000/735' is fine
+   if using -Aa, otherwise we have a problem.
+ */
+#ifndef MAX_PREPRO_ARGS
+#if !defined(__GNUC__) && (defined(VAXUltrix) || defined(__CF__APOLLO67) || (defined(sun)&&!defined(__sun)) || defined(_CRAY) || defined(__ultrix__) || (defined(__hpux)&&defined(__CF__KnR)))
+#define MAX_PREPRO_ARGS 31
+#else
+#define MAX_PREPRO_ARGS 99
+#endif
+#endif
+
+#if defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+/* In addition to explicit Absoft stuff, only Absoft requires:
+   - DEFAULT coming from _cfSTR.
+     DEFAULT could have been called e.g. INT, but keep it for clarity.
+   - M term in CFARGT14 and CFARGT14FS.
+ */
+#define ABSOFT_cf1(T0) _(T0,_cfSTR)(0,ABSOFT1,0,0,0,0,0)
+#define ABSOFT_cf2(T0) _(T0,_cfSTR)(0,ABSOFT2,0,0,0,0,0)
+#define ABSOFT_cf3(T0) _(T0,_cfSTR)(0,ABSOFT3,0,0,0,0,0)
+#define DEFAULT_cfABSOFT1
+#define LOGICAL_cfABSOFT1
+#define  STRING_cfABSOFT1 ,MAX_LEN_FORTRAN_FUNCTION_STRING
+#define DEFAULT_cfABSOFT2
+#define LOGICAL_cfABSOFT2
+#define  STRING_cfABSOFT2 ,unsigned D0
+#define DEFAULT_cfABSOFT3
+#define LOGICAL_cfABSOFT3
+#define  STRING_cfABSOFT3 ,D0
+#else
+#define ABSOFT_cf1(T0)
+#define ABSOFT_cf2(T0)
+#define ABSOFT_cf3(T0)
+#endif
+
+/* _Z introduced to cicumvent IBM and HP silly preprocessor warning.
+   e.g. "Macro CFARGT14 invoked with a null argument."
+ */
+#define _Z
+
+#define  CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)                \
+ S(T1,1)   S(T2,2)   S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)       \
+ S(T8,8)   S(T9,9)   S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)
+#define  CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ S(T1,1)   S(T2,2)   S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)       \
+ S(T8,8)   S(T9,9)   S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)      \
+ S(TF,15)  S(TG,16)  S(TH,17)   S(TI,18)   S(TJ,19)   S(TK,20)   S(TL,21)      \
+ S(TM,22)  S(TN,23)  S(TO,24)   S(TP,25)   S(TQ,26)   S(TR,27)
+
+#define  CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)           \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)     \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)    \
+ M       CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define  CFARGT27FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
+ F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1)  \
+ F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1)             \
+ M       CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+#if !(defined(PowerStationFortran)||defined(hpuxFortran800))
+/*  Old CFARGT14 -> CFARGT14FS as seen below, for Absoft cross-compile yields:
+      SunOS> cc -c -Xa -DAbsoftUNIXFortran c.c
+      "c.c", line 406: warning: argument mismatch
+    Haven't checked if this is ANSI C or a SunOS bug. SunOS -Xs works ok.
+    Behavior is most clearly seen in example:
+      #define A 1 , 2
+      #define  C(X,Y,Z) x=X. y=Y. z=Z.
+      #define  D(X,Y,Z) C(X,Y,Z)
+      D(x,A,z)
+    Output from preprocessor is: x = x . y = 1 . z = 2 .
+ #define CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+       CFARGT14FS(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+*/
+#define  CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)             \
+ F(T1,1,0) F(T2,2,1) F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)     \
+ F(T8,8,1) F(T9,9,1) F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)    \
+ M       CFARGT14S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define  CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
+ F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1) F(TL,21,1)  \
+ F(TM,22,1) F(TN,23,1) F(TO,24,1) F(TP,25,1) F(TQ,26,1) F(TR,27,1)             \
+ M       CFARGT27S(S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+#define  CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ F(T1,1,0)  F(T2,2,1)  F(T3,3,1)  F(T4,4,1)  F(T5,5,1)  F(T6,6,1)  F(T7,7,1)   \
+ F(T8,8,1)  F(T9,9,1)  F(TA,10,1) F(TB,11,1) F(TC,12,1) F(TD,13,1) F(TE,14,1)  \
+ F(TF,15,1) F(TG,16,1) F(TH,17,1) F(TI,18,1) F(TJ,19,1) F(TK,20,1)             \
+ S(T1,1)    S(T2,2)    S(T3,3)    S(T4,4)    S(T5,5)    S(T6,6)    S(T7,7)     \
+ S(T8,8)    S(T9,9)    S(TA,10)   S(TB,11)   S(TC,12)   S(TD,13)   S(TE,14)    \
+ S(TF,15)   S(TG,16)   S(TH,17)   S(TI,18)   S(TJ,19)   S(TK,20)
+#define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
+ F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1) F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
+ F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1) F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) S(T1,1)      S(T2,2)       S(T3,3)       S(T4,4)       \
+ S(T5,5)       S(T6,6)       S(T7,7)      S(T8,8)       S(T9,9)       S(TA,10)      \
+ S(TB,11)      S(TC,12)      S(TD,13)     S(TE,14)
+#if MAX_PREPRO_ARGS>31
+#define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+ F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1)  F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
+ F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1)  F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
+ F(TJ,AJ,19,1) F(TK,AK,20,1) S(T1,1)       S(T2,2)       S(T3,3)       S(T4,4)       \
+ S(T5,5)       S(T6,6)       S(T7,7)       S(T8,8)       S(T9,9)       S(TA,10)      \
+ S(TB,11)      S(TC,12)      S(TD,13)      S(TE,14)      S(TF,15)      S(TG,16)      \
+ S(TH,17)      S(TI,18)      S(TJ,19)      S(TK,20)
+#define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+ F(T1,A1,1,0)  F(T2,A2,2,1)  F(T3,A3,3,1)  F(T4,A4,4,1)  F(T5,A5,5,1)  F(T6,A6,6,1)  \
+ F(T7,A7,7,1)  F(T8,A8,8,1)  F(T9,A9,9,1)  F(TA,AA,10,1) F(TB,AB,11,1) F(TC,AC,12,1) \
+ F(TD,AD,13,1) F(TE,AE,14,1) F(TF,AF,15,1) F(TG,AG,16,1) F(TH,AH,17,1) F(TI,AI,18,1) \
+ F(TJ,AJ,19,1) F(TK,AK,20,1) F(TL,AL,21,1) F(TM,AM,22,1) F(TN,AN,23,1) F(TO,AO,24,1) \
+ F(TP,AP,25,1) F(TQ,AQ,26,1) F(TR,AR,27,1) S(T1,1)       S(T2,2)       S(T3,3)       \
+ S(T4,4)       S(T5,5)       S(T6,6)       S(T7,7)       S(T8,8)       S(T9,9)       \
+ S(TA,10)      S(TB,11)      S(TC,12)      S(TD,13)      S(TE,14)      S(TF,15)      \
+ S(TG,16)      S(TH,17)      S(TI,18)      S(TJ,19)      S(TK,20)      S(TL,21)      \
+ S(TM,22)      S(TN,23)      S(TO,24)      S(TP,25)      S(TQ,26)      S(TR,27)
+#endif
+#else
+#define  CFARGT14(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)             \
+ F(T1,1,0) S(T1,1) F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
+ F(T5,5,1) S(T5,5) F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
+ F(T9,9,1) S(T9,9) F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14)
+#define  CFARGT27(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+ F(T1,1,0)  S(T1,1)  F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
+ F(T5,5,1)  S(T5,5)  F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
+ F(T9,9,1)  S(T9,9)  F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
+ F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20) \
+ F(TL,21,1) S(TL,21) F(TM,22,1) S(TM,22) F(TN,23,1) S(TN,23) F(TO,24,1) S(TO,24) \
+ F(TP,25,1) S(TP,25) F(TQ,26,1) S(TQ,26) F(TR,27,1) S(TR,27)
+
+#define  CFARGT20(F,S,M,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+ F(T1,1,0)  S(T1,1)  F(T2,2,1)  S(T2,2)  F(T3,3,1)  S(T3,3)  F(T4,4,1)  S(T4,4)  \
+ F(T5,5,1)  S(T5,5)  F(T6,6,1)  S(T6,6)  F(T7,7,1)  S(T7,7)  F(T8,8,1)  S(T8,8)  \
+ F(T9,9,1)  S(T9,9)  F(TA,10,1) S(TA,10) F(TB,11,1) S(TB,11) F(TC,12,1) S(TC,12) \
+ F(TD,13,1) S(TD,13) F(TE,14,1) S(TE,14) F(TF,15,1) S(TF,15) F(TG,16,1) S(TG,16) \
+ F(TH,17,1) S(TH,17) F(TI,18,1) S(TI,18) F(TJ,19,1) S(TJ,19) F(TK,20,1) S(TK,20)
+#define CFARGTA14(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) \
+ F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
+ F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
+ F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14)
+#if MAX_PREPRO_ARGS>31
+#define CFARGTA20(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+ F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
+ F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
+ F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15)          \
+ F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18)          \
+ F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20)                
+#define CFARGTA27(F,S,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+ F(T1,A1,1,0)  S(T1,1)  F(T2,A2,2,1)  S(T2,2)  F(T3,A3,3,1)  S(T3,3)           \
+ F(T4,A4,4,1)  S(T4,4)  F(T5,A5,5,1)  S(T5,5)  F(T6,A6,6,1)  S(T6,6)           \
+ F(T7,A7,7,1)  S(T7,7)  F(T8,A8,8,1)  S(T8,8)  F(T9,A9,9,1)  S(T9,9)           \
+ F(TA,AA,10,1) S(TA,10) F(TB,AB,11,1) S(TB,11) F(TC,AC,12,1) S(TC,12)          \
+ F(TD,AD,13,1) S(TD,13) F(TE,AE,14,1) S(TE,14) F(TF,AF,15,1) S(TF,15)          \
+ F(TG,AG,16,1) S(TG,16) F(TH,AH,17,1) S(TH,17) F(TI,AI,18,1) S(TI,18)          \
+ F(TJ,AJ,19,1) S(TJ,19) F(TK,AK,20,1) S(TK,20) F(TL,AL,21,1) S(TL,21)          \
+ F(TM,AM,22,1) S(TM,22) F(TN,AN,23,1) S(TN,23) F(TO,AO,24,1) S(TO,24)          \
+ F(TP,AP,25,1) S(TP,25) F(TQ,AQ,26,1) S(TQ,26) F(TR,AR,27,1) S(TR,27)
+#endif
+#endif
+
+
+#define PROTOCCALLSFSUB1( UN,LN,T1) \
+        PROTOCCALLSFSUB14(UN,LN,T1,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB2( UN,LN,T1,T2) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB3( UN,LN,T1,T2,T3) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB4( UN,LN,T1,T2,T3,T4) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define PROTOCCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+
+#define PROTOCCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
+#define PROTOCCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
+
+#define PROTOCCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
+#define PROTOCCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
+
+
+#ifndef FCALLSC_QUALIFIER
+#ifdef VISUAL_CPLUSPLUS
+#define FCALLSC_QUALIFIER __stdcall
+#else
+#define FCALLSC_QUALIFIER
+#endif
+#endif
+
+#ifdef __cplusplus
+#define CFextern extern "C"
+#else
+#define CFextern extern
+#endif
+
+
+#ifdef CFSUBASFUN
+#define PROTOCCALLSFSUB0(UN,LN) \
+   PROTOCCALLSFFUN0( VOID,UN,LN)
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+   PROTOCCALLSFFUN14(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
+   PROTOCCALLSFFUN20(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
+   PROTOCCALLSFFUN27(VOID,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#else
+/* Note: Prevent compiler warnings, null #define PROTOCCALLSFSUB14/20 after 
+   #include-ing cfortran.h if calling the FORTRAN wrapper within the same 
+   source code where the wrapper is created. */
+#define PROTOCCALLSFSUB0(UN,LN)     _(VOID,_cfPU)(CFC_(UN,LN))();
+#ifndef __CF__KnR
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT14(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) );
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)\
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT20(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) );
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)\
+ _(VOID,_cfPU)(CFC_(UN,LN))( CFARGT27(NCF,KCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) );
+#else
+#define PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)     \
+         PROTOCCALLSFSUB0(UN,LN)
+#define PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+         PROTOCCALLSFSUB0(UN,LN)
+#define PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+         PROTOCCALLSFSUB0(UN,LN)
+#endif
+#endif
+
+
+#ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+
+#define CCALLSFSUB1( UN,LN,T1,                        A1)         \
+        CCALLSFSUB5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
+#define CCALLSFSUB2( UN,LN,T1,T2,                     A1,A2)      \
+        CCALLSFSUB5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
+#define CCALLSFSUB3( UN,LN,T1,T2,T3,                  A1,A2,A3)   \
+        CCALLSFSUB5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
+#define CCALLSFSUB4( UN,LN,T1,T2,T3,T4,               A1,A2,A3,A4)\
+        CCALLSFSUB5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
+#define CCALLSFSUB5( UN,LN,T1,T2,T3,T4,T5,            A1,A2,A3,A4,A5)          \
+        CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
+#define CCALLSFSUB6( UN,LN,T1,T2,T3,T4,T5,T6,         A1,A2,A3,A4,A5,A6)       \
+        CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
+#define CCALLSFSUB7( UN,LN,T1,T2,T3,T4,T5,T6,T7,      A1,A2,A3,A4,A5,A6,A7)    \
+        CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
+#define CCALLSFSUB8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,   A1,A2,A3,A4,A5,A6,A7,A8) \
+        CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
+#define CCALLSFSUB9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
+        CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
+#define CCALLSFSUB10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
+        CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
+#define CCALLSFSUB11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
+        CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
+#define CCALLSFSUB12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
+        CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
+#define CCALLSFSUB13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
+        CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
+
+#ifdef __cplusplus
+#define CPPPROTOCLSFSUB0( UN,LN)
+#define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#else
+#define CPPPROTOCLSFSUB0(UN,LN) \
+        PROTOCCALLSFSUB0(UN,LN)
+#define CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)     \
+        PROTOCCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+        PROTOCCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+        PROTOCCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+#endif
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB0(UN,LN) CCALLSFFUN0(UN,LN)
+#define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+        CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)
+#else
+/* do{...}while(0) allows if(a==b) FORT(); else BORT(); */
+#define CCALLSFSUB0( UN,LN) do{CPPPROTOCLSFSUB0(UN,LN) CFC_(UN,LN)();}while(0)
+#define CCALLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+do{VVCF(T1,A1,B1) VVCF(T2,A2,B2) VVCF(T3,A3,B3) VVCF(T4,A4,B4) VVCF(T5,A5,B5)  \
+   VVCF(T6,A6,B6) VVCF(T7,A7,B7) VVCF(T8,A8,B8) VVCF(T9,A9,B9) VVCF(TA,AA,B10) \
+   VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14)             \
+   CPPPROTOCLSFSUB14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)          \
+   ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)                           \
+   ACF(LN,T4,A4,4)  ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)          \
+   ACF(LN,T8,A8,8)  ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11)         \
+   ACF(LN,TC,AC,12) ACF(LN,TD,AD,13) ACF(LN,TE,AE,14)                          \
+   CFC_(UN,LN)( CFARGTA14(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE) );\
+   WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)        \
+   WCF(T6,A6,6)  WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10)       \
+   WCF(TB,AB,11) WCF(TC,AC,12) WCF(TD,AD,13) WCF(TE,AE,14)      }while(0)
+#endif
+
+
+#if MAX_PREPRO_ARGS>31
+#define CCALLSFSUB15(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF)\
+        CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,0,0,0,0,0)
+#define CCALLSFSUB16(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG)\
+        CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,0,0,0,0)
+#define CCALLSFSUB17(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH)\
+        CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,0,0,0)
+#define CCALLSFSUB18(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI)\
+        CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,0,0)
+#define CCALLSFSUB19(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ)\
+        CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,0)
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+        TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+        CCALLSFFUN20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+        TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK)
+#else
+#define CCALLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH, \
+        TI,TJ,TK, A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) \
+do{VVCF(T1,A1,B1)  VVCF(T2,A2,B2)  VVCF(T3,A3,B3)  VVCF(T4,A4,B4)  VVCF(T5,A5,B5)   \
+   VVCF(T6,A6,B6)  VVCF(T7,A7,B7)  VVCF(T8,A8,B8)  VVCF(T9,A9,B9)  VVCF(TA,AA,B10)  \
+   VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15)  \
+   VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20)  \
+   CPPPROTOCLSFSUB20(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)  \
+   ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)  ACF(LN,T4,A4,4)          \
+   ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)  ACF(LN,T8,A8,8)          \
+   ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12)         \
+   ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16)         \
+   ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20)         \
+   CFC_(UN,LN)( CFARGTA20(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK) ); \
+ WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)  WCF(T6,A6,6)  \
+ WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
+ WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
+ WCF(TJ,AJ,19) WCF(TK,AK,20) }while(0)
+#endif
+#endif         /* MAX_PREPRO_ARGS */
+
+#if MAX_PREPRO_ARGS>31
+#define CCALLSFSUB21(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,0,0,0,0,0,0)
+#define CCALLSFSUB22(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,0,0,0,0,0)
+#define CCALLSFSUB23(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,0,0,0,0)
+#define CCALLSFSUB24(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,0,0,0)
+#define CCALLSFSUB25(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,0,0)
+#define CCALLSFSUB26(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ)\
+        CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,0)
+
+#ifdef CFSUBASFUN
+#define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+                           A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+        CCALLSFFUN27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+                           A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR)
+#else
+#define CCALLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR, \
+                           A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) \
+do{VVCF(T1,A1,B1)  VVCF(T2,A2,B2)  VVCF(T3,A3,B3)  VVCF(T4,A4,B4)  VVCF(T5,A5,B5)   \
+   VVCF(T6,A6,B6)  VVCF(T7,A7,B7)  VVCF(T8,A8,B8)  VVCF(T9,A9,B9)  VVCF(TA,AA,B10)  \
+   VVCF(TB,AB,B11) VVCF(TC,AC,B12) VVCF(TD,AD,B13) VVCF(TE,AE,B14) VVCF(TF,AF,B15)  \
+   VVCF(TG,AG,B16) VVCF(TH,AH,B17) VVCF(TI,AI,B18) VVCF(TJ,AJ,B19) VVCF(TK,AK,B20)  \
+   VVCF(TL,AL,B21) VVCF(TM,AM,B22) VVCF(TN,AN,B23) VVCF(TO,AO,B24) VVCF(TP,AP,B25)  \
+   VVCF(TQ,AQ,B26) VVCF(TR,AR,B27)                                                  \
+   CPPPROTOCLSFSUB27(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+   ACF(LN,T1,A1,1)  ACF(LN,T2,A2,2)  ACF(LN,T3,A3,3)  ACF(LN,T4,A4,4)          \
+   ACF(LN,T5,A5,5)  ACF(LN,T6,A6,6)  ACF(LN,T7,A7,7)  ACF(LN,T8,A8,8)          \
+   ACF(LN,T9,A9,9)  ACF(LN,TA,AA,10) ACF(LN,TB,AB,11) ACF(LN,TC,AC,12)         \
+   ACF(LN,TD,AD,13) ACF(LN,TE,AE,14) ACF(LN,TF,AF,15) ACF(LN,TG,AG,16)         \
+   ACF(LN,TH,AH,17) ACF(LN,TI,AI,18) ACF(LN,TJ,AJ,19) ACF(LN,TK,AK,20)         \
+   ACF(LN,TL,AL,21) ACF(LN,TM,AM,22) ACF(LN,TN,AN,23) ACF(LN,TO,AO,24)         \
+   ACF(LN,TP,AP,25) ACF(LN,TQ,AQ,26) ACF(LN,TR,AR,27)                          \
+   CFC_(UN,LN)( CFARGTA27(AACF,JCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,\
+                                   A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR) ); \
+ WCF(T1,A1,1)  WCF(T2,A2,2)  WCF(T3,A3,3)  WCF(T4,A4,4)  WCF(T5,A5,5)  WCF(T6,A6,6)  \
+ WCF(T7,A7,7)  WCF(T8,A8,8)  WCF(T9,A9,9)  WCF(TA,AA,10) WCF(TB,AB,11) WCF(TC,AC,12) \
+ WCF(TD,AD,13) WCF(TE,AE,14) WCF(TF,AF,15) WCF(TG,AG,16) WCF(TH,AH,17) WCF(TI,AI,18) \
+ WCF(TJ,AJ,19) WCF(TK,AK,20) WCF(TL,AL,21) WCF(TM,AM,22) WCF(TN,AN,23) WCF(TO,AO,24) \
+ WCF(TP,AP,25) WCF(TQ,AQ,26) WCF(TR,AR,27) }while(0)
+#endif
+#endif         /* MAX_PREPRO_ARGS */
+
+/*-------------------------------------------------------------------------*/
+
+/*               UTILITIES FOR C TO CALL FORTRAN FUNCTIONS                 */
+
+/*N.B. PROTOCCALLSFFUNn(..) generates code, whether or not the FORTRAN
+  function is called. Therefore, especially for creator's of C header files
+  for large FORTRAN libraries which include many functions, to reduce
+  compile time and object code size, it may be desirable to create
+  preprocessor directives to allow users to create code for only those
+  functions which they use.                                                */
+
+/* The following defines the maximum length string that a function can return.
+   Of course it may be undefine-d and re-define-d before individual
+   PROTOCCALLSFFUNn(..) as required. It would also be nice to have this derived
+   from the individual machines' limits.                                      */
+#define MAX_LEN_FORTRAN_FUNCTION_STRING 0x4FE
+
+/* The following defines a character used by CFORTRAN.H to flag the end of a
+   string coming out of a FORTRAN routine.                                 */
+#define CFORTRAN_NON_CHAR 0x7F
+
+#ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#define _SEP_(TN,C,cfCOMMA)     _(__SEP_,C)(TN,cfCOMMA)
+#define __SEP_0(TN,cfCOMMA)  
+#define __SEP_1(TN,cfCOMMA)     _Icf(2,SEP,TN,cfCOMMA,0)
+#define        INT_cfSEP(T,B) _(A,B)
+#define       INTV_cfSEP(T,B) INT_cfSEP(T,B)
+#define      INTVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define     INTVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define    INTVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define   INTVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define  INTVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define INTVVVVVVV_cfSEP(T,B) INT_cfSEP(T,B)
+#define       PINT_cfSEP(T,B) INT_cfSEP(T,B)
+#define      PVOID_cfSEP(T,B) INT_cfSEP(T,B)
+#define    ROUTINE_cfSEP(T,B) INT_cfSEP(T,B)
+#define     SIMPLE_cfSEP(T,B) INT_cfSEP(T,B)
+#define       VOID_cfSEP(T,B) INT_cfSEP(T,B)    /* For FORTRAN calls C subr.s.*/
+#define     STRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define    STRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define    PSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define   PSTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define   PNSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define   PPSTRING_cfSEP(T,B) INT_cfSEP(T,B)
+#define    ZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+#define   PZTRINGV_cfSEP(T,B) INT_cfSEP(T,B)
+                         
+#if defined(SIGNED_BYTE) || !defined(UNSIGNED_BYTE)
+#ifdef OLD_VAXC
+#define INTEGER_BYTE               char    /* Old VAXC barfs on 'signed char' */
+#else
+#define INTEGER_BYTE        signed char    /* default */
+#endif
+#else
+#define INTEGER_BYTE        unsigned char
+#endif
+#define    BYTEVVVVVVV_cfTYPE INTEGER_BYTE
+#define  DOUBLEVVVVVVV_cfTYPE DOUBLE_PRECISION 
+#define   FLOATVVVVVVV_cfTYPE FORTRAN_REAL
+#define     INTVVVVVVV_cfTYPE int
+#define LOGICALVVVVVVV_cfTYPE int
+#define    LONGVVVVVVV_cfTYPE long
+#define LONGLONGVVVVVVV_cfTYPE LONGLONG   /* added by MR December 2005 */
+#define   SHORTVVVVVVV_cfTYPE short
+#define          PBYTE_cfTYPE INTEGER_BYTE
+#define        PDOUBLE_cfTYPE DOUBLE_PRECISION 
+#define         PFLOAT_cfTYPE FORTRAN_REAL
+#define           PINT_cfTYPE int
+#define       PLOGICAL_cfTYPE int
+#define          PLONG_cfTYPE long
+#define      PLONGLONG_cfTYPE LONGLONG  /* added by MR December 2005 */
+#define         PSHORT_cfTYPE short
+
+#define CFARGS0(A,T,V,W,X,Y,Z) _3(T,_cf,A)
+#define CFARGS1(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V)
+#define CFARGS2(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W)
+#define CFARGS3(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X)
+#define CFARGS4(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y)
+#define CFARGS5(A,T,V,W,X,Y,Z) _3(T,_cf,A)(V,W,X,Y,Z)
+
+#define  _Icf(N,T,I,X,Y)                 _(I,_cfINT)(N,T,I,X,Y,0)
+#define _Icf4(N,T,I,X,Y,Z)               _(I,_cfINT)(N,T,I,X,Y,Z)
+#define           BYTE_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define         DOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INT,B,X,Y,Z,0)
+#define          FLOAT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define            INT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define        LOGICAL_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define           LONG_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define       LONGLONG_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define          SHORT_cfINT(N,A,B,X,Y,Z)        DOUBLE_cfINT(N,A,B,X,Y,Z)
+#define          PBYTE_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define        PDOUBLE_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,PINT,B,X,Y,Z,0)
+#define         PFLOAT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define           PINT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define       PLOGICAL_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define          PLONG_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define      PLONGLONG_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define         PSHORT_cfINT(N,A,B,X,Y,Z)       PDOUBLE_cfINT(N,A,B,X,Y,Z)
+#define          BYTEV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define         BYTEVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define        BYTEVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define       BYTEVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define      BYTEVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define     BYTEVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define    BYTEVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define        DOUBLEV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTV,B,X,Y,Z,0)
+#define       DOUBLEVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVV,B,X,Y,Z,0)
+#define      DOUBLEVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVV,B,X,Y,Z,0)
+#define     DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVV,B,X,Y,Z,0)
+#define    DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVV,B,X,Y,Z,0)
+#define   DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVV,B,X,Y,Z,0)
+#define  DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,INTVVVVVVV,B,X,Y,Z,0)
+#define         FLOATV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define        FLOATVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define       FLOATVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define      FLOATVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define     FLOATVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define    FLOATVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define   FLOATVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define           INTV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define          INTVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define         INTVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define        INTVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define       INTVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define      INTVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define     INTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define       LOGICALV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define      LOGICALVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define     LOGICALVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define    LOGICALVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define   LOGICALVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define  LOGICALVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define LOGICALVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define          LONGV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define         LONGVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define        LONGVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define       LONGVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define      LONGVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define     LONGVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define    LONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define      LONGLONGV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define     LONGLONGVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define    LONGLONGVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define   LONGLONGVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define  LONGLONGVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z) /* added by MR December 2005 */
+#define         SHORTV_cfINT(N,A,B,X,Y,Z)       DOUBLEV_cfINT(N,A,B,X,Y,Z)
+#define        SHORTVV_cfINT(N,A,B,X,Y,Z)      DOUBLEVV_cfINT(N,A,B,X,Y,Z)
+#define       SHORTVVV_cfINT(N,A,B,X,Y,Z)     DOUBLEVVV_cfINT(N,A,B,X,Y,Z)
+#define      SHORTVVVV_cfINT(N,A,B,X,Y,Z)    DOUBLEVVVV_cfINT(N,A,B,X,Y,Z)
+#define     SHORTVVVVV_cfINT(N,A,B,X,Y,Z)   DOUBLEVVVVV_cfINT(N,A,B,X,Y,Z)
+#define    SHORTVVVVVV_cfINT(N,A,B,X,Y,Z)  DOUBLEVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define   SHORTVVVVVVV_cfINT(N,A,B,X,Y,Z) DOUBLEVVVVVVV_cfINT(N,A,B,X,Y,Z)
+#define          PVOID_cfINT(N,A,B,X,Y,Z) _(CFARGS,N)(A,B,B,X,Y,Z,0)
+#define        ROUTINE_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+/*CRAY coughs on the first,
+  i.e. the usual trouble of not being able to
+  define macros to macros with arguments. 
+  New ultrix is worse, it coughs on all such uses.
+ */
+/*#define       SIMPLE_cfINT                    PVOID_cfINT*/
+#define         SIMPLE_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define           VOID_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define         STRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define        STRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define        PSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define       PSTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define       PNSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define       PPSTRING_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define        ZTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define       PZTRINGV_cfINT(N,A,B,X,Y,Z)         PVOID_cfINT(N,A,B,X,Y,Z)
+#define           CF_0_cfINT(N,A,B,X,Y,Z)
+                         
+
+#define   UCF(TN,I,C)  _SEP_(TN,C,cfCOMMA) _Icf(2,U,TN,_(A,I),0)
+#define  UUCF(TN,I,C)  _SEP_(TN,C,cfCOMMA) _SEP_(TN,1,I) 
+#define UUUCF(TN,I,C)  _SEP_(TN,C,cfCOLON) _Icf(2,U,TN,_(A,I),0)
+#define        INT_cfU(T,A) _(T,VVVVVVV_cfTYPE)   A
+#define       INTV_cfU(T,A) _(T,VVVVVV_cfTYPE)  * A
+#define      INTVV_cfU(T,A) _(T,VVVVV_cfTYPE)   * A
+#define     INTVVV_cfU(T,A) _(T,VVVV_cfTYPE)    * A
+#define    INTVVVV_cfU(T,A) _(T,VVV_cfTYPE)     * A
+#define   INTVVVVV_cfU(T,A) _(T,VV_cfTYPE)      * A
+#define  INTVVVVVV_cfU(T,A) _(T,V_cfTYPE)       * A
+#define INTVVVVVVV_cfU(T,A) _(T,_cfTYPE)        * A
+#define       PINT_cfU(T,A) _(T,_cfTYPE)        * A
+#define      PVOID_cfU(T,A) void  *A 
+#define    ROUTINE_cfU(T,A) void (*A)(CF_NULL_PROTO) 
+#define       VOID_cfU(T,A) void   A    /* Needed for C calls FORTRAN sub.s.  */
+#define     STRING_cfU(T,A) char  *A    /*            via VOID and wrapper.   */
+#define    STRINGV_cfU(T,A) char  *A
+#define    PSTRING_cfU(T,A) char  *A
+#define   PSTRINGV_cfU(T,A) char  *A
+#define    ZTRINGV_cfU(T,A) char  *A
+#define   PZTRINGV_cfU(T,A) char  *A
+
+/* VOID breaks U into U and UU. */
+#define       INT_cfUU(T,A) _(T,VVVVVVV_cfTYPE) A
+#define      VOID_cfUU(T,A)             /* Needed for FORTRAN calls C sub.s.  */
+#define    STRING_cfUU(T,A) const char *A
+
+
+#define      BYTE_cfPU(A)   CFextern INTEGER_BYTE      FCALLSC_QUALIFIER A
+#define    DOUBLE_cfPU(A)   CFextern DOUBLE_PRECISION  FCALLSC_QUALIFIER A
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define     FLOAT_cfPU(A)   CFextern DOUBLE_PRECISION  FCALLSC_QUALIFIER A
+#else
+#define     FLOAT_cfPU(A)   CFextern FORTRAN_REAL      FCALLSC_QUALIFIER A
+#endif
+#else				   	                   
+#define     FLOAT_cfPU(A)   CFextern FLOATFUNCTIONTYPE FCALLSC_QUALIFIER A
+#endif				   	                   
+#define       INT_cfPU(A)   CFextern int   FCALLSC_QUALIFIER   A
+#define   LOGICAL_cfPU(A)   CFextern int   FCALLSC_QUALIFIER   A
+#define      LONG_cfPU(A)   CFextern long  FCALLSC_QUALIFIER   A
+#define     SHORT_cfPU(A)   CFextern short FCALLSC_QUALIFIER   A
+#define    STRING_cfPU(A)   CFextern void  FCALLSC_QUALIFIER   A
+#define      VOID_cfPU(A)   CFextern void  FCALLSC_QUALIFIER   A
+
+#define    BYTE_cfE INTEGER_BYTE     A0;
+#define  DOUBLE_cfE DOUBLE_PRECISION A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define   FLOAT_cfE FORTRAN_REAL  A0;
+#else
+#define   FLOAT_cfE FORTRAN_REAL AA0;   FLOATFUNCTIONTYPE A0;
+#endif
+#define     INT_cfE int    A0;
+#define LOGICAL_cfE int    A0;
+#define    LONG_cfE long   A0;
+#define   SHORT_cfE short  A0;
+#define    VOID_cfE
+#ifdef vmsFortran
+#define  STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];        \
+                       static fstring A0 =                                     \
+             {MAX_LEN_FORTRAN_FUNCTION_STRING,DSC$K_DTYPE_T,DSC$K_CLASS_S,AA0};\
+               memset(AA0, CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
+                                    *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
+#else
+#ifdef CRAYFortran
+#define  STRING_cfE static char AA0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];        \
+                   static _fcd A0; *(AA0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';\
+                memset(AA0,CFORTRAN_NON_CHAR, MAX_LEN_FORTRAN_FUNCTION_STRING);\
+                            A0 = _cptofcd(AA0,MAX_LEN_FORTRAN_FUNCTION_STRING);
+#else
+/* 'cc: SC3.0.1 13 Jul 1994' barfs on char A0[0x4FE+1]; 
+ * char A0[0x4FE +1]; char A0[1+0x4FE]; are both OK.     */
+#define STRING_cfE static char A0[1+MAX_LEN_FORTRAN_FUNCTION_STRING];          \
+                       memset(A0, CFORTRAN_NON_CHAR,                           \
+                              MAX_LEN_FORTRAN_FUNCTION_STRING);                \
+                       *(A0+MAX_LEN_FORTRAN_FUNCTION_STRING)='\0';
+#endif
+#endif
+/* ESTRING must use static char. array which is guaranteed to exist after
+   function returns.                                                     */
+
+/* N.B.i) The diff. for 0 (Zero) and >=1 arguments.
+       ii)That the following create an unmatched bracket, i.e. '(', which
+          must of course be matched in the call.
+       iii)Commas must be handled very carefully                         */
+#define    INT_cfGZ(T,UN,LN) A0=CFC_(UN,LN)(
+#define   VOID_cfGZ(T,UN,LN)    CFC_(UN,LN)(
+#ifdef vmsFortran
+#define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)(&A0
+#else
+#if defined(CRAYFortran) || defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)( A0
+#else
+#define STRING_cfGZ(T,UN,LN)    CFC_(UN,LN)( A0,MAX_LEN_FORTRAN_FUNCTION_STRING
+#endif
+#endif
+
+#define     INT_cfG(T,UN,LN)    INT_cfGZ(T,UN,LN)
+#define    VOID_cfG(T,UN,LN)   VOID_cfGZ(T,UN,LN)
+#define  STRING_cfG(T,UN,LN) STRING_cfGZ(T,UN,LN), /*, is only diff. from _cfG*/
+
+#define    BYTEVVVVVVV_cfPP
+#define     INTVVVVVVV_cfPP     /* These complement FLOATVVVVVVV_cfPP. */
+#define  DOUBLEVVVVVVV_cfPP
+#define LOGICALVVVVVVV_cfPP
+#define    LONGVVVVVVV_cfPP
+#define   SHORTVVVVVVV_cfPP
+#define          PBYTE_cfPP
+#define           PINT_cfPP
+#define        PDOUBLE_cfPP
+#define       PLOGICAL_cfPP
+#define          PLONG_cfPP
+#define         PSHORT_cfPP
+#define         PFLOAT_cfPP FLOATVVVVVVV_cfPP
+
+#define BCF(TN,AN,C)        _SEP_(TN,C,cfCOMMA) _Icf(2,B,TN,AN,0)
+#define        INT_cfB(T,A) (_(T,VVVVVVV_cfTYPE)) A
+#define       INTV_cfB(T,A)            A
+#define      INTVV_cfB(T,A)           (A)[0]
+#define     INTVVV_cfB(T,A)           (A)[0][0]
+#define    INTVVVV_cfB(T,A)           (A)[0][0][0]
+#define   INTVVVVV_cfB(T,A)           (A)[0][0][0][0]
+#define  INTVVVVVV_cfB(T,A)           (A)[0][0][0][0][0]
+#define INTVVVVVVV_cfB(T,A)           (A)[0][0][0][0][0][0]
+#define       PINT_cfB(T,A) _(T,_cfPP)&A
+#define     STRING_cfB(T,A) (char *)   A
+#define    STRINGV_cfB(T,A) (char *)   A
+#define    PSTRING_cfB(T,A) (char *)   A
+#define   PSTRINGV_cfB(T,A) (char *)   A
+#define      PVOID_cfB(T,A) (void *)   A
+#define    ROUTINE_cfB(T,A) (cfCAST_FUNCTION)A
+#define    ZTRINGV_cfB(T,A) (char *)   A
+#define   PZTRINGV_cfB(T,A) (char *)   A
+                                                              	
+#define SCF(TN,NAME,I,A)    _(TN,_cfSTR)(3,S,NAME,I,A,0,0)
+#define  DEFAULT_cfS(M,I,A)
+#define  LOGICAL_cfS(M,I,A)
+#define PLOGICAL_cfS(M,I,A)
+#define   STRING_cfS(M,I,A) ,sizeof(A)
+#define  STRINGV_cfS(M,I,A) ,( (unsigned)0xFFFF*firstindexlength(A) \
+                              +secondindexlength(A))
+#define  PSTRING_cfS(M,I,A) ,sizeof(A)
+#define PSTRINGV_cfS(M,I,A) STRINGV_cfS(M,I,A)
+#define  ZTRINGV_cfS(M,I,A)
+#define PZTRINGV_cfS(M,I,A)
+
+#define   HCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOMMA, H,_(C,I),0,0)
+#define  HHCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOMMA,HH,_(C,I),0,0)
+#define HHHCF(TN,I)         _(TN,_cfSTR)(3,H,cfCOLON, H,_(C,I),0,0)
+#define  H_CF_SPECIAL       unsigned
+#define HH_CF_SPECIAL
+#define  DEFAULT_cfH(M,I,A)
+#define  LOGICAL_cfH(S,U,B)
+#define PLOGICAL_cfH(S,U,B)
+#define   STRING_cfH(S,U,B) _(A,S) _(U,_CF_SPECIAL) B
+#define  STRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
+#define  PSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PSTRINGV_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PNSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define PPSTRING_cfH(S,U,B) STRING_cfH(S,U,B)
+#define  ZTRINGV_cfH(S,U,B)
+#define PZTRINGV_cfH(S,U,B)
+
+/* Need VOID_cfSTR because Absoft forced function types go through _cfSTR. */
+/* No spaces inside expansion. They screws up macro catenation kludge.     */
+#define           VOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define           BYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         DOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define          FLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define            INT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        LOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,LOGICAL,A,B,C,D,E)
+#define           LONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       LONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define          SHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define          BYTEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         BYTEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        BYTEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       BYTEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      BYTEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     BYTEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    BYTEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        DOUBLEV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       DOUBLEVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      DOUBLEVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     DOUBLEVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    DOUBLEVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define   DOUBLEVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define  DOUBLEVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         FLOATV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        FLOATVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       FLOATVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      FLOATVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     FLOATVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    FLOATVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define   FLOATVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define           INTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define          INTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         INTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        INTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       INTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      INTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     INTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       LOGICALV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      LOGICALVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     LOGICALVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    LOGICALVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define   LOGICALVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define  LOGICALVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define LOGICALVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define          LONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         LONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        LONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       LONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      LONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     LONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    LONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      LONGLONGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define     LONGLONGVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define    LONGLONGVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define   LONGLONGVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define  LONGLONGVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define         SHORTV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        SHORTVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       SHORTVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      SHORTVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define     SHORTVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define    SHORTVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define   SHORTVVVVVVV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define          PBYTE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        PDOUBLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         PFLOAT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define           PINT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define       PLOGICAL_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PLOGICAL,A,B,C,D,E)
+#define          PLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define      PLONGLONG_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E) /* added by MR December 2005 */
+#define         PSHORT_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         STRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRING,A,B,C,D,E)
+#define        PSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRING,A,B,C,D,E)
+#define        STRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,STRINGV,A,B,C,D,E)
+#define       PSTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PSTRINGV,A,B,C,D,E)
+#define       PNSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PNSTRING,A,B,C,D,E)
+#define       PPSTRING_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PPSTRING,A,B,C,D,E)
+#define          PVOID_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        ROUTINE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define         SIMPLE_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,DEFAULT,A,B,C,D,E)
+#define        ZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,ZTRINGV,A,B,C,D,E)
+#define       PZTRINGV_cfSTR(N,T,A,B,C,D,E) _(CFARGS,N)(T,PZTRINGV,A,B,C,D,E)
+#define           CF_0_cfSTR(N,T,A,B,C,D,E)
+
+/* See ACF table comments, which explain why CCF was split into two. */
+#define CCF(NAME,TN,I)     _(TN,_cfSTR)(5,C,NAME,I,_(A,I),_(B,I),_(C,I))
+#define  DEFAULT_cfC(M,I,A,B,C)
+#define  LOGICAL_cfC(M,I,A,B,C)  A=C2FLOGICAL( A);
+#define PLOGICAL_cfC(M,I,A,B,C) *A=C2FLOGICAL(*A);
+#ifdef vmsFortran
+#define   STRING_cfC(M,I,A,B,C) (B.clen=strlen(A),B.f.dsc$a_pointer=A,         \
+        C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.f.dsc$w_length=B.clen:     \
+          (memset((A)+B.clen,' ',C-B.clen-1),A[B.f.dsc$w_length=C-1]='\0'));
+      /* PSTRING_cfC to beware of array A which does not contain any \0.      */
+#define  PSTRING_cfC(M,I,A,B,C) (B.dsc$a_pointer=A, C==sizeof(char*) ?         \
+             B.dsc$w_length=strlen(A):  (A[C-1]='\0',B.dsc$w_length=strlen(A), \
+       (unsigned)memset((A)+B.dsc$w_length,' ',C-B.dsc$w_length-1), B.dsc$w_length=C-1));
+#else
+#define   STRING_cfC(M,I,A,B,C) (B.nombre=A,B.clen=(unsigned)strlen(A),                             \
+                C==sizeof(char*)||C==(unsigned)(B.clen+1)?B.flen=B.clen:       \
+                        (unsigned)(memset(B.nombre+B.clen,' ',C-B.clen-1),B.nombre[B.flen=C-1]='\0'));
+#define  PSTRING_cfC(M,I,A,B,C) (C==sizeof(char*)? B=strlen(A):                \
+                    (A[C-1]='\0',B=strlen(A),memset((A)+B,' ',C-B-1),B=C-1));
+#endif
+          /* For CRAYFortran for (P)STRINGV_cfC, B.fs is set, but irrelevant. */
+#define  STRINGV_cfC(M,I,A,B,C) \
+        AATRINGV_cfA(    A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
+#define PSTRINGV_cfC(M,I,A,B,C) \
+       APATRINGV_cfA(    A,B,(C/0xFFFF)*(C%0xFFFF),C/0xFFFF,C%0xFFFF)
+#define  ZTRINGV_cfC(M,I,A,B,C) \
+        AATRINGV_cfA(    A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1),       \
+                              (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1   )
+#define PZTRINGV_cfC(M,I,A,B,C) \
+       APATRINGV_cfA(    A,B, (_3(M,_ELEMS_,I))*((_3(M,_ELEMLEN_,I))+1),       \
+                              (_3(M,_ELEMS_,I)), (_3(M,_ELEMLEN_,I))+1   )
+
+#define     BYTE_cfCCC(A,B) &A
+#define   DOUBLE_cfCCC(A,B) &A
+#if !defined(__CF__KnR)
+#define    FLOAT_cfCCC(A,B) &A
+                               /* Although the VAX doesn't, at least the      */
+#else                          /* HP and K&R mips promote float arg.'s of     */
+#define    FLOAT_cfCCC(A,B) &B /* unprototyped functions to double. Cannot    */
+#endif                         /* use A here to pass the argument to FORTRAN. */
+#define      INT_cfCCC(A,B) &A
+#define  LOGICAL_cfCCC(A,B) &A
+#define     LONG_cfCCC(A,B) &A
+#define    SHORT_cfCCC(A,B) &A
+#define    PBYTE_cfCCC(A,B)  A
+#define  PDOUBLE_cfCCC(A,B)  A
+#define   PFLOAT_cfCCC(A,B)  A
+#define     PINT_cfCCC(A,B)  A
+#define PLOGICAL_cfCCC(A,B)  B=A       /* B used to keep a common W table. */
+#define    PLONG_cfCCC(A,B)  A
+#define   PSHORT_cfCCC(A,B)  A
+
+#define CCCF(TN,I,M)           _SEP_(TN,M,cfCOMMA) _Icf(3,CC,TN,_(A,I),_(B,I))
+#define        INT_cfCC(T,A,B) _(T,_cfCCC)(A,B) 
+#define       INTV_cfCC(T,A,B)  A
+#define      INTVV_cfCC(T,A,B)  A
+#define     INTVVV_cfCC(T,A,B)  A
+#define    INTVVVV_cfCC(T,A,B)  A
+#define   INTVVVVV_cfCC(T,A,B)  A
+#define  INTVVVVVV_cfCC(T,A,B)  A
+#define INTVVVVVVV_cfCC(T,A,B)  A
+#define       PINT_cfCC(T,A,B) _(T,_cfCCC)(A,B) 
+#define      PVOID_cfCC(T,A,B)  A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define    ROUTINE_cfCC(T,A,B) &A
+#else
+#define    ROUTINE_cfCC(T,A,B)  A
+#endif
+#define     SIMPLE_cfCC(T,A,B)  A
+#ifdef vmsFortran
+#define     STRING_cfCC(T,A,B) &B.f
+#define    STRINGV_cfCC(T,A,B) &B
+#define    PSTRING_cfCC(T,A,B) &B
+#define   PSTRINGV_cfCC(T,A,B) &B
+#else
+#ifdef CRAYFortran
+#define     STRING_cfCC(T,A,B) _cptofcd(A,B.flen)
+#define    STRINGV_cfCC(T,A,B) _cptofcd(B.s,B.flen)
+#define    PSTRING_cfCC(T,A,B) _cptofcd(A,B)
+#define   PSTRINGV_cfCC(T,A,B) _cptofcd(A,B.flen)
+#else
+#define     STRING_cfCC(T,A,B)  A
+#define    STRINGV_cfCC(T,A,B)  B.fs
+#define    PSTRING_cfCC(T,A,B)  A
+#define   PSTRINGV_cfCC(T,A,B)  B.fs
+#endif
+#endif
+#define    ZTRINGV_cfCC(T,A,B)   STRINGV_cfCC(T,A,B)
+#define   PZTRINGV_cfCC(T,A,B)  PSTRINGV_cfCC(T,A,B)
+
+#define    BYTE_cfX  return A0;
+#define  DOUBLE_cfX  return A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define   FLOAT_cfX  return A0;
+#else
+#define   FLOAT_cfX  ASSIGNFLOAT(AA0,A0); return AA0;
+#endif
+#define     INT_cfX  return A0;
+#define LOGICAL_cfX  return F2CLOGICAL(A0);
+#define    LONG_cfX  return A0;
+#define   SHORT_cfX  return A0;
+#define    VOID_cfX  return   ;
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define  STRING_cfX  return kill_trailing(                                     \
+                                      kill_trailing(AA0,CFORTRAN_NON_CHAR),' ');
+#else
+#define  STRING_cfX  return kill_trailing(                                     \
+                                      kill_trailing( A0,CFORTRAN_NON_CHAR),' ');
+#endif
+
+#define CFFUN(NAME) _(__cf__,NAME)
+
+/* Note that we don't use LN here, but we keep it for consistency. */
+#define CCALLSFFUN0(UN,LN) CFFUN(UN)()
+
+#ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+#define CCALLSFFUN1( UN,LN,T1,                        A1)         \
+        CCALLSFFUN5 (UN,LN,T1,CF_0,CF_0,CF_0,CF_0,A1,0,0,0,0)
+#define CCALLSFFUN2( UN,LN,T1,T2,                     A1,A2)      \
+        CCALLSFFUN5 (UN,LN,T1,T2,CF_0,CF_0,CF_0,A1,A2,0,0,0)
+#define CCALLSFFUN3( UN,LN,T1,T2,T3,                  A1,A2,A3)   \
+        CCALLSFFUN5 (UN,LN,T1,T2,T3,CF_0,CF_0,A1,A2,A3,0,0)
+#define CCALLSFFUN4( UN,LN,T1,T2,T3,T4,               A1,A2,A3,A4)\
+        CCALLSFFUN5 (UN,LN,T1,T2,T3,T4,CF_0,A1,A2,A3,A4,0)
+#define CCALLSFFUN5( UN,LN,T1,T2,T3,T4,T5,            A1,A2,A3,A4,A5)          \
+        CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,0,0,0,0,0)
+#define CCALLSFFUN6( UN,LN,T1,T2,T3,T4,T5,T6,         A1,A2,A3,A4,A5,A6)       \
+        CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,0,0,0,0)
+#define CCALLSFFUN7( UN,LN,T1,T2,T3,T4,T5,T6,T7,      A1,A2,A3,A4,A5,A6,A7)    \
+        CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,0,0,0)
+#define CCALLSFFUN8( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,   A1,A2,A3,A4,A5,A6,A7,A8) \
+        CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,0,0)
+#define CCALLSFFUN9( UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,A1,A2,A3,A4,A5,A6,A7,A8,A9)\
+        CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,0)
+#define CCALLSFFUN10(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA)\
+        CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,0,0,0,0)
+#define CCALLSFFUN11(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB)\
+        CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,0,0,0)
+#define CCALLSFFUN12(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC)\
+        CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,0,0)
+#define CCALLSFFUN13(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD)\
+        CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,0)
+
+#define CCALLSFFUN14(UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,A1,A2,A3,A4,A5,A6,A7,A8,A9,AA,AB,AC,AD,AE)\
+((CFFUN(UN)(  BCF(T1,A1,0) BCF(T2,A2,1) BCF(T3,A3,1) BCF(T4,A4,1) BCF(T5,A5,1) \
+              BCF(T6,A6,1) BCF(T7,A7,1) BCF(T8,A8,1) BCF(T9,A9,1) BCF(TA,AA,1) \
+              BCF(TB,AB,1) BCF(TC,AC,1) BCF(TD,AD,1) BCF(TE,AE,1)              \
+           SCF(T1,LN,1,A1)  SCF(T2,LN,2,A2)  SCF(T3,LN,3,A3)  SCF(T4,LN,4,A4)  \
+           SCF(T5,LN,5,A5)  SCF(T6,LN,6,A6)  SCF(T7,LN,7,A7)  SCF(T8,LN,8,A8)  \
+           SCF(T9,LN,9,A9)  SCF(TA,LN,10,AA) SCF(TB,LN,11,AB) SCF(TC,LN,12,AC) \
+           SCF(TD,LN,13,AD) SCF(TE,LN,14,AE))))
+
+/*  N.B. Create a separate function instead of using (call function, function
+value here) because in order to create the variables needed for the input
+arg.'s which may be const.'s one has to do the creation within {}, but these
+can never be placed within ()'s. Therefore one must create wrapper functions.
+gcc, on the other hand may be able to avoid the wrapper functions. */
+
+/* Prototypes are needed to correctly handle the value returned correctly. N.B.
+Can only have prototype arg.'s with difficulty, a la G... table since FORTRAN
+functions returning strings have extra arg.'s. Don't bother, since this only
+causes a compiler warning to come up when one uses FCALLSCFUNn and CCALLSFFUNn
+for the same function in the same source code. Something done by the experts in
+debugging only.*/    
+
+#define PROTOCCALLSFFUN0(F,UN,LN)                                              \
+_(F,_cfPU)( CFC_(UN,LN))(CF_NULL_PROTO);                                       \
+static _Icf(2,U,F,CFFUN(UN),0)() {_(F,_cfE) _Icf(3,GZ,F,UN,LN) ABSOFT_cf1(F));_(F,_cfX)}
+
+#define PROTOCCALLSFFUN1( T0,UN,LN,T1)                                         \
+        PROTOCCALLSFFUN5 (T0,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN2( T0,UN,LN,T1,T2)                                      \
+        PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN3( T0,UN,LN,T1,T2,T3)                                   \
+        PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,CF_0,CF_0)
+#define PROTOCCALLSFFUN4( T0,UN,LN,T1,T2,T3,T4)                                \
+        PROTOCCALLSFFUN5 (T0,UN,LN,T1,T2,T3,T4,CF_0)
+#define PROTOCCALLSFFUN5( T0,UN,LN,T1,T2,T3,T4,T5)                             \
+        PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN6( T0,UN,LN,T1,T2,T3,T4,T5,T6)                          \
+        PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN7( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7)                       \
+        PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN8( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8)                    \
+        PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
+#define PROTOCCALLSFFUN9( T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9)                 \
+        PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
+#define PROTOCCALLSFFUN10(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA)              \
+        PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN11(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB)           \
+        PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define PROTOCCALLSFFUN12(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC)        \
+        PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define PROTOCCALLSFFUN13(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD)     \
+        PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+/* HP/UX 9.01 cc requires the blank between '_Icf(3,G,T0,UN,LN) CCCF(T1,1,0)' */
+
+#ifndef __CF__KnR
+#define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  \
+ _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)(     \
+   CFARGT14FS(UCF,HCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )          \
+{       CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    _(T0,_cfE) \
+ CCF(LN,T1,1)  CCF(LN,T2,2)  CCF(LN,T3,3)  CCF(LN,T4,4)  CCF(LN,T5,5)          \
+ CCF(LN,T6,6)  CCF(LN,T7,7)  CCF(LN,T8,8)  CCF(LN,T9,9)  CCF(LN,TA,10)         \
+ CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14)    _Icf(3,G,T0,UN,LN) \
+ CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
+ WCF(T1,A1,1)   WCF(T2,A2,2)   WCF(T3,A3,3)   WCF(T4,A4,4)  WCF(T5,A5,5)       \
+ WCF(T6,A6,6)   WCF(T7,A7,7)   WCF(T8,A8,8)   WCF(T9,A9,9)  WCF(TA,A10,10)     \
+ WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
+#else
+#define PROTOCCALLSFFUN14(T0,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  \
+ _(T0,_cfPU)(CFC_(UN,LN))(CF_NULL_PROTO); static _Icf(2,U,T0,CFFUN(UN),0)(     \
+   CFARGT14FS(UUCF,HHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )        \
+ CFARGT14FS(UUUCF,HHHCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) ;        \
+{       CFARGT14S(VCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    _(T0,_cfE) \
+ CCF(LN,T1,1)  CCF(LN,T2,2)  CCF(LN,T3,3)  CCF(LN,T4,4)  CCF(LN,T5,5)          \
+ CCF(LN,T6,6)  CCF(LN,T7,7)  CCF(LN,T8,8)  CCF(LN,T9,9)  CCF(LN,TA,10)         \
+ CCF(LN,TB,11) CCF(LN,TC,12) CCF(LN,TD,13) CCF(LN,TE,14)    _Icf(3,G,T0,UN,LN) \
+ CFARGT14(CCCF,JCF,ABSOFT_cf1(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)); \
+ WCF(T1,A1,1)   WCF(T2,A2,2)   WCF(T3,A3,3)   WCF(T4,A4,4)   WCF(T5,A5,5)      \
+ WCF(T6,A6,6)   WCF(T7,A7,7)   WCF(T8,A8,8)   WCF(T9,A9,9)   WCF(TA,A10,10)    \
+ WCF(TB,A11,11) WCF(TC,A12,12) WCF(TD,A13,13) WCF(TE,A14,14) _(T0,_cfX)}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*               UTILITIES FOR FORTRAN TO CALL C ROUTINES                  */
+
+#ifdef OLD_VAXC                                /* Prevent %CC-I-PARAMNOTUSED. */
+#pragma nostandard
+#endif
+
+#if defined(vmsFortran) || defined(CRAYFortran)
+#define   DCF(TN,I)
+#define  DDCF(TN,I)
+#define DDDCF(TN,I)
+#else
+#define   DCF(TN,I)          HCF(TN,I)
+#define  DDCF(TN,I)         HHCF(TN,I)
+#define DDDCF(TN,I)        HHHCF(TN,I)
+#endif
+
+#define QCF(TN,I)       _(TN,_cfSTR)(1,Q,_(B,I), 0,0,0,0)
+#define  DEFAULT_cfQ(B)
+#define  LOGICAL_cfQ(B)
+#define PLOGICAL_cfQ(B)
+#define  STRINGV_cfQ(B) char *B; unsigned int _(B,N);
+#define   STRING_cfQ(B) char *B=NULL;
+#define  PSTRING_cfQ(B) char *B=NULL;
+#define PSTRINGV_cfQ(B) STRINGV_cfQ(B)
+#define PNSTRING_cfQ(B) char *B=NULL;
+#define PPSTRING_cfQ(B)
+
+#ifdef     __sgi   /* Else SGI gives warning 182 contrary to its C LRM A.17.7 */
+#define ROUTINE_orig    *(void**)& 
+#else
+#define ROUTINE_orig     (void *)  
+#endif
+
+#define ROUTINE_1     ROUTINE_orig   
+#define ROUTINE_2     ROUTINE_orig   
+#define ROUTINE_3     ROUTINE_orig   
+#define ROUTINE_4     ROUTINE_orig   
+#define ROUTINE_5     ROUTINE_orig   
+#define ROUTINE_6     ROUTINE_orig   
+#define ROUTINE_7     ROUTINE_orig   
+#define ROUTINE_8     ROUTINE_orig   
+#define ROUTINE_9     ROUTINE_orig   
+#define ROUTINE_10    ROUTINE_orig   
+#define ROUTINE_11    ROUTINE_orig   
+#define ROUTINE_12    ROUTINE_orig   
+#define ROUTINE_13    ROUTINE_orig   
+#define ROUTINE_14    ROUTINE_orig   
+#define ROUTINE_15    ROUTINE_orig   
+#define ROUTINE_16    ROUTINE_orig   
+#define ROUTINE_17    ROUTINE_orig   
+#define ROUTINE_18    ROUTINE_orig   
+#define ROUTINE_19    ROUTINE_orig   
+#define ROUTINE_20    ROUTINE_orig   
+#define ROUTINE_21    ROUTINE_orig   
+#define ROUTINE_22    ROUTINE_orig   
+#define ROUTINE_23    ROUTINE_orig   
+#define ROUTINE_24    ROUTINE_orig   
+#define ROUTINE_25    ROUTINE_orig   
+#define ROUTINE_26    ROUTINE_orig   
+#define ROUTINE_27    ROUTINE_orig   
+
+#define TCF(NAME,TN,I,M)              _SEP_(TN,M,cfCOMMA) _(TN,_cfT)(NAME,I,_(A,I),_(B,I),_(C,I))
+#define           BYTE_cfT(M,I,A,B,D) *A
+#define         DOUBLE_cfT(M,I,A,B,D) *A
+#define          FLOAT_cfT(M,I,A,B,D) *A
+#define            INT_cfT(M,I,A,B,D) *A
+#define        LOGICAL_cfT(M,I,A,B,D)  F2CLOGICAL(*A)
+#define           LONG_cfT(M,I,A,B,D) *A
+#define       LONGLONG_cfT(M,I,A,B,D) *A /* added by MR December 2005 */
+#define          SHORT_cfT(M,I,A,B,D) *A
+#define          BYTEV_cfT(M,I,A,B,D)  A
+#define        DOUBLEV_cfT(M,I,A,B,D)  A
+#define         FLOATV_cfT(M,I,A,B,D)  VOIDP A
+#define           INTV_cfT(M,I,A,B,D)  A
+#define       LOGICALV_cfT(M,I,A,B,D)  A
+#define          LONGV_cfT(M,I,A,B,D)  A
+#define      LONGLONGV_cfT(M,I,A,B,D)  A /* added by MR December 2005 */
+#define         SHORTV_cfT(M,I,A,B,D)  A
+#define         BYTEVV_cfT(M,I,A,B,D)  (void *)A /* We have to cast to void *,*/
+#define        BYTEVVV_cfT(M,I,A,B,D)  (void *)A /* since we don't know the   */
+#define       BYTEVVVV_cfT(M,I,A,B,D)  (void *)A /* dimensions of the array.  */
+#define      BYTEVVVVV_cfT(M,I,A,B,D)  (void *)A /* i.e. Unfortunately, can't */
+#define     BYTEVVVVVV_cfT(M,I,A,B,D)  (void *)A /* check that the type       */
+#define    BYTEVVVVVVV_cfT(M,I,A,B,D)  (void *)A /* matches the prototype.    */
+#define       DOUBLEVV_cfT(M,I,A,B,D)  (void *)A
+#define      DOUBLEVVV_cfT(M,I,A,B,D)  (void *)A
+#define     DOUBLEVVVV_cfT(M,I,A,B,D)  (void *)A
+#define    DOUBLEVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define   DOUBLEVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define  DOUBLEVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define        FLOATVV_cfT(M,I,A,B,D)  (void *)A
+#define       FLOATVVV_cfT(M,I,A,B,D)  (void *)A
+#define      FLOATVVVV_cfT(M,I,A,B,D)  (void *)A
+#define     FLOATVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define    FLOATVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define   FLOATVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define          INTVV_cfT(M,I,A,B,D)  (void *)A  
+#define         INTVVV_cfT(M,I,A,B,D)  (void *)A  
+#define        INTVVVV_cfT(M,I,A,B,D)  (void *)A  
+#define       INTVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define      INTVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define     INTVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define      LOGICALVV_cfT(M,I,A,B,D)  (void *)A
+#define     LOGICALVVV_cfT(M,I,A,B,D)  (void *)A
+#define    LOGICALVVVV_cfT(M,I,A,B,D)  (void *)A
+#define   LOGICALVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define  LOGICALVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define LOGICALVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define         LONGVV_cfT(M,I,A,B,D)  (void *)A
+#define        LONGVVV_cfT(M,I,A,B,D)  (void *)A
+#define       LONGVVVV_cfT(M,I,A,B,D)  (void *)A
+#define      LONGVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define     LONGVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define    LONGVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define     LONGLONGVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define    LONGLONGVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define   LONGLONGVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define  LONGLONGVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define LONGLONGVVVVVVV_cfT(M,I,A,B,D)  (void *)A /* added by MR December 2005 */
+#define        SHORTVV_cfT(M,I,A,B,D)  (void *)A
+#define       SHORTVVV_cfT(M,I,A,B,D)  (void *)A
+#define      SHORTVVVV_cfT(M,I,A,B,D)  (void *)A
+#define     SHORTVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define    SHORTVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define   SHORTVVVVVVV_cfT(M,I,A,B,D)  (void *)A
+#define          PBYTE_cfT(M,I,A,B,D)  A
+#define        PDOUBLE_cfT(M,I,A,B,D)  A
+#define         PFLOAT_cfT(M,I,A,B,D)  VOIDP A
+#define           PINT_cfT(M,I,A,B,D)  A
+#define       PLOGICAL_cfT(M,I,A,B,D)  ((*A=F2CLOGICAL(*A)),A)
+#define          PLONG_cfT(M,I,A,B,D)  A
+#define      PLONGLONG_cfT(M,I,A,B,D)  A /* added by MR December 2005 */
+#define         PSHORT_cfT(M,I,A,B,D)  A
+#define          PVOID_cfT(M,I,A,B,D)  A
+#if defined(apolloFortran) || defined(hpuxFortran800) || defined(AbsoftUNIXFortran)
+#define        ROUTINE_cfT(M,I,A,B,D)  _(ROUTINE_,I)  (*A)
+#else
+#define        ROUTINE_cfT(M,I,A,B,D)  _(ROUTINE_,I)    A
+#endif
+/* A == pointer to the characters
+   D == length of the string, or of an element in an array of strings
+   E == number of elements in an array of strings                             */
+#define TTSTR(    A,B,D)                                                       \
+           ((B=_cf_malloc(D+1))[D]='\0', memcpy(B,A,D), kill_trailing(B,' '))
+#define TTTTSTR(  A,B,D)   (!(D<4||A[0]||A[1]||A[2]||A[3]))?NULL:              \
+                            memchr(A,'\0',D)                 ?A   : TTSTR(A,B,D)
+#define TTTTSTRV( A,B,D,E) (_(B,N)=E,B=_cf_malloc(_(B,N)*(D+1)), (void *)      \
+  vkill_trailing(f2cstrv(A,B,D+1, _(B,N)*(D+1)), D+1,_(B,N)*(D+1),' '))
+#ifdef vmsFortran
+#define         STRING_cfT(M,I,A,B,D)  TTTTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(A->dsc$a_pointer, B,           \
+                                             A->dsc$w_length , A->dsc$l_m[0])
+#define        PSTRING_cfT(M,I,A,B,D)    TTSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define       PPSTRING_cfT(M,I,A,B,D)           A->dsc$a_pointer
+#else
+#ifdef CRAYFortran
+#define         STRING_cfT(M,I,A,B,D)  TTTTSTR( _fcdtocp(A),B,_fcdlen(A))
+#define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(_fcdtocp(A),B,_fcdlen(A),      \
+                              num_elem(_fcdtocp(A),_fcdlen(A),_3(M,_STRV_A,I)))
+#define        PSTRING_cfT(M,I,A,B,D)    TTSTR( _fcdtocp(A),B,_fcdlen(A))
+#define       PPSTRING_cfT(M,I,A,B,D)           _fcdtocp(A)
+#else
+#define         STRING_cfT(M,I,A,B,D)  TTTTSTR( A,B,D)
+#define        STRINGV_cfT(M,I,A,B,D)  TTTTSTRV(A,B,D, num_elem(A,D,_3(M,_STRV_A,I)))
+#define        PSTRING_cfT(M,I,A,B,D)    TTSTR( A,B,D)
+#define       PPSTRING_cfT(M,I,A,B,D)           ((void)D, A)
+#endif
+#endif
+#define       PNSTRING_cfT(M,I,A,B,D)    STRING_cfT(M,I,A,B,D)
+#define       PSTRINGV_cfT(M,I,A,B,D)   STRINGV_cfT(M,I,A,B,D)
+#define           CF_0_cfT(M,I,A,B,D)
+
+#define RCF(TN,I)           _(TN,_cfSTR)(3,R,_(A,I),_(B,I),_(C,I),0,0)
+#define  DEFAULT_cfR(A,B,D)
+#define  LOGICAL_cfR(A,B,D)
+#define PLOGICAL_cfR(A,B,D) *A=C2FLOGICAL(*A);
+#define   STRING_cfR(A,B,D) if (B) _cf_free(B);
+#define  STRINGV_cfR(A,B,D) _cf_free(B);
+/* A and D as defined above for TSTRING(V) */
+#define RRRRPSTR( A,B,D)    if (B) memcpy(A,B, _cfMIN(strlen(B),D)),           \
+                  (D>strlen(B)?memset(A+strlen(B),' ', D-strlen(B)):0), _cf_free(B);
+#define RRRRPSTRV(A,B,D)    c2fstrv(B,A,D+1,(D+1)*_(B,N)), _cf_free(B);
+#ifdef vmsFortran
+#define  PSTRING_cfR(A,B,D) RRRRPSTR( A->dsc$a_pointer,B,A->dsc$w_length)
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A->dsc$a_pointer,B,A->dsc$w_length)
+#else
+#ifdef CRAYFortran
+#define  PSTRING_cfR(A,B,D) RRRRPSTR( _fcdtocp(A),B,_fcdlen(A))
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(_fcdtocp(A),B,_fcdlen(A))
+#else
+#define  PSTRING_cfR(A,B,D) RRRRPSTR( A,B,D)
+#define PSTRINGV_cfR(A,B,D) RRRRPSTRV(A,B,D)
+#endif
+#endif
+#define PNSTRING_cfR(A,B,D) PSTRING_cfR(A,B,D)
+#define PPSTRING_cfR(A,B,D)
+
+#define    BYTE_cfFZ(UN,LN) INTEGER_BYTE     FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define  DOUBLE_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define     INT_cfFZ(UN,LN) int   FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define LOGICAL_cfFZ(UN,LN) int   FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define    LONG_cfFZ(UN,LN) long  FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define LONGLONG_cfFZ(UN,LN) LONGLONG FCALLSC_QUALIFIER fcallsc(UN,LN)( /* added by MR December 2005 */
+#define   SHORT_cfFZ(UN,LN) short FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#define    VOID_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#ifndef __CF__KnR
+/* The void is req'd by the Apollo, to make this an ANSI function declaration.
+   The Apollo promotes K&R float functions to double. */
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(void
+#else
+#define FLOAT_cfFZ(UN,LN) FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(void
+#endif
+#ifdef vmsFortran
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(fstring *AS
+#else
+#ifdef CRAYFortran
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(_fcd     AS
+#else
+#if  defined(AbsoftUNIXFortran) || defined(AbsoftProFortran)
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(char    *AS
+#else
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(char    *AS, unsigned D0
+#endif
+#endif
+#endif
+#else
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define   FLOAT_cfFZ(UN,LN) DOUBLE_PRECISION  FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define   FLOAT_cfFZ(UN,LN) FORTRAN_REAL      FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#else
+#define   FLOAT_cfFZ(UN,LN) FLOATFUNCTIONTYPE FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#if defined(vmsFortran) || defined(CRAYFortran) || defined(AbsoftUNIXFortran)
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(AS
+#else
+#define  STRING_cfFZ(UN,LN) void  FCALLSC_QUALIFIER fcallsc(UN,LN)(AS, D0
+#endif
+#endif
+
+#define    BYTE_cfF(UN,LN)     BYTE_cfFZ(UN,LN)
+#define  DOUBLE_cfF(UN,LN)   DOUBLE_cfFZ(UN,LN)
+#ifndef __CF_KnR
+#if defined (f2cFortran) && ! defined (gFortran)
+/* f2c/g77 return double from FORTRAN REAL functions. (KMCCARTY, 2005/12/09) */
+#define   FLOAT_cfF(UN,LN)  DOUBLE_PRECISION FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#else
+#define   FLOAT_cfF(UN,LN)  FORTRAN_REAL FCALLSC_QUALIFIER fcallsc(UN,LN)(
+#endif
+#else
+#define   FLOAT_cfF(UN,LN)    FLOAT_cfFZ(UN,LN)
+#endif
+#define     INT_cfF(UN,LN)      INT_cfFZ(UN,LN)
+#define LOGICAL_cfF(UN,LN)  LOGICAL_cfFZ(UN,LN)
+#define    LONG_cfF(UN,LN)     LONG_cfFZ(UN,LN)
+#define LONGLONG_cfF(UN,LN) LONGLONG_cfFZ(UN,LN) /* added by MR December 2005 */
+#define   SHORT_cfF(UN,LN)    SHORT_cfFZ(UN,LN)
+#define    VOID_cfF(UN,LN)     VOID_cfFZ(UN,LN)
+#define  STRING_cfF(UN,LN)   STRING_cfFZ(UN,LN),
+
+#define     INT_cfFF
+#define    VOID_cfFF
+#ifdef vmsFortran
+#define  STRING_cfFF           fstring *AS; 
+#else
+#ifdef CRAYFortran
+#define  STRING_cfFF           _fcd     AS;
+#else
+#define  STRING_cfFF           char    *AS; unsigned D0;
+#endif
+#endif
+
+#define     INT_cfL            A0=
+#define  STRING_cfL            A0=
+#define    VOID_cfL                        
+
+#define    INT_cfK
+#define   VOID_cfK
+/* KSTRING copies the string into the position provided by the caller. */
+#ifdef vmsFortran
+#define STRING_cfK                                                             \
+ memcpy(AS->dsc$a_pointer,A0,_cfMIN(AS->dsc$w_length,(A0==NULL?0:strlen(A0))));\
+ AS->dsc$w_length>(A0==NULL?0:strlen(A0))?                                     \
+  memset(AS->dsc$a_pointer+(A0==NULL?0:strlen(A0)),' ',                        \
+         AS->dsc$w_length-(A0==NULL?0:strlen(A0))):0;
+#else
+#ifdef CRAYFortran
+#define STRING_cfK                                                             \
+ memcpy(_fcdtocp(AS),A0, _cfMIN(_fcdlen(AS),(A0==NULL?0:strlen(A0))) );        \
+ _fcdlen(AS)>(A0==NULL?0:strlen(A0))?                                          \
+  memset(_fcdtocp(AS)+(A0==NULL?0:strlen(A0)),' ',                             \
+         _fcdlen(AS)-(A0==NULL?0:strlen(A0))):0;
+#else
+#define STRING_cfK         memcpy(AS,A0, _cfMIN(D0,(A0==NULL?0:strlen(A0))) ); \
+                 D0>(A0==NULL?0:strlen(A0))?memset(AS+(A0==NULL?0:strlen(A0)), \
+                                            ' ', D0-(A0==NULL?0:strlen(A0))):0;
+#endif
+#endif
+
+/* Note that K.. and I.. can't be combined since K.. has to access data before
+R.., in order for functions returning strings which are also passed in as
+arguments to work correctly. Note that R.. frees and hence may corrupt the
+string. */
+#define    BYTE_cfI  return A0;
+#define  DOUBLE_cfI  return A0;
+#if ! (defined(FLOATFUNCTIONTYPE)&&defined(ASSIGNFLOAT)&&defined(RETURNFLOAT))
+#define   FLOAT_cfI  return A0;
+#else
+#define   FLOAT_cfI  RETURNFLOAT(A0);
+#endif
+#define     INT_cfI  return A0;
+#ifdef hpuxFortran800
+/* Incredibly, functions must return true as 1, elsewhere .true.==0x01000000. */
+#define LOGICAL_cfI  return ((A0)?1:0);
+#else
+#define LOGICAL_cfI  return C2FLOGICAL(A0);
+#endif
+#define    LONG_cfI  return A0;
+#define LONGLONG_cfI  return A0; /* added by MR December 2005 */
+#define   SHORT_cfI  return A0;
+#define  STRING_cfI  return   ;
+#define    VOID_cfI  return   ;
+
+#ifdef OLD_VAXC                                  /* Allow %CC-I-PARAMNOTUSED. */
+#pragma standard
+#endif
+
+#define FCALLSCSUB0( CN,UN,LN)             FCALLSCFUN0(VOID,CN,UN,LN)
+#define FCALLSCSUB1( CN,UN,LN,T1)          FCALLSCFUN1(VOID,CN,UN,LN,T1)
+#define FCALLSCSUB2( CN,UN,LN,T1,T2)       FCALLSCFUN2(VOID,CN,UN,LN,T1,T2)
+#define FCALLSCSUB3( CN,UN,LN,T1,T2,T3)    FCALLSCFUN3(VOID,CN,UN,LN,T1,T2,T3)
+#define FCALLSCSUB4( CN,UN,LN,T1,T2,T3,T4) \
+    FCALLSCFUN4(VOID,CN,UN,LN,T1,T2,T3,T4)
+#define FCALLSCSUB5( CN,UN,LN,T1,T2,T3,T4,T5) \
+    FCALLSCFUN5(VOID,CN,UN,LN,T1,T2,T3,T4,T5)
+#define FCALLSCSUB6( CN,UN,LN,T1,T2,T3,T4,T5,T6) \
+    FCALLSCFUN6(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6)       
+#define FCALLSCSUB7( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+    FCALLSCFUN7(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7)
+#define FCALLSCSUB8( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+    FCALLSCFUN8(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8)
+#define FCALLSCSUB9( CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+    FCALLSCFUN9(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9)
+#define FCALLSCSUB10(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+   FCALLSCFUN10(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA)
+#define FCALLSCSUB11(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+   FCALLSCFUN11(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB)
+#define FCALLSCSUB12(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+   FCALLSCFUN12(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC)
+#define FCALLSCSUB13(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+   FCALLSCFUN13(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD)
+#define FCALLSCSUB14(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) \
+   FCALLSCFUN14(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)
+#define FCALLSCSUB15(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+   FCALLSCFUN15(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF)
+#define FCALLSCSUB16(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+   FCALLSCFUN16(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG)
+#define FCALLSCSUB17(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+   FCALLSCFUN17(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH)
+#define FCALLSCSUB18(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+   FCALLSCFUN18(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI)
+#define FCALLSCSUB19(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+   FCALLSCFUN19(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ)
+#define FCALLSCSUB20(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+   FCALLSCFUN20(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK)
+#define FCALLSCSUB21(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+   FCALLSCFUN21(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL)
+#define FCALLSCSUB22(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+   FCALLSCFUN22(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM)
+#define FCALLSCSUB23(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+   FCALLSCFUN23(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN)
+#define FCALLSCSUB24(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+   FCALLSCFUN24(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO)
+#define FCALLSCSUB25(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+   FCALLSCFUN25(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP)
+#define FCALLSCSUB26(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+   FCALLSCFUN26(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ)
+#define FCALLSCSUB27(CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) \
+   FCALLSCFUN27(VOID,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)
+
+
+#define FCALLSCFUN1( T0,CN,UN,LN,T1) \
+        FCALLSCFUN5 (T0,CN,UN,LN,T1,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN2( T0,CN,UN,LN,T1,T2) \
+        FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,CF_0,CF_0,CF_0)
+#define FCALLSCFUN3( T0,CN,UN,LN,T1,T2,T3) \
+        FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,CF_0,CF_0)
+#define FCALLSCFUN4( T0,CN,UN,LN,T1,T2,T3,T4) \
+        FCALLSCFUN5 (T0,CN,UN,LN,T1,T2,T3,T4,CF_0)
+#define FCALLSCFUN5( T0,CN,UN,LN,T1,T2,T3,T4,T5) \
+        FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN6( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6) \
+        FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN7( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7) \
+        FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,CF_0,CF_0,CF_0)
+#define FCALLSCFUN8( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8) \
+        FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,CF_0,CF_0)
+#define FCALLSCFUN9( T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9) \
+        FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,CF_0)
+#define FCALLSCFUN10(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA) \
+        FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN11(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB) \
+        FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,CF_0,CF_0,CF_0)
+#define FCALLSCFUN12(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC) \
+        FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,CF_0,CF_0)
+#define FCALLSCFUN13(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD) \
+        FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,CF_0)
+
+
+#define FCALLSCFUN15(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF) \
+        FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN16(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG) \
+        FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN17(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH) \
+        FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,CF_0,CF_0,CF_0)
+#define FCALLSCFUN18(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI) \
+        FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,CF_0,CF_0)
+#define FCALLSCFUN19(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ) \
+        FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,CF_0)
+#define FCALLSCFUN20(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN21(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,CF_0,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN22(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,CF_0,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN23(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,CF_0,CF_0,CF_0,CF_0)
+#define FCALLSCFUN24(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,CF_0,CF_0,CF_0)
+#define FCALLSCFUN25(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,CF_0,CF_0)
+#define FCALLSCFUN26(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ) \
+        FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,CF_0)
+
+
+#ifndef __CF__KnR
+#define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf2(T0))   \
+        {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
+
+#define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
+                                 CFextern _(T0,_cfF)(UN,LN)                    \
+ CFARGT14(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE) )  \
+ {                 CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
+  _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(    TCF(LN,T1,1,0)  TCF(LN,T2,2,1) \
+    TCF(LN,T3,3,1)  TCF(LN,T4,4,1) TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1) \
+    TCF(LN,T8,8,1)  TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+    TCF(LN,TD,13,1) TCF(LN,TE,14,1) );                          _Icf(0,K,T0,0,0) \
+                   CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  _(T0,_cfI) }
+
+#define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)   \
+                                 CFextern _(T0,_cfF)(UN,LN)                    \
+ CFARGT27(NCF,DCF,ABSOFT_cf2(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR) ) \
+ {                 CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)   \
+  _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(     TCF(LN,T1,1,0)  TCF(LN,T2,2,1)  \
+    TCF(LN,T3,3,1)  TCF(LN,T4,4,1)  TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1)  \
+    TCF(LN,T8,8,1)  TCF(LN,T9,9,1)  TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+    TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
+    TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
+    TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
+                   CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  _(T0,_cfI) }
+
+#else
+#define FCALLSCFUN0(T0,CN,UN,LN) CFextern _(T0,_cfFZ)(UN,LN) ABSOFT_cf3(T0)) _Icf(0,FF,T0,0,0)\
+        {_Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0) CN(); _Icf(0,K,T0,0,0) _(T0,_cfI)}
+
+#define FCALLSCFUN14(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
+                                 CFextern _(T0,_cfF)(UN,LN)                    \
+ CFARGT14(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)) _Icf(0,FF,T0,0,0) \
+       CFARGT14FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE);   \
+ {                 CFARGT14S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)    \
+  _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(  TCF(LN,T1,1,0) TCF(LN,T2,2,1) \
+    TCF(LN,T3,3,1) TCF(LN,T4,4,1) TCF(LN,T5,5,1) TCF(LN,T6,6,1) TCF(LN,T7,7,1) \
+    TCF(LN,T8,8,1) TCF(LN,T9,9,1) TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+    TCF(LN,TD,13,1) TCF(LN,TE,14,1) );                          _Icf(0,K,T0,0,0) \
+                   CFARGT14S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE)  _(T0,_cfI)}
+
+#define FCALLSCFUN27(T0,CN,UN,LN,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  \
+                                 CFextern _(T0,_cfF)(UN,LN)                    \
+ CFARGT27(NNCF,DDCF,ABSOFT_cf3(T0),T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)) _Icf(0,FF,T0,0,0) \
+       CFARGT27FS(NNNCF,DDDCF,_Z,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR); \
+ {                 CFARGT27S(QCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  \
+  _Icf(2,UU,T0,A0,0); _Icf(0,L,T0,0,0)      CN(     TCF(LN,T1,1,0)  TCF(LN,T2,2,1)  \
+    TCF(LN,T3,3,1)  TCF(LN,T4,4,1)  TCF(LN,T5,5,1)  TCF(LN,T6,6,1)  TCF(LN,T7,7,1)  \
+    TCF(LN,T8,8,1)  TCF(LN,T9,9,1)  TCF(LN,TA,10,1) TCF(LN,TB,11,1) TCF(LN,TC,12,1) \
+    TCF(LN,TD,13,1) TCF(LN,TE,14,1) TCF(LN,TF,15,1) TCF(LN,TG,16,1) TCF(LN,TH,17,1) \
+    TCF(LN,TI,18,1) TCF(LN,TJ,19,1) TCF(LN,TK,20,1) TCF(LN,TL,21,1) TCF(LN,TM,22,1) \
+    TCF(LN,TN,23,1) TCF(LN,TO,24,1) TCF(LN,TP,25,1) TCF(LN,TQ,26,1) TCF(LN,TR,27,1) ); _Icf(0,K,T0,0,0) \
+                   CFARGT27S(RCF,T1,T2,T3,T4,T5,T6,T7,T8,T9,TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR)  _(T0,_cfI)}
+
+#endif
+
+
+#endif	 /* __CFORTRAN_LOADED */
diff --git a/src/cmortable_parser.cc b/src/cmortable_parser.cc
index 6174c47..4cce3cf 100644
--- a/src/cmortable_parser.cc
+++ b/src/cmortable_parser.cc
@@ -32,7 +32,7 @@ char *readLineFromBuffer(char *buffer, size_t *buffersize, char *line, size_t le
       line[ipos++] = ichar;
       if ( ipos >= len )
         {
-          fprintf(stderr, "readLineFromBuffer: end of line not found (maxlen = %ld)!\n", len);
+          fprintf(stderr, "readLineFromBuffer: end of line not found (maxlen = %zu)!\n", len);
           break;
         }
     }
diff --git a/src/compare.h b/src/compare.h
index 76f9340..eb24cc2 100644
--- a/src/compare.h
+++ b/src/compare.h
@@ -15,11 +15,11 @@
   GNU General Public License for more details.
 */
 
-#ifndef _COMPARE_H
-#define _COMPARE_H
+#ifndef  COMPARE_H
+#define  COMPARE_H
 
-#if defined(HAVE_CONFIG_H)
-#  include "config.h"
+#ifdef  HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #include <math.h>
@@ -52,4 +52,4 @@
 
 #define STR_IS_EQ(x,y) ((*x)==(*y) && strcmp(x,y) == 0)
 
-#endif  /* _COMPARE_H */
+#endif  /* COMPARE_H */
diff --git a/src/config.h.in b/src/config.h.in
index c527e4d..3c78bf3 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -18,9 +18,21 @@
 /* Define to 1 for DATA support */
 #undef ENABLE_DATA
 
+/* Define to 1 for nearpt3 support */
+#undef ENABLE_NEARPT3
+
+/* F77 Compiler */
+#undef F77_COMPILER
+
+/* F77 Compiler version */
+#undef F77_VERSION
+
 /* Define to 1 if you have the `backtrace' function. */
 #undef HAVE_BACKTRACE
 
+/* Defined to 1 if C / Fortran interface cfortran.h works */
+#undef HAVE_CF_INTERFACE
+
 /* Define to 1 if you have the <cmor.h> header file. */
 #undef HAVE_CMOR_H
 
@@ -276,6 +288,11 @@
 /* Version number of package */
 #undef VERSION
 
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
diff --git a/src/ecacore.cc b/src/ecacore.cc
index 244c098..5bb9dbf 100644
--- a/src/ecacore.cc
+++ b/src/ecacore.cc
@@ -36,7 +36,7 @@ void eca1(const ECA_REQUEST_1 *request)
 {
   const int operatorID = cdoOperatorID();
   
-  int nmiss;
+  size_t nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -403,7 +403,7 @@ void eca2(const ECA_REQUEST_2 *request)
 {
   const int operatorID = cdoOperatorID();
   
-  int nmiss;
+  size_t nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -792,7 +792,7 @@ void eca3(const ECA_REQUEST_3 *request)
 {
   const int operatorID = cdoOperatorID();
 
-  int nmiss;
+  size_t nmiss;
   int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   int gridsize;
@@ -999,7 +999,7 @@ void eca4(const ECA_REQUEST_4 *request)
 {
   const int operatorID = cdoOperatorID();
 
-  int nmiss;
+  size_t nmiss;
   int yearcnt = 0;
   int nrecs;
   int varID, levelID;
diff --git a/src/ecautil.cc b/src/ecautil.cc
index 03d1fb6..65c8fd6 100644
--- a/src/ecautil.cc
+++ b/src/ecautil.cc
@@ -147,16 +147,16 @@ unsigned long day_of_year(int date)
  */  
 static void count(field_type *field1, const field_type *field2, double mode)
 {
-  int   i, len;
+  size_t i;
   const int     grid1    = field1->grid;
-  const int     nmiss1   = field1->nmiss;
+  const size_t  nmiss1   = field1->nmiss;
   const double  missval1 = field1->missval;
   double       *array1   = field1->ptr;
   const int     grid2    = field2->grid;
   const double  missval2 = field2->missval;
   const double *array2   = field2->ptr;
   
-  len = gridInqSize(grid1);
+  size_t len = gridInqSize(grid1);
 
   if ( len != gridInqSize(grid2) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
@@ -231,17 +231,17 @@ static void count(field_type *field1, const field_type *field2, double mode)
  */  
 static void selcomp(field_type *field1, const field_type *field2, int (*compare)(double, double))
 {
-  int   i, len;
+  size_t i;
   const int     grid1    = field1->grid;
-  const int     nmiss1   = field1->nmiss;
+  const size_t  nmiss1   = field1->nmiss;
   const double  missval1 = field1->missval;
   double       *array1   = field1->ptr;
   const int     grid2    = field2->grid;
-  const int     nmiss2   = field2->nmiss;
+  const size_t  nmiss2   = field2->nmiss;
   const double  missval2 = field2->missval;
   const double *array2   = field2->ptr;
   
-  len = gridInqSize(grid1);
+  size_t len = gridInqSize(grid1);
 
   if ( len != gridInqSize(grid2) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
@@ -282,13 +282,13 @@ static void selcomp(field_type *field1, const field_type *field2, int (*compare)
  */  
 static void selcompc(field_type *field, double c, int (*compare)(double, double))
 {
-  int   i, len;
+  size_t i;
   const int     grid    = field->grid;
-  const int     nmiss   = field->nmiss;
+  const size_t  nmiss   = field->nmiss;
   const double  missval = field->missval;
   double       *array   = field->ptr;
   
-  len = gridInqSize(grid);
+  size_t len = gridInqSize(grid);
 
   if ( DBL_IS_EQUAL(c, missval) )
     {
@@ -370,16 +370,16 @@ void farnum3(field_type *field1, field_type field2, double n)
 
 void farsel(field_type *field1, field_type field2)
 {
-  int   i, len;
+  size_t i;
   const int     grid1    = field1->grid;
   const double  missval1 = field1->missval;
   double       *array1   = field1->ptr;
   const int     grid2    = field2.grid;
-  const int     nmiss2   = field2.nmiss;
+  const size_t  nmiss2   = field2.nmiss;
   const double  missval2 = field2.missval;
   const double *array2   = field2.ptr;
   
-  len = gridInqSize(grid1);
+  size_t len = gridInqSize(grid1);
 
   if ( len != gridInqSize(grid2) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
diff --git a/src/expr.cc b/src/expr.cc
index 0fdbdab..5c1b51c 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -58,6 +58,7 @@ enum {FT_STD, FT_CONST, FT_FLD, FT_VERT, FT_COORD, FT_1C};
 #define MVCOMPAND(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPAND(x,y))
 #define  MVCOMPOR(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPOR(x,y))
 
+static double f_float(double x)        { return (float)(x); }
 static double f_int(double x)          { return (int)(x); }
 static double f_nint(double x)         { return round(x); }
 static double f_sqr(double x)          { return x*x;      }
@@ -101,6 +102,7 @@ static func_t fun_sym_tbl[] =
   {FT_STD, 0, "acosh", (double (*)()) (double (*)(double)) acosh},
   {FT_STD, 0, "atanh", (double (*)()) (double (*)(double)) atanh},
   {FT_STD, 0, "gamma", (double (*)()) (double (*)(double)) tgamma},
+  {FT_STD, 0, "float", (double (*)()) f_float},
   {FT_STD, 0, "int",   (double (*)()) f_int},
   {FT_STD, 0, "nint",  (double (*)()) f_nint},
   {FT_STD, 0, "sqr",   (double (*)()) f_sqr},
@@ -185,10 +187,17 @@ int get_funcID(const char *fun)
 }
 
 static
+bool isCompare(int oper)
+{
+  return oper==LEG||oper==GE||oper==LE||oper==EQ||oper==NE||oper==GT||oper==LT;
+}
+
+static
 void param_meta_copy(paramType *out, paramType *in)
 {
   out->gridID   = in->gridID;
   out->zaxisID  = in->zaxisID;
+  out->datatype = in->datatype;
   out->steptype = in->steptype;
   out->ngp      = in->ngp;
   out->nlev     = in->nlev;
@@ -450,6 +459,7 @@ nodeType *expr_con_var(int init, int oper, nodeType *p1, nodeType *p2)
   size_t ngp   = p2->param.ngp;
   size_t nlev  = p2->param.nlev;
   size_t nmiss = p2->param.nmiss;
+  int datatype = p2->param.datatype;
   double missval1 = p2->param.missval;
   double missval2 = p2->param.missval;
 
@@ -469,6 +479,7 @@ nodeType *expr_con_var(int init, int oper, nodeType *p1, nodeType *p2)
       double *restrict odat = p->param.data;
       const double *restrict idat = p2->param.data;
       double cval = p1->u.con.value;
+      if ( datatype == CDI_DATATYPE_FLT32 && isCompare(oper) ) cval = (float) cval;
 
       oper_expr_con_var(oper, nmiss>0, n, missval1, missval2, odat, cval, idat);
 
@@ -488,6 +499,7 @@ nodeType *expr_var_con(int init, int oper, nodeType *p1, nodeType *p2)
   size_t ngp   = p1->param.ngp;
   size_t nlev  = p1->param.nlev;
   size_t nmiss = p1->param.nmiss;
+  int datatype = p1->param.datatype;
   double missval1 = p1->param.missval;
   double missval2 = p1->param.missval;
 
@@ -507,6 +519,7 @@ nodeType *expr_var_con(int init, int oper, nodeType *p1, nodeType *p2)
       double *restrict odat = p->param.data;
       const double *restrict idat = p1->param.data;
       double cval = p2->u.con.value;
+      if ( datatype == CDI_DATATYPE_FLT32 && isCompare(oper) ) cval = (float) cval;
 
       oper_expr_var_con(oper, nmiss>0, n, missval1, missval2, odat, idat, cval);
 
@@ -584,7 +597,7 @@ nodeType *expr_var_var(int init, int oper, nodeType *p1, nodeType *p2)
     }
 
   p->param.name = p->u.var.nm;
-  //printf("%s %s nmiss %ld %ld\n", p->u.var.nm, px->param.name, nmiss1, nmiss2);
+  //printf("%s %s nmiss %zu %zu\n", p->u.var.nm, px->param.name, nmiss1, nmiss2);
 
   if ( ! init )
     {
@@ -601,7 +614,7 @@ nodeType *expr_var_var(int init, int oper, nodeType *p1, nodeType *p2)
           const double *restrict idat1 = p1->param.data+loff1;
           const double *restrict idat2 = p2->param.data+loff2;
           double *restrict odat = p->param.data+loff;
-          int nmiss = nmiss1 > 0 || nmiss2 > 0;
+          size_t nmiss = nmiss1 > 0 || nmiss2 > 0;
 
           if ( ngp1 != ngp2 )
             {
@@ -629,7 +642,7 @@ nodeType *expr_var_var(int init, int oper, nodeType *p1, nodeType *p2)
 static
 void ex_copy_var(int init, nodeType *p2, nodeType *p1)
 {
-  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%lu][N%lu] = %s[L%lu][N%lu]",
+  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%zu][N%zu] = %s[L%zu][N%zu]",
                              ExIn[init], p2->param.name, p2->param.nlev, p2->param.ngp, p1->param.name, p2->param.nlev, p2->param.ngp);
   
   size_t ngp = p1->param.ngp;
@@ -662,7 +675,7 @@ void ex_copy_con(int init, nodeType *p2, nodeType *p1)
 {
   double cval = p1->u.con.value;
 
-  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%lu][N%lu] = %g", ExIn[init], p2->param.name, p2->param.nlev, p2->param.ngp, cval);
+  if ( cdoVerbose ) cdoPrint("\t%s\tcopy\t%s[L%zu][N%zu] = %g", ExIn[init], p2->param.name, p2->param.nlev, p2->param.ngp, cval);
   
   size_t ngp = p2->param.ngp;
   assert(ngp > 0);
@@ -722,19 +735,19 @@ nodeType *expr(int init, int oper, nodeType *p1, nodeType *p2)
     {
       p = expr_var_var(init, oper, p1, p2);
       if ( cdoVerbose )
-	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %s %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.var.nm);
+	cdoPrint("\t%s\tarith\t%s[L%zu][N%zu] = %s %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.var.nm);
     }
   else if ( p1->type == typeVar && p2->type == typeCon )
     {
       p = expr_var_con(init, oper, p1, p2);
       if ( cdoVerbose )
-	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %s %s %g", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.con.value);
+	cdoPrint("\t%s\tarith\t%s[L%zu][N%zu] = %s %s %g", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.var.nm, coper, p2->u.con.value);
     }
   else if ( p1->type == typeCon && p2->type == typeVar )
     {
       p = expr_con_var(init, oper, p1, p2);
       if ( cdoVerbose )
-	cdoPrint("\t%s\tarith\t%s[L%lu][N%lu] = %g %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.con.value, coper, p2->u.var.nm);
+	cdoPrint("\t%s\tarith\t%s[L%zu][N%zu] = %g %s %s", ExIn[init], p->u.var.nm, p->param.nlev, p->param.ngp, p1->u.con.value, coper, p2->u.var.nm);
     }
   else if ( p1->type == typeCon && p2->type == typeCon )
     {
@@ -969,7 +982,7 @@ nodeType *fun1c(int init, int funcID, nodeType *p1, double value, parse_param_t
     {
       long ilevidx = lround(value);
       if ( ilevidx < 1 || ilevidx > (long)nlev )
-        cdoAbort("%s(): level index %ld out of range (range: 1-%lu)!", funcname, ilevidx, nlev);
+        cdoAbort("%s(): level index %ld out of range (range: 1-%zu)!", funcname, ilevidx, nlev);
       levidx = (size_t) ilevidx - 1;
     }
   else if ( strcmp(funcname, "sellevel") == 0 )
@@ -1137,15 +1150,15 @@ nodeType *ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3)
 
   if ( cdoVerbose )
     {
-      fprintf(stderr, "cdo expr:\t%s\tifelse\t%s[L%lu][N%lu] ? ", ExIn[init], p1->u.var.nm, p1->param.nlev, p1->param.ngp);
+      fprintf(stderr, "cdo expr:\t%s\tifelse\t%s[L%zu][N%zu] ? ", ExIn[init], p1->u.var.nm, p1->param.nlev, p1->param.ngp);
       if ( p2->type == typeCon )
         fprintf(stderr, "%g : ", p2->u.con.value);
       else
-        fprintf(stderr, "%s[L%lu][N%lu] : ", p2->u.var.nm, p2->param.nlev, p2->param.ngp);
+        fprintf(stderr, "%s[L%zu][N%zu] : ", p2->u.var.nm, p2->param.nlev, p2->param.ngp);
       if ( p3->type == typeCon )
         fprintf(stderr, "%g\n", p3->u.con.value);
       else
-        fprintf(stderr, "%s[L%lu][N%lu]\n", p3->u.var.nm, p3->param.nlev, p3->param.ngp);
+        fprintf(stderr, "%s[L%zu][N%zu]\n", p3->u.var.nm, p3->param.nlev, p3->param.ngp);
     }
 
   size_t nmiss1 = p1->param.nmiss;
@@ -1377,9 +1390,9 @@ nodeType *expr_run(nodeType *p, parse_param_t *parse_arg)
                       if ( i < maxout || (ngp > maxout && i >= (ngp-maxout)) )
                         {
                           if ( steptype == TIME_CONSTANT )
-                            fprintf(stdout, "   %s[lev=%lu:gp=%lu] = %g\n", vname, k+1, i+1, data[k*ngp+i]);
+                            fprintf(stdout, "   %s[lev=%zu:gp=%zu] = %g\n", vname, k+1, i+1, data[k*ngp+i]);
                           else
-                            fprintf(stdout, "   %s[ts=%ld:lev=%lu:gp=%lu] = %g\n", vname, tsID, k+1, i+1, data[k*ngp+i]);
+                            fprintf(stdout, "   %s[ts=%ld:lev=%zu:gp=%zu] = %g\n", vname, tsID, k+1, i+1, data[k*ngp+i]);
                         }
                       else if ( i == maxout )
                         {
@@ -1514,7 +1527,7 @@ nodeType *expr_run(nodeType *p, parse_param_t *parse_arg)
             p->param.nmiss = params[varID].nmiss;
           }
 
-        if ( parse_arg->debug ) cdoPrint("\tpush\tvar\t%s[L%lu][N%lu]", vnm, p->param.nlev, p->param.ngp);
+        if ( parse_arg->debug ) cdoPrint("\tpush\tvar\t%s[L%zu][N%zu]", vnm, p->param.nlev, p->param.ngp);
 
         rnode = p;
 
@@ -1577,7 +1590,7 @@ nodeType *expr_run(nodeType *p, parse_param_t *parse_arg)
             if ( parse_arg->debug )
               {
                 if ( rnode && rnode->type == typeVar)
-                  cdoPrint("\tpop\tvar\t%s[L%lu][N%lu]", varname2, rnode->param.nlev, rnode->param.ngp);
+                  cdoPrint("\tpop\tvar\t%s[L%zu][N%zu]", varname2, rnode->param.nlev, rnode->param.ngp);
                 else
                   cdoPrint("\tpop\tconst\t%s", varname2);
               }
diff --git a/src/expr.h b/src/expr.h
index b7fc437..278c38b 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -73,6 +73,7 @@ typedef struct {
   int        coord;
   int        gridID;
   int        zaxisID;
+  int        datatype;
   int        steptype;
   size_t     ngp;
   size_t     nlev;
diff --git a/src/expr_lex.cc b/src/expr_lex.cc
index bf0929b..948162e 100644
--- a/src/expr_lex.cc
+++ b/src/expr_lex.cc
@@ -1,6 +1,6 @@
-#line 2 "expr_lex.cc"
+#line 1 "expr_lex.cc"
 
-#line 4 "expr_lex.cc"
+#line 3 "expr_lex.cc"
 
 #define  YY_INT_ALIGNED short int
 
@@ -9,11 +9,23 @@
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 6
-#define YY_FLEX_SUBMINOR_VERSION 1
+#define YY_FLEX_SUBMINOR_VERSION 4
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #endif
 
+#ifdef yyget_lval
+#define yyget_lval_ALREADY_DEFINED
+#else
+#define yyget_lval yyget_lval
+#endif
+
+#ifdef yyset_lval
+#define yyset_lval_ALREADY_DEFINED
+#else
+#define yyset_lval yyset_lval
+#endif
+
 /* First, we deal with  platform-specific or compiler-specific issues. */
 
 /* begin standard C headers. */
@@ -84,10 +96,16 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #endif
 
+#ifndef SIZE_MAX
+#define SIZE_MAX               (~(size_t)0)
+#endif
+
 #endif /* ! C99 */
 
 #endif /* ! FLEXINT_H */
 
+/* begin standard C++ headers. */
+
 /* TODO: this is always defined, so inline it */
 #define yyconst const
 
@@ -100,12 +118,10 @@ typedef unsigned int flex_uint32_t;
 /* Returned upon end-of-file. */
 #define YY_NULL 0
 
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
+/* Promotes a possibly negative, possibly signed char to an
+ *   integer in range [0..255] for use as an array index.
  */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
 
 /* An opaque pointer. */
 #ifndef YY_TYPEDEF_YY_SCANNER_T
@@ -129,20 +145,16 @@ typedef void* yyscan_t;
  * definition of BEGIN.
  */
 #define BEGIN yyg->yy_start = 1 + 2 *
-
 /* Translate the current start state into a value that can be later handed
  * to BEGIN to return to the state.  The YYSTATE alias is for lex
  * compatibility.
  */
 #define YY_START ((yyg->yy_start - 1) / 2)
 #define YYSTATE YY_START
-
 /* Action number for EOF rule of a given start state. */
 #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
 /* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
-
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
 #define YY_END_OF_BUFFER_CHAR 0
 
 /* Size of default input buffer. */
@@ -175,7 +187,7 @@ typedef size_t yy_size_t;
 #define EOB_ACT_CONTINUE_SCAN 0
 #define EOB_ACT_END_OF_FILE 1
 #define EOB_ACT_LAST_MATCH 2
-
+    
     #define YY_LESS_LINENO(n)
     #define YY_LINENO_REWIND_TO(ptr)
     
@@ -192,7 +204,6 @@ typedef size_t yy_size_t;
 		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
 		} \
 	while ( 0 )
-
 #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
 
 #ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -235,7 +246,7 @@ struct yy_buffer_state
 
     int yy_bs_lineno; /**< The line count. */
     int yy_bs_column; /**< The column count. */
-    
+
 	/* Whether to try to fill the input buffer when we reach the
 	 * end of it.
 	 */
@@ -269,73 +280,67 @@ struct yy_buffer_state
 #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
                           ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
                           : NULL)
-
 /* Same as previous macro, but useful when we know that the buffer stack is not
  * NULL or when we need an lvalue. For internal use only.
  */
 #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
 
-void yyrestart (FILE *input_file ,yyscan_t yyscanner );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
-void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
-void yypop_buffer_state (yyscan_t yyscanner );
-
-static void yyensure_buffer_stack (yyscan_t yyscanner );
-static void yy_load_buffer_state (yyscan_t yyscanner );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
 
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
 
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
 
-void *yyalloc (yy_size_t ,yyscan_t yyscanner );
-void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
-void yyfree (void * ,yyscan_t yyscanner );
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
 
 #define yy_new_buffer yy_create_buffer
-
 #define yy_set_interactive(is_interactive) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){ \
         yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
 	}
-
 #define yy_set_bol(at_bol) \
 	{ \
 	if ( ! YY_CURRENT_BUFFER ){\
         yyensure_buffer_stack (yyscanner); \
 		YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
 	} \
 	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
 	}
-
 #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
 
 /* Begin user sect3 */
 
 #define yywrap(yyscanner) (/*CONSTCOND*/1)
 #define YY_SKIP_YYWRAP
-
-typedef unsigned char YY_CHAR;
+typedef flex_uint8_t YY_CHAR;
 
 typedef int yy_state_type;
 
 #define yytext_ptr yytext_r
 
-static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ,yyscan_t yyscanner);
-static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner );
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state  , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
 
 /* Done after the current pattern has been matched and before the
  * corresponding action - sets up yytext.
@@ -346,7 +351,6 @@ static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner );
 	yyg->yy_hold_char = *yy_cp; \
 	*yy_cp = '\0'; \
 	yyg->yy_c_buf_p = yy_cp;
-
 #define YY_NUM_RULES 25
 #define YY_END_OF_BUFFER 26
 /* This struct is not used in this scanner,
@@ -356,7 +360,7 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_acclist[164] =
+static const flex_int16_t yy_acclist[164] =
     {   0,
         4,    4,   26,   24,   25,   23,   24,   25,   23,   25,
        24,   25,    1,   24,   25,   24,   25,   11,   24,   25,
@@ -378,7 +382,7 @@ static yyconst flex_int16_t yy_acclist[164] =
     16391,    5, 8199
     } ;
 
-static yyconst flex_int16_t yy_accept[76] =
+static const flex_int16_t yy_accept[76] =
     {   0,
         1,    2,    3,    4,    6,    9,   11,   13,   16,   18,
        21,   25,   28,   31,   34,   37,   40,   43,   48,   54,
@@ -390,7 +394,7 @@ static yyconst flex_int16_t yy_accept[76] =
       157,  159,  162,  164,  164
     } ;
 
-static yyconst YY_CHAR yy_ec[256] =
+static const YY_CHAR yy_ec[256] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
@@ -422,7 +426,7 @@ static yyconst YY_CHAR yy_ec[256] =
         1,    1,    1,    1,    1
     } ;
 
-static yyconst YY_CHAR yy_meta[35] =
+static const YY_CHAR yy_meta[35] =
     {   0,
         1,    1,    2,    3,    1,    1,    1,    3,    1,    1,
         4,    5,    1,    1,    1,    1,    1,    6,    6,    6,
@@ -430,7 +434,7 @@ static yyconst YY_CHAR yy_meta[35] =
         6,    6,    6,    1
     } ;
 
-static yyconst flex_uint16_t yy_base[80] =
+static const flex_int16_t yy_base[80] =
     {   0,
         0,    0,  134,  135,   33,   36,  118,    0,  125,  135,
        29,   31,  135,  116,  115,  114,  135,   49,   51,   34,
@@ -442,7 +446,7 @@ static yyconst flex_uint16_t yy_base[80] =
       135,   50,  135,  135,   97,  100,  104,  106,   46
     } ;
 
-static yyconst flex_int16_t yy_def[80] =
+static const flex_int16_t yy_def[80] =
     {   0,
        74,    1,   74,   74,   74,   74,   74,   75,   74,   74,
        74,   76,   74,   74,   74,   74,   74,   77,   77,   19,
@@ -454,7 +458,7 @@ static yyconst flex_int16_t yy_def[80] =
        74,   19,   74,    0,   74,   74,   74,   74,   74
     } ;
 
-static yyconst flex_uint16_t yy_nxt[170] =
+static const flex_int16_t yy_nxt[170] =
     {   0,
         4,    5,    6,    5,    7,    8,    9,   10,   10,   10,
        11,   12,   13,   14,   15,   16,   17,   18,   19,   20,
@@ -476,7 +480,7 @@ static yyconst flex_uint16_t yy_nxt[170] =
        74,   74,   74,   74,   74,   74,   74,   74,   74
     } ;
 
-static yyconst flex_int16_t yy_chk[170] =
+static const flex_int16_t yy_chk[170] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -532,6 +536,7 @@ goto find_rule; \
 #include "expr.h"
 #include "expr_yacc.h"
 
+#line 539 "expr_lex.cc"
 /* Definitions:  LMB92 p. 153
    Definitions are named regular expressions, e.g., DGT [0-9]
    Definitions enclosed in braces in rules section, e.g. {DGT}, are interpreted literally
@@ -539,7 +544,7 @@ goto find_rule; \
    LPH [A-Za-z_] Alphabetic character
    LPHDGT [A-Za-z0-9_] Alphanumeric character
    XPN [eE][+-]?[0-9]+ Real number Exponent */
-#line 543 "expr_lex.cc"
+#line 547 "expr_lex.cc"
 
 #define INITIAL 0
 
@@ -602,7 +607,7 @@ struct yyguts_t
 
     }; /* end struct yyguts_t */
 
-static int yy_init_globals (yyscan_t yyscanner );
+static int yy_init_globals ( yyscan_t yyscanner );
 
     /* This must go here because YYSTYPE and YYLTYPE are included
      * from bison output in section 1.*/
@@ -610,44 +615,44 @@ static int yy_init_globals (yyscan_t yyscanner );
     
 int yylex_init (yyscan_t* scanner);
 
-int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
 
 /* Accessor methods to globals.
    These are made visible to non-reentrant scanners for convenience. */
 
-int yylex_destroy (yyscan_t yyscanner );
+int yylex_destroy ( yyscan_t yyscanner );
 
-int yyget_debug (yyscan_t yyscanner );
+int yyget_debug ( yyscan_t yyscanner );
 
-void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
 
-YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
 
-void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
 
-FILE *yyget_in (yyscan_t yyscanner );
+FILE *yyget_in ( yyscan_t yyscanner );
 
-void yyset_in  (FILE * _in_str ,yyscan_t yyscanner );
+void yyset_in  ( FILE * _in_str , yyscan_t yyscanner );
 
-FILE *yyget_out (yyscan_t yyscanner );
+FILE *yyget_out ( yyscan_t yyscanner );
 
-void yyset_out  (FILE * _out_str ,yyscan_t yyscanner );
+void yyset_out  ( FILE * _out_str , yyscan_t yyscanner );
 
-			int yyget_leng (yyscan_t yyscanner );
+			int yyget_leng ( yyscan_t yyscanner );
 
-char *yyget_text (yyscan_t yyscanner );
+char *yyget_text ( yyscan_t yyscanner );
 
-int yyget_lineno (yyscan_t yyscanner );
+int yyget_lineno ( yyscan_t yyscanner );
 
-void yyset_lineno (int _line_number ,yyscan_t yyscanner );
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
 
-int yyget_column  (yyscan_t yyscanner );
+int yyget_column  ( yyscan_t yyscanner );
 
-void yyset_column (int _column_no ,yyscan_t yyscanner );
+void yyset_column ( int _column_no , yyscan_t yyscanner );
 
-YYSTYPE * yyget_lval (yyscan_t yyscanner );
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
 
-void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -655,9 +660,9 @@ void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
 
 #ifndef YY_SKIP_YYWRAP
 #ifdef __cplusplus
-extern "C" int yywrap (yyscan_t yyscanner );
+extern "C" int yywrap ( yyscan_t yyscanner );
 #else
-extern int yywrap (yyscan_t yyscanner );
+extern int yywrap ( yyscan_t yyscanner );
 #endif
 #endif
 
@@ -666,19 +671,18 @@ extern int yywrap (yyscan_t yyscanner );
 #endif
 
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
 #endif
 
 #ifndef YY_NO_INPUT
-
 #ifdef __cplusplus
-static int yyinput (yyscan_t yyscanner );
+static int yyinput ( yyscan_t yyscanner );
 #else
-static int input (yyscan_t yyscanner );
+static int input ( yyscan_t yyscanner );
 #endif
 
 #endif
@@ -709,7 +713,7 @@ static int input (yyscan_t yyscanner );
 	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
 		{ \
 		int c = '*'; \
-		size_t n; \
+		int n; \
 		for ( n = 0; n < max_size && \
 			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
 			buf[n] = (char) c; \
@@ -722,7 +726,7 @@ static int input (yyscan_t yyscanner );
 	else \
 		{ \
 		errno=0; \
-		while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+		while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
 			{ \
 			if( errno != EINTR) \
 				{ \
@@ -764,7 +768,7 @@ static int input (yyscan_t yyscanner );
 #define YY_DECL_IS_OURS 1
 
 extern int yylex \
-               (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+               (YYSTYPE * yylval_param , yyscan_t yyscanner);
 
 #define YY_DECL int yylex \
                (YYSTYPE * yylval_param , yyscan_t yyscanner)
@@ -806,7 +810,7 @@ YY_DECL
 
         /* Create the reject buffer large enough to save one state per allowed character. */
         if ( ! yyg->yy_state_buf )
-            yyg->yy_state_buf = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE  ,yyscanner);
+            yyg->yy_state_buf = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE  , yyscanner);
             if ( ! yyg->yy_state_buf )
                 YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
 
@@ -822,17 +826,17 @@ YY_DECL
 		if ( ! YY_CURRENT_BUFFER ) {
 			yyensure_buffer_stack (yyscanner);
 			YY_CURRENT_BUFFER_LVALUE =
-				yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+				yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 		}
 
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		}
 
 	{
 #line 36 "expr_lex.l"
 
 
-#line 836 "expr_lex.cc"
+#line 839 "expr_lex.cc"
 
 	while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
 		{
@@ -859,9 +863,9 @@ yy_match:
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
 				if ( yy_current_state >= 75 )
-					yy_c = yy_meta[(unsigned int) yy_c];
+					yy_c = yy_meta[yy_c];
 				}
-			yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 			*yyg->yy_state_ptr++ = yy_current_state;
 			++yy_cp;
 			}
@@ -1066,7 +1070,7 @@ YY_RULE_SETUP
 #line 104 "expr_lex.l"
 ECHO;
 	YY_BREAK
-#line 1070 "expr_lex.cc"
+#line 1073 "expr_lex.cc"
 			case YY_STATE_EOF(INITIAL):
 				yyterminate();
 
@@ -1144,7 +1148,7 @@ ECHO;
 				{
 				yyg->yy_did_buffer_switch_on_eof = 0;
 
-				if ( yywrap(yyscanner ) )
+				if ( yywrap( yyscanner ) )
 					{
 					/* Note: because we've taken care in
 					 * yy_get_next_buffer() to have set up
@@ -1212,7 +1216,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
 	char *source = yyg->yytext_ptr;
-	yy_size_t number_to_move, i;
+	int number_to_move, i;
 	int ret_val;
 
 	if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
@@ -1241,7 +1245,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	/* Try to read more data. */
 
 	/* First move last chars to start of buffer. */
-	number_to_move = (yy_size_t) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+	number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
 
 	for ( i = 0; i < number_to_move; ++i )
 		*(dest++) = *(source++);
@@ -1280,7 +1284,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		if ( number_to_move == YY_MORE_ADJ )
 			{
 			ret_val = EOB_ACT_END_OF_FILE;
-			yyrestart(yyin  ,yyscanner);
+			yyrestart( yyin  , yyscanner);
 			}
 
 		else
@@ -1294,12 +1298,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
-	if ((int) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+	if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
 		/* Extend the array by 50%, plus the number we really need. */
 		int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
-		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+			(void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
 		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
 			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+		/* "- 2" to take care of EOB's */
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
 	}
 
 	yyg->yy_n_chars += number_to_move;
@@ -1331,9 +1338,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
 			if ( yy_current_state >= 75 )
-				yy_c = yy_meta[(unsigned int) yy_c];
+				yy_c = yy_meta[yy_c];
 			}
-		yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 		*yyg->yy_state_ptr++ = yy_current_state;
 		}
 
@@ -1355,9 +1362,9 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
 		if ( yy_current_state >= 75 )
-			yy_c = yy_meta[(unsigned int) yy_c];
+			yy_c = yy_meta[yy_c];
 		}
-	yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c];
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
 	yy_is_jam = (yy_current_state == 74);
 	if ( ! yy_is_jam )
 		*yyg->yy_state_ptr++ = yy_current_state;
@@ -1395,7 +1402,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 
 		else
 			{ /* need more input */
-			int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+			int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
 			++yyg->yy_c_buf_p;
 
 			switch ( yy_get_next_buffer( yyscanner ) )
@@ -1412,13 +1419,13 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 					 */
 
 					/* Reset buffer status. */
-					yyrestart(yyin ,yyscanner);
+					yyrestart( yyin , yyscanner);
 
 					/*FALLTHROUGH*/
 
 				case EOB_ACT_END_OF_FILE:
 					{
-					if ( yywrap(yyscanner ) )
+					if ( yywrap( yyscanner ) )
 						return 0;
 
 					if ( ! yyg->yy_did_buffer_switch_on_eof )
@@ -1457,11 +1464,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 	if ( ! YY_CURRENT_BUFFER ){
         yyensure_buffer_stack (yyscanner);
 		YY_CURRENT_BUFFER_LVALUE =
-            yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+            yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
 	}
 
-	yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
-	yy_load_buffer_state(yyscanner );
+	yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+	yy_load_buffer_state( yyscanner );
 }
 
 /** Switch to a different input buffer.
@@ -1490,7 +1497,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
 		}
 
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
-	yy_load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 
 	/* We don't actually know whether we did this switch during
 	 * EOF (yywrap()) processing, but the only time this flag
@@ -1519,22 +1526,22 @@ static void yy_load_buffer_state  (yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
     
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
-	b->yy_buf_size = (yy_size_t)size;
+	b->yy_buf_size = size;
 
 	/* yy_ch_buf has to be 2 characters longer than the size given because
 	 * we need to put in 2 end-of-buffer characters.
 	 */
-	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+	b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
 	if ( ! b->yy_ch_buf )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
 
 	b->yy_is_our_buffer = 1;
 
-	yy_init_buffer(b,file ,yyscanner);
+	yy_init_buffer( b, file , yyscanner);
 
 	return b;
 }
@@ -1554,9 +1561,9 @@ static void yy_load_buffer_state  (yyscan_t yyscanner)
 		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
 
 	if ( b->yy_is_our_buffer )
-		yyfree((void *) b->yy_ch_buf ,yyscanner );
+		yyfree( (void *) b->yy_ch_buf , yyscanner );
 
-	yyfree((void *) b ,yyscanner );
+	yyfree( (void *) b , yyscanner );
 }
 
 /* Initializes or reinitializes a buffer.
@@ -1569,7 +1576,7 @@ static void yy_load_buffer_state  (yyscan_t yyscanner)
 	int oerrno = errno;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-	yy_flush_buffer(b ,yyscanner);
+	yy_flush_buffer( b , yyscanner);
 
 	b->yy_input_file = file;
 	b->yy_fill_buffer = 1;
@@ -1613,7 +1620,7 @@ static void yy_load_buffer_state  (yyscan_t yyscanner)
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
 	if ( b == YY_CURRENT_BUFFER )
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 }
 
 /** Pushes the new state onto the stack. The new state becomes
@@ -1645,7 +1652,7 @@ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
 	YY_CURRENT_BUFFER_LVALUE = new_buffer;
 
 	/* copied from yy_switch_to_buffer. */
-	yy_load_buffer_state(yyscanner );
+	yy_load_buffer_state( yyscanner );
 	yyg->yy_did_buffer_switch_on_eof = 1;
 }
 
@@ -1659,13 +1666,13 @@ void yypop_buffer_state (yyscan_t yyscanner)
 	if (!YY_CURRENT_BUFFER)
 		return;
 
-	yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+	yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
 	YY_CURRENT_BUFFER_LVALUE = NULL;
 	if (yyg->yy_buffer_stack_top > 0)
 		--yyg->yy_buffer_stack_top;
 
 	if (YY_CURRENT_BUFFER) {
-		yy_load_buffer_state(yyscanner );
+		yy_load_buffer_state( yyscanner );
 		yyg->yy_did_buffer_switch_on_eof = 1;
 	}
 }
@@ -1675,7 +1682,7 @@ void yypop_buffer_state (yyscan_t yyscanner)
  */
 static void yyensure_buffer_stack (yyscan_t yyscanner)
 {
-	int num_to_alloc;
+	yy_size_t num_to_alloc;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
 	if (!yyg->yy_buffer_stack) {
@@ -1690,9 +1697,9 @@ static void yyensure_buffer_stack (yyscan_t yyscanner)
 								, yyscanner);
 		if ( ! yyg->yy_buffer_stack )
 			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-								  
+
 		memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-				
+
 		yyg->yy_buffer_stack_max = num_to_alloc;
 		yyg->yy_buffer_stack_top = 0;
 		return;
@@ -1721,7 +1728,7 @@ static void yyensure_buffer_stack (yyscan_t yyscanner)
  * @param base the character buffer
  * @param size the size in bytes of the character buffer
  * @param yyscanner The scanner object.
- * @return the newly allocated buffer state object. 
+ * @return the newly allocated buffer state object.
  */
 YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscanner)
 {
@@ -1733,11 +1740,11 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscann
 		/* They forgot to leave room for the EOB's. */
 		return NULL;
 
-	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+	b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
 	if ( ! b )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
 
-	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_size = (int) (size - 2);	/* "- 2" to take care of EOB's */
 	b->yy_buf_pos = b->yy_ch_buf = base;
 	b->yy_is_our_buffer = 0;
 	b->yy_input_file = NULL;
@@ -1747,7 +1754,7 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscann
 	b->yy_fill_buffer = 0;
 	b->yy_buffer_status = YY_BUFFER_NEW;
 
-	yy_switch_to_buffer(b ,yyscanner );
+	yy_switch_to_buffer( b , yyscanner );
 
 	return b;
 }
@@ -1760,10 +1767,10 @@ YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size , yyscan_t yyscann
  * @note If you want to scan bytes that may contain NUL values, then use
  *       yy_scan_bytes() instead.
  */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
 {
     
-	return yy_scan_bytes(yystr,(int) strlen(yystr) ,yyscanner);
+	return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
 }
 
 /** Setup the input buffer state to scan the given bytes. The next call to yylex() will
@@ -1773,16 +1780,16 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
  * @param yyscanner The scanner object.
  * @return the newly allocated buffer state object.
  */
-YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
+YY_BUFFER_STATE yy_scan_bytes  (const char * yybytes, int  _yybytes_len , yyscan_t yyscanner)
 {
 	YY_BUFFER_STATE b;
 	char *buf;
 	yy_size_t n;
-	yy_size_t i;
+	int i;
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = (yy_size_t) _yybytes_len + 2;
-	buf = (char *) yyalloc(n ,yyscanner );
+	n = (yy_size_t) (_yybytes_len + 2);
+	buf = (char *) yyalloc( n , yyscanner );
 	if ( ! buf )
 		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
 
@@ -1791,7 +1798,7 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yysc
 
 	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
-	b = yy_scan_buffer(buf,n ,yyscanner);
+	b = yy_scan_buffer( buf, n , yyscanner);
 	if ( ! b )
 		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
 
@@ -1807,11 +1814,11 @@ YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len , yysc
 #define YY_EXIT_FAILURE 2
 #endif
 
-static void yynoreturn yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
-	(void) fprintf( stderr, "%s\n", msg );
+	fprintf( stderr, "%s\n", msg );
 	exit( YY_EXIT_FAILURE );
 }
 
@@ -1849,7 +1856,7 @@ YY_EXTRA_TYPE yyget_extra  (yyscan_t yyscanner)
 int yyget_lineno  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
+
         if (! YY_CURRENT_BUFFER)
             return 0;
     
@@ -1862,7 +1869,7 @@ int yyget_lineno  (yyscan_t yyscanner)
 int yyget_column  (yyscan_t yyscanner)
 {
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-    
+
         if (! YY_CURRENT_BUFFER)
             return 0;
     
@@ -1996,9 +2003,7 @@ void yyset_lval (YYSTYPE *  yylval_param , yyscan_t yyscanner)
  * the ONLY reentrant function that doesn't take the scanner as the last argument.
  * That's why we explicitly handle the declaration, instead of using our macros.
  */
-
 int yylex_init(yyscan_t* ptr_yy_globals)
-
 {
     if (ptr_yy_globals == NULL){
         errno = EINVAL;
@@ -2025,9 +2030,7 @@ int yylex_init(yyscan_t* ptr_yy_globals)
  * The user defined value in the first argument will be available to yyalloc in
  * the yyextra field.
  */
-
-int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
-
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
 {
     struct yyguts_t dummy_yyguts;
 
@@ -2037,20 +2040,20 @@ int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
         errno = EINVAL;
         return 1;
     }
-	
+
     *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-	
+
     if (*ptr_yy_globals == NULL){
         errno = ENOMEM;
         return 1;
     }
-    
+
     /* By setting to 0xAA, we expose bugs in
     yy_init_globals. Leave at 0x00 for releases. */
     memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-    
+
     yyset_extra (yy_user_defined, *ptr_yy_globals);
-    
+
     return yy_init_globals ( *ptr_yy_globals );
 }
 
@@ -2099,17 +2102,17 @@ int yylex_destroy  (yyscan_t yyscanner)
 
     /* Pop the buffer stack, destroying each element. */
 	while(YY_CURRENT_BUFFER){
-		yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+		yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
 		YY_CURRENT_BUFFER_LVALUE = NULL;
 		yypop_buffer_state(yyscanner);
 	}
 
 	/* Destroy the stack itself. */
-	yyfree(yyg->yy_buffer_stack ,yyscanner);
+	yyfree(yyg->yy_buffer_stack , yyscanner);
 	yyg->yy_buffer_stack = NULL;
 
     /* Destroy the start condition stack. */
-        yyfree(yyg->yy_start_stack ,yyscanner );
+        yyfree( yyg->yy_start_stack , yyscanner );
         yyg->yy_start_stack = NULL;
 
     yyfree ( yyg->yy_state_buf , yyscanner);
@@ -2130,7 +2133,7 @@ int yylex_destroy  (yyscan_t yyscanner)
  */
 
 #ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
 {
 	struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 	(void)yyg;
@@ -2142,7 +2145,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysca
 #endif
 
 #ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
 {
 	int n;
 	for ( n = 0; s[n]; ++n )
@@ -2186,4 +2189,3 @@ void yyfree (void * ptr , yyscan_t yyscanner)
 #line 104 "expr_lex.l"
 
 
-
diff --git a/src/expr_yacc.cc b/src/expr_yacc.cc
index b5a9650..e692378 100644
--- a/src/expr_yacc.cc
+++ b/src/expr_yacc.cc
@@ -416,16 +416,16 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  3
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   186
+#define YYLAST   204
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  32
 /* YYNNTS -- Number of nonterminals.  */
 #define YYNNTS  7
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  36
+#define YYNRULES  37
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  77
+#define YYNSTATES  79
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
@@ -476,7 +476,7 @@ static const yytype_uint8 yyrline[] =
        0,    60,    60,    64,    65,    69,    70,    71,    72,    73,
       74,    75,    76,    80,    81,    85,    86,    87,    88,    89,
       90,    91,    92,    93,    94,    95,    96,    97,    98,    99,
-     100,   101,   102,   103,   104,   105,   108
+     100,   101,   102,   103,   104,   105,   106,   109
 };
 #endif
 
@@ -519,14 +519,14 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-     -25,     2,    34,   -25,   -25,   -21,   -24,     7,    10,    41,
-     -25,    34,    41,   -25,   133,   -25,    41,    41,    13,    14,
-     -25,    24,   -25,    27,   100,    41,    41,    41,    41,    41,
-      41,    41,    41,    41,    41,    41,    41,    41,    41,   -25,
-      84,     9,    62,    26,    33,   -25,   -25,   -25,   162,   162,
-      46,    46,    46,    46,    46,    46,    46,   -12,   -12,    24,
-      24,    24,    41,   -25,   -25,   -25,    30,   -25,   -25,   118,
-      22,    12,    41,   -25,    42,   149,   -25
+     -25,     2,    41,   -25,   -25,   -21,   -24,     7,    10,    59,
+     -25,    41,    59,   -25,   151,   -25,    59,    59,   -11,     8,
+     -25,    14,   -25,    28,    80,    13,    59,    59,    59,    59,
+      59,    59,    59,    59,    59,    59,    59,    59,    59,    59,
+     -25,   120,    16,    98,    17,    18,   -25,   -25,    59,   -25,
+     -25,   180,   180,    53,    53,    53,    53,    53,    53,    53,
+     -12,   -12,    14,    14,    14,   -25,   -25,   -25,    31,   -25,
+     -25,   136,    20,    12,    59,   -25,    25,   167,   -25
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -537,23 +537,23 @@ static const yytype_uint8 yydefact[] =
        4,     0,     2,     1,    15,    16,     0,     0,     0,     0,
        5,     0,     0,     3,     0,     9,     0,     0,     0,     0,
       16,    17,    13,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     6,
-       0,     0,     0,     0,     0,    12,    14,    32,    30,    31,
-      29,    25,    26,    28,    27,    23,    22,    18,    19,    20,
-      21,    24,     0,     7,     8,    35,     0,    10,    11,     0,
-       0,     0,     0,    34,     0,    36,    33
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       6,     0,     0,     0,     0,     0,    12,    14,     0,    32,
+      33,    30,    31,    29,    25,    26,    28,    27,    23,    22,
+      18,    19,    20,    21,    24,     7,     8,    36,     0,    10,
+      11,     0,     0,     0,     0,    35,     0,    37,    34
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -25,   -25,   -25,   -10,   -25,    -9,   -25
+     -25,   -25,   -25,   -10,   -25,    -9,    38
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     1,     2,    13,    23,    14,    41
+      -1,     1,     2,    13,    23,    14,    25
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -561,48 +561,52 @@ static const yytype_int8 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      21,    22,     3,    24,    15,    16,    17,    40,    42,    36,
-      37,    18,    38,    46,    19,    74,    48,    49,    50,    51,
-      52,    53,    54,    55,    56,    57,    58,    59,    60,    61,
-       4,     5,     6,    70,    64,     7,     8,     4,     5,     6,
-      43,    44,     7,     8,     4,    20,     6,     9,    38,    73,
-      71,    67,    10,    69,     9,    11,    45,    12,    68,    10,
-       0,     9,    11,    75,    12,    34,    35,    36,    37,    76,
-      38,    12,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    36,    37,     0,    38,     0,     0,    65,
-      62,     0,     0,    66,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    35,    36,    37,     0,    38,    63,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,     0,    38,    72,     0,    47,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-      37,     0,    38,    25,    26,    27,    28,    29,    30,    31,
-      32,    33,    34,    35,    36,    37,     0,    38,    39,    25,
+      21,    22,     3,    24,    15,    16,    17,    41,    43,    37,
+      38,    18,    39,    47,    19,    76,    44,    51,    52,    53,
+      54,    55,    56,    57,    58,    59,    60,    61,    62,    63,
+      64,     4,     5,     6,    72,    45,     7,     8,    39,    71,
+      50,    66,    69,    70,     4,     5,     6,    75,     9,     7,
+       8,    73,    78,    10,    42,     0,    11,    46,    12,     0,
+       0,     9,     4,    20,     6,    77,    10,     0,     0,    11,
+       0,    12,    35,    36,    37,    38,     0,    39,     0,     9,
+       0,     0,     0,     0,     0,     0,    48,     0,     0,    12,
       26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-      36,    37,     0,    38,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    36,    37,     0,    38
+      36,    37,    38,     0,    39,     0,     0,    49,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    36,    37,
+      38,     0,    39,     0,     0,    67,    48,     0,     0,    68,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    74,    39,    65,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    36,    37,    38,     0,
+      39,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,     0,    39,    40,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+       0,    39,    28,    29,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,     0,    39
 };
 
 static const yytype_int8 yycheck[] =
 {
        9,    11,     0,    12,    25,    26,    30,    16,    17,    21,
-      22,     4,    24,    23,     4,     3,    25,    26,    27,    28,
+      22,     4,    24,    23,     4,     3,    27,    26,    27,    28,
       29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
-       3,     4,     5,     3,    25,     8,     9,     3,     4,     5,
-      27,    27,     8,     9,     3,     4,     5,    20,    24,    27,
-      20,    25,    25,    62,    20,    28,    29,    30,    25,    25,
-      -1,    20,    28,    72,    30,    19,    20,    21,    22,    27,
-      24,    30,    10,    11,    12,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    -1,    24,    -1,    -1,    27,
-       6,    -1,    -1,    31,    10,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    -1,    24,    25,
+      39,     3,     4,     5,     3,    27,     8,     9,    24,    48,
+      27,    25,    25,    25,     3,     4,     5,    27,    20,     8,
+       9,    20,    27,    25,    16,    -1,    28,    29,    30,    -1,
+      -1,    20,     3,     4,     5,    74,    25,    -1,    -1,    28,
+      -1,    30,    19,    20,    21,    22,    -1,    24,    -1,    20,
+      -1,    -1,    -1,    -1,    -1,    -1,     6,    -1,    -1,    30,
       10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,    -1,    24,     7,    -1,    27,    10,    11,
+      20,    21,    22,    -1,    24,    -1,    -1,    27,    10,    11,
       12,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    -1,    24,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    -1,    24,    25,    10,
-      11,    12,    13,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    -1,    24,    12,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    -1,    24
+      22,    -1,    24,    -1,    -1,    27,     6,    -1,    -1,    31,
+      10,    11,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,     7,    24,    25,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    -1,
+      24,    10,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    -1,    24,    25,    10,    11,    12,
+      13,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      -1,    24,    12,    13,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    -1,    24
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -611,12 +615,12 @@ static const yytype_uint8 yystos[] =
 {
        0,    33,    34,     0,     3,     4,     5,     8,     9,    20,
       25,    28,    30,    35,    37,    25,    26,    30,     4,     4,
-       4,    37,    35,    36,    37,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    24,    25,
-      37,    38,    37,    27,    27,    29,    35,    27,    37,    37,
-      37,    37,    37,    37,    37,    37,    37,    37,    37,    37,
-      37,    37,     6,    25,    25,    27,    31,    25,    25,    37,
-       3,    20,     7,    27,     3,    37,    27
+       4,    37,    35,    36,    37,    38,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    24,
+      25,    37,    38,    37,    27,    27,    29,    35,     6,    27,
+      27,    37,    37,    37,    37,    37,    37,    37,    37,    37,
+      37,    37,    37,    37,    37,    25,    25,    27,    31,    25,
+      25,    37,     3,    20,     7,    27,     3,    37,    27
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
@@ -625,7 +629,7 @@ static const yytype_uint8 yyr1[] =
        0,    32,    33,    34,    34,    35,    35,    35,    35,    35,
       35,    35,    35,    36,    36,    37,    37,    37,    37,    37,
       37,    37,    37,    37,    37,    37,    37,    37,    37,    37,
-      37,    37,    37,    37,    37,    37,    38
+      37,    37,    37,    37,    37,    37,    37,    38
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -634,7 +638,7 @@ static const yytype_uint8 yyr2[] =
        0,     2,     1,     2,     0,     1,     2,     4,     4,     2,
        4,     4,     3,     1,     2,     1,     1,     2,     3,     3,
        3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     3,     7,     6,     4,     5
+       3,     3,     3,     3,     7,     6,     4,     5
 };
 
 
@@ -1321,209 +1325,215 @@ yyreduce:
         case 2:
 #line 60 "expr_yacc.y" /* yacc.c:1646  */
     { return 0; }
-#line 1325 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1329 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 3:
 #line 64 "expr_yacc.y" /* yacc.c:1646  */
     { expr_run((yyvsp[0].nPtr), (parse_param_t *) parse_arg); freeNode((yyvsp[0].nPtr)); }
-#line 1331 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1335 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 5:
 #line 69 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(';', 2, NULL, NULL); }
-#line 1337 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1341 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 6:
 #line 70 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1343 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1347 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 7:
 #line 71 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-3].varnm)), (yyvsp[-1].nPtr)); }
-#line 1349 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1353 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 8:
 #line 72 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-3].varnm)), (yyvsp[-1].nPtr)); }
-#line 1355 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1359 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 9:
 #line 73 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('=', 2, expr_var((yyvsp[-1].varnm)), expr_var((yyvsp[-1].varnm))); }
-#line 1361 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1365 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 10:
 #line 74 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_com("remove", (yyvsp[-2].varnm)); }
-#line 1367 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1371 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 11:
 #line 75 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_com("print", (yyvsp[-2].varnm)); }
-#line 1373 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1377 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 12:
 #line 76 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1379 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1383 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 13:
 #line 80 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = (yyvsp[0].nPtr); }
-#line 1385 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1389 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 14:
 #line 81 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(';', 2, (yyvsp[-1].nPtr), (yyvsp[0].nPtr)); }
-#line 1391 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1395 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 15:
 #line 85 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_con((yyvsp[0].cvalue)); }
-#line 1397 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1401 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 16:
 #line 86 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_var((yyvsp[0].varnm)); }
-#line 1403 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1407 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 17:
 #line 87 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(UMINUS, 1, (yyvsp[0].nPtr)); }
-#line 1409 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1413 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 18:
 #line 88 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('+', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1415 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1419 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 19:
 #line 89 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('-', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1421 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1425 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 20:
 #line 90 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('*', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1427 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1431 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 21:
 #line 91 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('/', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1433 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1437 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 22:
 #line 92 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(LT,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1439 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1443 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 23:
 #line 93 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(GT,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1445 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1449 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 24:
 #line 94 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('^', 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1451 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1455 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 25:
 #line 95 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(GE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1457 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1461 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 26:
 #line 96 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(LE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1463 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1467 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 27:
 #line 97 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(NE,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1469 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1473 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 28:
 #line 98 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(EQ,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1475 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1479 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 29:
 #line 99 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(LEG, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1481 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1485 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 30:
 #line 100 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(AND, 2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1487 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1491 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 31:
 #line 101 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr(OR,  2, (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1493 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1497 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 32:
 #line 102 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = (yyvsp[-1].nPtr); }
-#line 1499 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1503 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 33:
 #line 103 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_fun1c((yyvsp[-6].fname), (yyvsp[-4].nPtr), - (yyvsp[-1].cvalue)); }
-#line 1505 "expr_yacc.cc" /* yacc.c:1646  */
+    { (yyval.nPtr) = (yyvsp[-1].nPtr); }
+#line 1509 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 34:
 #line 104 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_fun1c((yyvsp[-5].fname), (yyvsp[-3].nPtr), (yyvsp[-1].cvalue)); }
-#line 1511 "expr_yacc.cc" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_fun1c((yyvsp[-6].fname), (yyvsp[-4].nPtr), - (yyvsp[-1].cvalue)); }
+#line 1515 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 35:
 #line 105 "expr_yacc.y" /* yacc.c:1646  */
-    { (yyval.nPtr) = expr_fun((yyvsp[-3].fname), (yyvsp[-1].nPtr)); }
-#line 1517 "expr_yacc.cc" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_fun1c((yyvsp[-5].fname), (yyvsp[-3].nPtr), (yyvsp[-1].cvalue)); }
+#line 1521 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
   case 36:
-#line 108 "expr_yacc.y" /* yacc.c:1646  */
+#line 106 "expr_yacc.y" /* yacc.c:1646  */
+    { (yyval.nPtr) = expr_fun((yyvsp[-3].fname), (yyvsp[-1].nPtr)); }
+#line 1527 "expr_yacc.cc" /* yacc.c:1646  */
+    break;
+
+  case 37:
+#line 109 "expr_yacc.y" /* yacc.c:1646  */
     { (yyval.nPtr) = expr_opr('?', 3, (yyvsp[-4].nPtr), (yyvsp[-2].nPtr), (yyvsp[0].nPtr)); }
-#line 1523 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1533 "expr_yacc.cc" /* yacc.c:1646  */
     break;
 
 
-#line 1527 "expr_yacc.cc" /* yacc.c:1646  */
+#line 1537 "expr_yacc.cc" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -1751,7 +1761,7 @@ yyreturn:
 #endif
   return yyresult;
 }
-#line 111 "expr_yacc.y" /* yacc.c:1906  */
+#line 112 "expr_yacc.y" /* yacc.c:1906  */
 
 
 #define SIZEOF_NODETYPE ((char *)&p->u.con - (char *)p)
diff --git a/src/features.cc b/src/features.cc
index 07713c8..e56f7a8 100644
--- a/src/features.cc
+++ b/src/features.cc
@@ -23,13 +23,9 @@
 #endif
 
 #if defined(HAVE_LIBCMOR)
-#ifdef __cplusplus
-  extern "C" {
-#endif
+extern "C" {
 #include "cmor.h"
-#ifdef __cplusplus
-  }
-#endif
+}
 #endif
 
 #include <stdio.h>
@@ -37,9 +33,21 @@
 
 #include "cdo_int.h" // HAVE_OPENMP4
 
+extern "C" {
+size_t getMemorySize(void);
+}
+
 void printFeatures(void)
 {
   fprintf(stderr, "Features:");
+  size_t memory_size = getMemorySize();
+  memory_size /= 1024;
+  memory_size /= 1024;
+  memory_size /= 1024;
+  if ( memory_size > 0 ) fprintf(stderr, " %zuGB", memory_size);
+#if defined(HAVE_CF_INTERFACE)
+  fprintf(stderr, " Fortran");
+#endif
 #if defined(ENABLE_DATA)
   fprintf(stderr, " DATA");
 #endif
diff --git a/src/field.cc b/src/field.cc
index 3cb9031..40dd87b 100644
--- a/src/field.cc
+++ b/src/field.cc
@@ -63,7 +63,7 @@ double fldrank(field_type field)
   double *array  =  &(field.ptr[1]);
   double val     = array[-1];
   const double missval = field.missval;
-  int nmiss      = field.nmiss;
+  size_t nmiss      = field.nmiss;
   const size_t len       = field.size-1;
   size_t j;
   
@@ -92,7 +92,7 @@ double fldroc(field_type field)
 double fldcrps(field_type field)
 {
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
+  const size_t nmiss   = field.nmiss;
   double *array  = field.ptr;
 
   if ( nmiss > 0 ) 
@@ -112,7 +112,7 @@ double fldcrps(field_type field)
 
 double fldbrs(field_type field) 
 {
-  const int     nmiss   = field.nmiss;
+  const size_t  nmiss   = field.nmiss;
   const size_t    len   = field.size;
   double *array   = field.ptr;
   const double missval  = field.missval;
@@ -145,7 +145,7 @@ double fldbrs(field_type field)
 
 double fldrange(field_type field)
 {
-  const int nmiss      = field.nmiss > 0;
+  const size_t nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   const double *restrict array = field.ptr;
@@ -186,7 +186,7 @@ double fldrange(field_type field)
 
 double fldmin(field_type field)
 {
-  const int nmiss      = field.nmiss > 0;
+  const size_t nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   const double *restrict array = field.ptr;
@@ -215,7 +215,7 @@ double fldmin(field_type field)
 
 double fldmax(field_type field)
 {
-  const int nmiss      = field.nmiss > 0;
+  const size_t nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   const double *restrict array = field.ptr;
@@ -243,7 +243,7 @@ double fldmax(field_type field)
 
 double fldsum(field_type field)
 {
-  const int nmiss      = field.nmiss > 0;
+  const size_t nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   const double *restrict array = field.ptr;
@@ -276,7 +276,7 @@ double fldsum(field_type field)
 
 double fldmean(field_type field)
 {
-  const int nmiss       = field.nmiss > 0;
+  const size_t nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
@@ -307,7 +307,7 @@ double fldmean(field_type field)
 
 double fldmeanw(field_type field)
 {
-  const int nmiss       = field.nmiss > 0;
+  const size_t nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
@@ -340,7 +340,7 @@ double fldmeanw(field_type field)
 
 double fldavg(field_type field)
 {
-  const int nmiss       = field.nmiss > 0;
+  const size_t nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
@@ -371,7 +371,7 @@ double fldavg(field_type field)
 
 double fldavgw(field_type field)
 {
-  const int nmiss       = field.nmiss > 0;
+  const size_t nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
   const double missval1 = field.missval;
   const double missval2 = field.missval;
@@ -406,7 +406,7 @@ double fldavgw(field_type field)
 }
 
 static
-void prevarsum(const double *restrict array, size_t len, int nmiss, 
+void prevarsum(const double *restrict array, size_t len, size_t nmiss, 
                double missval, double *rsum, double *rsumw, double *rsumq, double *rsumwq)
 { 
   assert(array!=NULL);
@@ -445,7 +445,7 @@ void prevarsum(const double *restrict array, size_t len, int nmiss,
 
 double fldvar(field_type field)
 {
-  const int    nmiss   = field.nmiss > 0;
+  const size_t nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   double rsum, rsumw;
@@ -462,7 +462,7 @@ double fldvar(field_type field)
 
 double fldvar1(field_type field)
 {
-  const int    nmiss   = field.nmiss > 0;
+  const size_t nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   double rsum, rsumw;
@@ -477,7 +477,7 @@ double fldvar1(field_type field)
 }
 
 static
-void prevarsumw(const double *restrict array, const double *restrict w, size_t len, int nmiss, 
+void prevarsumw(const double *restrict array, const double *restrict w, size_t len, size_t nmiss, 
                 double missval, double *rsum, double *rsumw, double *rsumq, double *rsumwq)
 { 
   assert(array!=NULL);
@@ -517,7 +517,7 @@ void prevarsumw(const double *restrict array, const double *restrict w, size_t l
 
 double fldvarw(field_type field)
 {
-  const int    nmiss   = field.nmiss > 0;
+  const size_t nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   double rsum, rsumw;
@@ -534,7 +534,7 @@ double fldvarw(field_type field)
 
 double fldvar1w(field_type field)
 {
-  const int    nmiss   = field.nmiss > 0;
+  const size_t nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
   const double missval = field.missval;
   double rsum, rsumw;
@@ -594,12 +594,12 @@ void fldrms(field_type field, field_type field2, field_type *field3)
 {
   size_t   i;
   size_t len;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid1    = field.grid;
-  //  int    nmiss1   = field.nmiss;
+  //  size_t nmiss1   = field.nmiss;
   double *array1  = field.ptr;
   int    grid2    = field2.grid;
-  //  int    nmiss2   = field2.nmiss;
+  //  size_t nmiss2   = field2.nmiss;
   double *array2  = field2.ptr;
   const double missval1 = field.missval;
   const double missval2 = field2.missval;
@@ -645,13 +645,13 @@ void fldrms(field_type field, field_type field2, field_type *field3)
 void varrms(field_type field, field_type field2, field_type *field3)
 {
   size_t   i, k, nlev, len;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    zaxis    = field.zaxis;
   int    grid1    = field.grid;
-  //  int    nmiss1   = field.nmiss;
+  //  size_t nmiss1   = field.nmiss;
   double *array1  = field.ptr;
   int    grid2    = field2.grid;
-  //  int    nmiss2   = field2.nmiss;
+  //  size_t nmiss2   = field2.nmiss;
   double *array2  = field2.ptr;
   const double missval1 = field.missval;
   const double missval2 = field2.missval;
@@ -699,7 +699,7 @@ void varrms(field_type field, field_type field2, field_type *field3)
 double fldpctl(field_type field, const double pn)
 {
   const size_t len     = field.size;
-  const int    nmiss   = field.nmiss;
+  const size_t nmiss   = field.nmiss;
   const double missval = field.missval;
   double *array  = field.ptr;
   double pctl = missval;
diff --git a/src/field2.cc b/src/field2.cc
index c1a2058..6390875 100644
--- a/src/field2.cc
+++ b/src/field2.cc
@@ -42,13 +42,13 @@ void farfun(field_type *field1, field_type field2, int function)
 }
 
 static
-int farsetnmiss(int len, double *restrict array, double missval)
+int farsetnmiss(size_t len, double *restrict array, double missval)
 {
-  int nmiss = 0;
+  size_t nmiss = 0;
 
   if ( DBL_IS_NAN(missval) )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         if ( DBL_IS_EQUAL(array[i], missval) || array[i] < 0 )
           {
             array[i] = missval;
@@ -57,7 +57,7 @@ int farsetnmiss(int len, double *restrict array, double missval)
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         if ( IS_EQUAL(array[i], missval) || array[i] < 0 )
           {
             array[i] = missval;
@@ -72,8 +72,8 @@ int farsetnmiss(int len, double *restrict array, double missval)
 void farcpy(field_type *field1, field_type field2)
 {
   int nwpv = field1->nwpv;
-  int gridsize1 = field1->size;
-  int gridsize2 = field2.size;
+  size_t gridsize1 = field1->size;
+  size_t gridsize2 = field2.size;
   double *restrict array1 = field1->ptr;
   const double *restrict array2 = field2.ptr;
   const float *restrict array2f = field2.ptrf;
@@ -83,15 +83,14 @@ void farcpy(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridsize1;
-
+  size_t len = nwpv*gridsize1;
   if ( len != nwpv*gridsize2 )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( field2.memtype == MEMTYPE_FLOAT )
-    for ( int i = 0; i < len; i++ ) array1[i] = array2f[i];
+    for ( size_t i = 0; i < len; i++ ) array1[i] = array2f[i];
   else
-    for ( int i = 0; i < len; i++ ) array1[i] = array2[i];
+    for ( size_t i = 0; i < len; i++ ) array1[i] = array2[i];
 }
 
 
@@ -100,8 +99,8 @@ void faradd(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -110,25 +109,24 @@ void faradd(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] = ADDMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
       if ( field2.memtype == MEMTYPE_FLOAT )
         {
-          for ( int i = 0; i < len; i++ ) array1[i] += array2f[i];
+          for ( size_t i = 0; i < len; i++ ) array1[i] += array2f[i];
         }
       else
         {
@@ -141,10 +139,10 @@ void faradd(field_type *field1, field_type field2)
 void farsum(field_type *field1, field_type field2)
 {
   int nwpv = field1->nwpv;
-  int gridsize1 = field1->size;
-  int gridsize2 = field2.size;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t gridsize1 = field1->size;
+  size_t gridsize2 = field2.size;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -156,14 +154,14 @@ void farsum(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridsize1;
+  size_t len = nwpv*gridsize1;
 
   if ( len != nwpv*gridsize2 )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -173,14 +171,14 @@ void farsum(field_type *field1, field_type field2)
 	  }
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
       if ( field2.memtype == MEMTYPE_FLOAT )
         {
-          for ( int i = 0; i < len; i++ ) array1[i] += array2f[i];
+          for ( size_t i = 0; i < len; i++ ) array1[i] += array2f[i];
         }
       else
         {
@@ -195,8 +193,8 @@ void farsumw(field_type *field1, field_type field2, double w)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -204,14 +202,13 @@ void farsumw(field_type *field1, field_type field2, double w)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -221,7 +218,7 @@ void farsumw(field_type *field1, field_type field2, double w)
 	  }
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
@@ -229,7 +226,7 @@ void farsumw(field_type *field1, field_type field2, double w)
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(array1,array2,w,len)
 #endif
-      for ( int i = 0; i < len; i++ ) array1[i] += w*array2[i];
+      for ( size_t i = 0; i < len; i++ ) array1[i] += w*array2[i];
     }
 }
 
@@ -248,8 +245,7 @@ void farsumtr(field_type *occur, field_type field, const double refval)
   double *restrict oarray = occur->ptr;
   double *restrict farray = field.ptr;
 
-  int len = gridInqSize(occur->grid);
-
+  size_t len = gridInqSize(occur->grid);
   if ( len != gridInqSize(field.grid) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
@@ -258,7 +254,7 @@ void farsumtr(field_type *occur, field_type field, const double refval)
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared) schedule(static)
 #endif
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(farray[i], fmissval) )
 	  {
 	    if ( !DBL_IS_EQUAL(oarray[i], omissval) )
@@ -273,7 +269,7 @@ void farsumtr(field_type *occur, field_type field, const double refval)
 	}
 
       occur->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(oarray[i], omissval) ) occur->nmiss++;
     }
   else
@@ -281,7 +277,7 @@ void farsumtr(field_type *occur, field_type field, const double refval)
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
 #endif
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	oarray[i] = (DBL_IS_EQUAL(farray[i], refval)) ? 0.0 : oarray[i] + 1.0;
     }
 }
@@ -292,8 +288,8 @@ void farsumq(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -302,14 +298,13 @@ void farsumq(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -319,18 +314,18 @@ void farsumq(field_type *field1, field_type field2)
 	  }
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
       if ( field2.memtype == MEMTYPE_FLOAT )
         {
-          for ( int i = 0; i < len; i++ ) array1[i] += ((double)array2f[i])*array2f[i];
+          for ( size_t i = 0; i < len; i++ ) array1[i] += ((double)array2f[i])*array2f[i];
         }
       else
         {
-          for ( int i = 0; i < len; i++ ) array1[i] += array2[i]*array2[i];
+          for ( size_t i = 0; i < len; i++ ) array1[i] += array2[i]*array2[i];
         }
     }
 }
@@ -341,8 +336,8 @@ void farsumqw(field_type *field1, field_type field2, double w)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -350,14 +345,13 @@ void farsumqw(field_type *field1, field_type field2, double w)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -367,12 +361,12 @@ void farsumqw(field_type *field1, field_type field2, double w)
 	  }
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] += w*array2[i]*array2[i];
     }
 }
@@ -383,8 +377,8 @@ void farsub(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -392,23 +386,22 @@ void farsub(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] = SUBMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] -= array2[i];
     }
 }
@@ -419,8 +412,8 @@ void farmul(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -428,22 +421,22 @@ void farmul(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] = MULMN(array1[i], array2[i]);
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] *= array2[i];
     }
 }
@@ -461,15 +454,15 @@ void fardiv(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  for ( int i = 0; i < len; i++ ) 
+  for ( size_t i = 0; i < len; i++ ) 
     array1[i] = DIVMN(array1[i], array2[i]);
 
   field1->nmiss = 0;
-  for ( int i = 0; i < len; i++ )
+  for ( size_t i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
@@ -486,16 +479,15 @@ void faratan2(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
-  for ( int i = 0; i < len; i++ ) 
+  for ( size_t i = 0; i < len; i++ ) 
     array1[i] = DBL_IS_EQUAL(array1[i],missval1) || DBL_IS_EQUAL(array2[i],missval2) ? missval1 : atan2(array1[i], array2[i]);
 
   field1->nmiss = 0;
-  for ( int i = 0; i < len; i++ )
+  for ( size_t i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
@@ -505,24 +497,24 @@ void farsetmiss(field_type *field1, field_type field2)
   int nwpv  = field1->nwpv;
   int grid1 = field1->grid;
   int grid2 = field2.grid;
-  int nmiss1 = field1->nmiss;
+  size_t nmiss1 = field1->nmiss;
   double missval1 = field1->missval;
   double *restrict array1 = field1->ptr;
   const double *restrict array2 = field2.ptr;
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 )
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
         array1[i] = DBL_IS_EQUAL(array1[i],missval1) ? array2[i] : array1[i];
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
 }
@@ -533,8 +525,8 @@ void farmin(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -542,14 +534,13 @@ void farmin(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	{
 	  array1[i] = DBL_IS_EQUAL(array2[i], missval2) ? array1[i] :
 	              DBL_IS_EQUAL(array1[i], missval1) ? array2[i] :
@@ -557,12 +548,12 @@ void farmin(field_type *field1, field_type field2)
 	}
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	array1[i] = MIN(array1[i], array2[i]);
     }
 }
@@ -573,8 +564,8 @@ void farmax(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -582,14 +573,13 @@ void farmax(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	{
 	  array1[i] = DBL_IS_EQUAL(array2[i], missval2) ? array1[i] :
 	              DBL_IS_EQUAL(array1[i], missval1) ? array2[i] :
@@ -597,12 +587,12 @@ void farmax(field_type *field1, field_type field2)
 	}
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	array1[i] = MAX(array1[i], array2[i]);
     }
 }
@@ -613,8 +603,8 @@ void farvar(field_type *field1, field_type field2, field_type field3, int diviso
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1  = field1->ptr;
@@ -624,14 +614,13 @@ void farvar(field_type *field1, field_type field2, field_type field3, int diviso
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( (nmiss1 || nmiss2) /*&& (DBL_IS_NAN(missval1) || DBL_IS_NAN(missval2))*/ )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         {
           temp      = DIV( MULMN(array1[i], array1[i]), array3[i]);
           array1[i] = DIV( SUBMN(array2[i], temp), array3[i]-divisor);
@@ -640,7 +629,7 @@ void farvar(field_type *field1, field_type field2, field_type field3, int diviso
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         {
           temp      = DIV( MUL(array1[i], array1[i]), array3[i]);
           array1[i] = DIV( SUB(array2[i], temp), array3[i]-divisor);
@@ -662,15 +651,14 @@ void farstd(field_type *field1, field_type field2, field_type field3, int diviso
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   farvar(field1, field2, field3, divisor);
 
-  int nmiss = 0;
-  for ( int i = 0; i < len; i++ )
+  size_t nmiss = 0;
+  for ( size_t i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
       {
 	array1[i] = missval1;
@@ -689,8 +677,8 @@ void farcvar(field_type *field1, field_type field2, int nsets, int divisor)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   const int nsetx = nsets - divisor;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
@@ -700,18 +688,17 @@ void farcvar(field_type *field1, field_type field2, int nsets, int divisor)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nsetx == 0 )
     {
-      for ( int i = 0; i < len; i++ ) array1[i] = missval1;
+      for ( size_t i = 0; i < len; i++ ) array1[i] = missval1;
     }
   else if ( (nmiss1 || nmiss2) /*&& (DBL_IS_NAN(missval1) || DBL_IS_NAN(missval2))*/ )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         {
           temp      = MULMN(array1[i], array1[i]) / nsets;
           array1[i] = SUBMN(array2[i], temp) / nsetx;
@@ -720,7 +707,7 @@ void farcvar(field_type *field1, field_type field2, int nsets, int divisor)
     }
   else
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
         {
           temp      = MUL(array1[i], array1[i]) / nsets;
           array1[i] = SUB(array2[i], temp) / nsetx;
@@ -742,15 +729,14 @@ void farcstd(field_type *field1, field_type field2, int nsets, int divisor)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   farcvar(field1, field2, nsets, divisor);
 
-  int nmiss = 0;
-  for ( int i = 0; i < len; i++ )
+  size_t nmiss = 0;
+  for ( size_t i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) || array1[i] < 0 )
       {
 	array1[i] = missval1;
@@ -769,7 +755,7 @@ void farmoq(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -777,26 +763,25 @@ void farmoq(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  array1[i] = array2[i]*array2[i];
 	else
 	  array1[i] = missval1;
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] = array2[i]*array2[i];
     }
 }
@@ -807,7 +792,7 @@ void farmoqw(field_type *field1, field_type field2, double w)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -815,26 +800,25 @@ void farmoqw(field_type *field1, field_type field2, double w)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  array1[i] = w*array2[i]*array2[i];
 	else
 	  array1[i] = missval1;
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] = w*array2[i]*array2[i];
     }
 }
@@ -857,8 +841,8 @@ void farcount(field_type *field1, field_type field2)
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
   int grid2  = field2.grid;
-  int nmiss1 = field1->nmiss;
-  int nmiss2 = field2.nmiss;
+  size_t nmiss1 = field1->nmiss;
+  size_t nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
@@ -866,14 +850,13 @@ void farcount(field_type *field1, field_type field2)
 
   if ( nwpv != 2 ) nwpv = 1;
 
-  int len = nwpv*gridInqSize(grid1);
-
+  size_t len = nwpv*gridInqSize(grid1);
   if ( len != (nwpv*gridInqSize(grid2)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
   if ( nmiss1 > 0 || nmiss2 > 0 )
     {
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( !DBL_IS_EQUAL(array2[i], missval2) )
 	  {
 	    if ( !DBL_IS_EQUAL(array1[i], missval1) )
@@ -883,12 +866,12 @@ void farcount(field_type *field1, field_type field2)
 	  }
 
       field1->nmiss = 0;
-      for ( int i = 0; i < len; i++ )
+      for ( size_t i = 0; i < len; i++ )
 	if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
     }
   else
     {
-      for ( int i = 0; i < len; i++ ) 
+      for ( size_t i = 0; i < len; i++ ) 
 	array1[i] += 1.0;
     }
 }
diff --git a/src/fieldc.cc b/src/fieldc.cc
index 5bef4b5..1affa15 100644
--- a/src/fieldc.cc
+++ b/src/fieldc.cc
@@ -38,7 +38,7 @@ void farcmul(field_type *field, double rconst)
   int i, len;
   int    nwpv     = field->nwpv;
   int    grid     = field->grid;
-  int    nmiss    = field->nmiss;
+  size_t nmiss    = field->nmiss;
   double missval1 = field->missval;
   double missval2 = field->missval;
   double *array   = field->ptr;
@@ -69,7 +69,7 @@ void farcdiv(field_type *field, double rconst)
 {
   int i, len;
   int    grid     = field->grid;
-  int    nmiss    = field->nmiss;
+  size_t nmiss    = field->nmiss;
   double missval1 = field->missval;
   double missval2 = field->missval;
   double *array   = field->ptr;
@@ -95,7 +95,7 @@ void farcadd(field_type *field, double rconst)
 {
   int i, len;
   int    grid     = field->grid;
-  int    nmiss    = field->nmiss;
+  size_t nmiss    = field->nmiss;
   double missval1 = field->missval;
   double missval2 = field->missval;
   double *array   = field->ptr;
diff --git a/src/fieldmer.cc b/src/fieldmer.cc
index 784a22b..8c67792 100644
--- a/src/fieldmer.cc
+++ b/src/fieldmer.cc
@@ -43,9 +43,9 @@ void merfun(field_type field1, field_type *field2, int function)
 void mermin(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmin = 0;
@@ -85,9 +85,9 @@ void mermin(field_type field1, field_type *field2)
 void mermax(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmax = 0;
@@ -127,9 +127,9 @@ void mermax(field_type field1, field_type *field2)
 void merrange(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmin = 0;
@@ -186,9 +186,9 @@ void mersum(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   long   nvals   = 0;
-  int    rnmiss  = 0;
+  size_t rnmiss  = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rsum = 0;
@@ -232,9 +232,9 @@ void mersum(field_type field1, field_type *field2)
 void mermeanw(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval1 = field1.missval;
   double missval2 = field1.missval;
   double *array  = field1.ptr;
@@ -281,9 +281,9 @@ void mermeanw(field_type field1, field_type *field2)
 void meravgw(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid     = field1.grid;
-  int    nmiss    = field1.nmiss;
+  size_t nmiss    = field1.nmiss;
   double missval1 = field1.missval;
   double missval2 = field1.missval;
   double *array   = field1.ptr;
@@ -326,7 +326,7 @@ void meravgw(field_type field1, field_type *field2)
 }
 
 static
-void prevarsum_merw(const double *restrict array, const double *restrict w, int nx, int ny, int nmiss, 
+void prevarsum_merw(const double *restrict array, const double *restrict w, int nx, int ny, size_t nmiss, 
                     double missval, double *restrict rsum, double *restrict rsumw, double *restrict rsumq, double *restrict rsumwq)
 { 
   *rsum   = 0;
@@ -361,9 +361,9 @@ void prevarsum_merw(const double *restrict array, const double *restrict w, int
 
 void mervarw(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double *w      = field1.weight;
@@ -391,9 +391,9 @@ void mervarw(field_type field1, field_type *field2)
 
 void mervar1w(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double *w      = field1.weight;
@@ -421,7 +421,7 @@ void mervar1w(field_type field1, field_type *field2)
 
 void merstdw(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
   double missval = field1.missval;
   double rstd;
@@ -445,7 +445,7 @@ void merstdw(field_type field1, field_type *field2)
 
 void merstd1w(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
   double missval = field1.missval;
   double rstd;
@@ -470,9 +470,9 @@ void merstd1w(field_type field1, field_type *field2)
 void merpctl(field_type field1, field_type *field2, int p)
 {
   long   i, j, l;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
 
diff --git a/src/fieldzon.cc b/src/fieldzon.cc
index 3474338..944530e 100644
--- a/src/fieldzon.cc
+++ b/src/fieldzon.cc
@@ -43,9 +43,9 @@ void zonfun(field_type field1, field_type *field2, int function)
 void zonmin(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmin = 0;
@@ -85,9 +85,9 @@ void zonmin(field_type field1, field_type *field2)
 void zonmax(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmax = 0;
@@ -127,9 +127,9 @@ void zonmax(field_type field1, field_type *field2)
 void zonrange(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rmin = 0;
@@ -186,9 +186,9 @@ void zonsum(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   long   nvals   = 0;
-  int    rnmiss  = 0;
+  size_t rnmiss  = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
   double rsum = 0;
@@ -232,9 +232,9 @@ void zonsum(field_type field1, field_type *field2)
 void zonmean(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid     = field1.grid;
-  int    nmiss    = field1.nmiss;
+  size_t nmiss    = field1.nmiss;
   double missval1 = field1.missval;
   double missval2 = field1.missval;
   double *array   = field1.ptr;
@@ -279,9 +279,9 @@ void zonmean(field_type field1, field_type *field2)
 void zonavg(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid     = field1.grid;
-  int    nmiss    = field1.nmiss;
+  size_t nmiss    = field1.nmiss;
   double missval1 = field1.missval;
   double missval2 = field1.missval;
   double *array   = field1.ptr;
@@ -322,7 +322,7 @@ void zonavg(field_type field1, field_type *field2)
 }
 
 static
-void prevarsum_zon(const double *restrict array, int nx, int nmiss,  double missval, 
+void prevarsum_zon(const double *restrict array, int nx, size_t nmiss,  double missval, 
                    double *rsum, double *rsumw, double *rsumq, double *rsumwq)
 {
   double w = 1./nx;
@@ -358,9 +358,9 @@ void prevarsum_zon(const double *restrict array, int nx, int nmiss,  double miss
 
 void zonvar(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid     = field1.grid;
-  int    nmiss    = field1.nmiss;
+  size_t nmiss    = field1.nmiss;
   double missval1 = field1.missval;
   double *array   = field1.ptr;
   double rsum = 0, rsumw = 0, rvar = 0;
@@ -387,9 +387,9 @@ void zonvar(field_type field1, field_type *field2)
 
 void zonvar1(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid     = field1.grid;
-  int    nmiss    = field1.nmiss;
+  size_t nmiss    = field1.nmiss;
   double missval1 = field1.missval;
   double *array   = field1.ptr;
   double rsum = 0, rsumw = 0, rvar = 0;
@@ -416,7 +416,7 @@ void zonvar1(field_type field1, field_type *field2)
 
 void zonstd(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
   double missval = field1.missval;
   double rstd;
@@ -440,7 +440,7 @@ void zonstd(field_type field1, field_type *field2)
 
 void zonstd1(field_type field1, field_type *field2)
 {
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
   double missval = field1.missval;
   double rstd;
@@ -465,9 +465,9 @@ void zonstd1(field_type field1, field_type *field2)
 void zonpctl(field_type field1, field_type *field2, int p)
 {
   long   i, j, l;
-  int    rnmiss = 0;
+  size_t rnmiss = 0;
   int    grid    = field1.grid;
-  int    nmiss   = field1.nmiss;
+  size_t nmiss   = field1.nmiss;
   double missval = field1.missval;
   double *array  = field1.ptr;
 
diff --git a/src/getMemorySize.c b/src/getMemorySize.c
new file mode 100644
index 0000000..4b15ac7
--- /dev/null
+++ b/src/getMemorySize.c
@@ -0,0 +1,97 @@
+/*
+ * Author:  David Robert Nadeau
+ * Site:    http://NadeauSoftware.com/
+ * License: Creative Commons Attribution 3.0 Unported License
+ *          http://creativecommons.org/licenses/by/3.0/deed.en_US
+ */
+
+#if defined(_WIN32)
+#include <Windows.h>
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#if defined(BSD)
+#include <sys/sysctl.h>
+#endif
+
+#else
+#error "Unable to define getMemorySize( ) for an unknown OS."
+#endif
+
+
+
+/**
+ * Returns the size of physical memory (RAM) in bytes.
+ */
+size_t getMemorySize(void)
+{
+#if defined(_WIN32) && (defined(__CYGWIN__) || defined(__CYGWIN32__))
+	/* Cygwin under Windows. ------------------------------------ */
+	/* New 64-bit MEMORYSTATUSEX isn't available.  Use old 32.bit */
+	MEMORYSTATUS status;
+	status.dwLength = sizeof(status);
+	GlobalMemoryStatus( &status );
+	return (size_t)status.dwTotalPhys;
+
+#elif defined(_WIN32)
+	/* Windows. ------------------------------------------------- */
+	/* Use new 64-bit MEMORYSTATUSEX, not old 32-bit MEMORYSTATUS */
+	MEMORYSTATUSEX status;
+	status.dwLength = sizeof(status);
+	GlobalMemoryStatusEx( &status );
+	return (size_t)status.ullTotalPhys;
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+	/* UNIX variants. ------------------------------------------- */
+	/* Prefer sysctl() over sysconf() except sysctl() HW_REALMEM and HW_PHYSMEM */
+
+#if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64))
+	int mib[2];
+	mib[0] = CTL_HW;
+#if defined(HW_MEMSIZE)
+	mib[1] = HW_MEMSIZE;		/* OSX. --------------------- */
+#elif defined(HW_PHYSMEM64)
+	mib[1] = HW_PHYSMEM64;		/* NetBSD, OpenBSD. --------- */
+#endif
+	int64_t size = 0;		/* 64-bit */
+	size_t len = sizeof( size );
+	if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
+		return (size_t)size;
+	return 0L;			/* Failed? */
+
+#elif defined(_SC_AIX_REALMEM)
+	/* AIX. ----------------------------------------------------- */
+	return (size_t)sysconf( _SC_AIX_REALMEM ) * (size_t)1024L;
+
+#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
+	/* FreeBSD, Linux, OpenBSD, and Solaris. -------------------- */
+	return (size_t)sysconf( _SC_PHYS_PAGES ) *
+		(size_t)sysconf( _SC_PAGESIZE );
+
+#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE)
+	/* Legacy. -------------------------------------------------- */
+	return (size_t)sysconf( _SC_PHYS_PAGES ) *
+		(size_t)sysconf( _SC_PAGE_SIZE );
+
+#elif defined(CTL_HW) && (defined(HW_PHYSMEM) || defined(HW_REALMEM))
+	/* DragonFly BSD, FreeBSD, NetBSD, OpenBSD, and OSX. -------- */
+	int mib[2];
+	mib[0] = CTL_HW;
+#if defined(HW_REALMEM)
+	mib[1] = HW_REALMEM;		/* FreeBSD. ----------------- */
+#elif defined(HW_PYSMEM)
+	mib[1] = HW_PHYSMEM;		/* Others. ------------------ */
+#endif
+	unsigned int size = 0;		/* 32-bit */
+	size_t len = sizeof( size );
+	if ( sysctl( mib, 2, &size, &len, NULL, 0 ) == 0 )
+		return (size_t)size;
+	return 0L;			/* Failed? */
+#endif /* sysctl and sysconf variants */
+
+#else
+	return 0L;			/* Unknown OS. */
+#endif
+}
diff --git a/src/getRSS.c b/src/getRSS.c
new file mode 100644
index 0000000..574d373
--- /dev/null
+++ b/src/getRSS.c
@@ -0,0 +1,122 @@
+/*
+ * Author:  David Robert Nadeau
+ * Site:    http://NadeauSoftware.com/
+ * License: Creative Commons Attribution 3.0 Unported License
+ *          http://creativecommons.org/licenses/by/3.0/deed.en_US
+ */
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <psapi.h>
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#include <sys/resource.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include <mach/mach.h>
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+#include <fcntl.h>
+#include <procfs.h>
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+#include <stdio.h>
+
+#endif
+
+#else
+#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
+#endif
+
+
+
+
+
+/**
+ * Returns the peak (maximum so far) resident set size (physical
+ * memory use) measured in bytes, or zero if the value cannot be
+ * determined on this OS.
+ */
+size_t getPeakRSS( )
+{
+#if defined(_WIN32)
+	/* Windows -------------------------------------------------- */
+	PROCESS_MEMORY_COUNTERS info;
+	GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+	return (size_t)info.PeakWorkingSetSize;
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+	/* AIX and Solaris ------------------------------------------ */
+	struct psinfo psinfo;
+	int fd = -1;
+	if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
+		return (size_t)0L;		/* Can't open? */
+	if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
+	{
+		close( fd );
+		return (size_t)0L;		/* Can't read? */
+	}
+	close( fd );
+	return (size_t)(psinfo.pr_rssize * 1024L);
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+	/* BSD, Linux, and OSX -------------------------------------- */
+	struct rusage rusage;
+	getrusage( RUSAGE_SELF, &rusage );
+#if defined(__APPLE__) && defined(__MACH__)
+	return (size_t)rusage.ru_maxrss;
+#else
+	return (size_t)(rusage.ru_maxrss * 1024L);
+#endif
+
+#else
+	/* Unknown OS ----------------------------------------------- */
+	return (size_t)0L;			/* Unsupported. */
+#endif
+}
+
+
+
+
+
+/**
+ * Returns the current resident set size (physical memory use) measured
+ * in bytes, or zero if the value cannot be determined on this OS.
+ */
+size_t getCurrentRSS( )
+{
+#if defined(_WIN32)
+	/* Windows -------------------------------------------------- */
+	PROCESS_MEMORY_COUNTERS info;
+	GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+	return (size_t)info.WorkingSetSize;
+
+#elif defined(__APPLE__) && defined(__MACH__)
+	/* OSX ------------------------------------------------------ */
+	struct mach_task_basic_info info;
+	mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
+	if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
+		(task_info_t)&info, &infoCount ) != KERN_SUCCESS )
+		return (size_t)0L;		/* Can't access? */
+	return (size_t)info.resident_size;
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+	/* Linux ---------------------------------------------------- */
+	long rss = 0L;
+	FILE* fp = NULL;
+	if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
+		return (size_t)0L;		/* Can't open? */
+	if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
+	{
+		fclose( fp );
+		return (size_t)0L;		/* Can't read? */
+	}
+	fclose( fp );
+	return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
+
+#else
+	/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
+	return (size_t)0L;			/* Unsupported. */
+#endif
+}
diff --git a/src/grid.cc b/src/grid.cc
index 486cce7..64059f6 100644
--- a/src/grid.cc
+++ b/src/grid.cc
@@ -683,7 +683,7 @@ int qu2reg_subarea(size_t gridsize, int np, double xfirst, double xlast,
 }
 
 
-void field2regular(int gridID1, int gridID2, double missval, double *array, int nmiss, int lnearest)
+void field2regular(int gridID1, int gridID2, double missval, double *array, size_t nmiss, int lnearest)
 {
   int gridtype = gridInqType(gridID1);
   if ( gridtype != GRID_GAUSSIAN_REDUCED ) cdoAbort("Not a reduced Gaussian grid!");
@@ -691,7 +691,7 @@ void field2regular(int gridID1, int gridID2, double missval, double *array, int
   int lmiss = nmiss > 0;
   int lperio = 1;
 
-  int ny = gridInqYsize(gridID1);
+  size_t ny = gridInqYsize(gridID1);
   int np = gridInqNP(gridID1);
 
   int *rowlon = (int*) Malloc(ny*sizeof(int));
@@ -703,7 +703,7 @@ void field2regular(int gridID1, int gridID2, double missval, double *array, int
   double xlast  = xfirstandlast[1];
 
   int iret;
-  int nx = 0;
+  size_t nx = 0;
   if ( fabs(xfirst) > 0 || (np > 0 && fabs(xlast - (360.0-90.0/np)) > 90.0/np) )
     {
       nx = qu2reg_subarea(gridInqSize(gridID1), np, xfirst, xlast, array, rowlon, ny, missval, &iret, lmiss, lperio, lnearest);
@@ -1531,7 +1531,7 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
   int *grid_mask = NULL;
 
   int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
   
   if ( gridtype == GRID_GME )
     {
@@ -1542,7 +1542,7 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
 
   double total_area = 0;
   int nvals = 0;
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     {
       if ( grid_mask )
 	if ( grid_mask[i] == 0 ) continue;
@@ -1552,7 +1552,7 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
 
   if ( cdoVerbose ) cdoPrint("Total area = %g", total_area);
 
-  for ( int i = 0; i < gridsize; i++ )
+  for ( size_t i = 0; i < gridsize; i++ )
     {
       if ( grid_mask )
 	if ( grid_mask[i] == 0 )
@@ -1653,7 +1653,7 @@ int gridWeights(int gridID, double *grid_wgts)
   int w_status = 1;
   int a_status = 0;
 
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
   int gridtype = gridInqType(gridID);
   int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1; 
   
@@ -1690,7 +1690,7 @@ int gridWeights(int gridID, double *grid_wgts)
     }
   else
     {
-      for ( int i = 0; i < gridsize; ++i ) grid_wgts[i] = 1./gridsize;
+      for ( size_t i = 0; i < gridsize; ++i ) grid_wgts[i] = 1./gridsize;
     }
   /*
   for ( i = 0; i < gridsize; ++i ) 
diff --git a/src/grid.h b/src/grid.h
index a8a52b9..4da6e48 100644
--- a/src/grid.h
+++ b/src/grid.h
@@ -65,7 +65,7 @@ int gridToUnstructuredSelecton(int gridID1, size_t selectionSize, int *selection
 int gridToCurvilinear(int gridID, int lbounds);
 int gridCurvilinearToRegular(int gridID);
 int gridToRegular(int gridID);
-void field2regular(int gridID1, int gridID2, double missval, double *array, int nmiss, int lnearest);
+void field2regular(int gridID1, int gridID2, double missval, double *array, size_t nmiss, int lnearest);
 
 /* GME grid */
 struct cart {
diff --git a/src/grid_area.cc b/src/grid_area.cc
index b6f6ba7..3586eb8 100644
--- a/src/grid_area.cc
+++ b/src/grid_area.cc
@@ -286,9 +286,8 @@ int gridGenArea(int gridID, double* area)
   int status = 0;
   bool lgrid_gen_bounds = false;
   bool lgriddestroy = false;
-  long nv;
 
-  long gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
   int gridtype = gridInqType(gridID);
   int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1; 
 
@@ -340,10 +339,7 @@ int gridGenArea(int gridID, double* area)
 
   gridtype = gridInqType(gridID);
 
-  if ( gridtype == GRID_UNSTRUCTURED )
-    nv = gridInqNvertex(gridID);
-  else
-    nv = 4;
+  size_t nv = ( gridtype == GRID_UNSTRUCTURED ) ? gridInqNvertex(gridID) : 4;
 
   if ( gridInqYvals(gridID, NULL) == 0 || gridInqXvals(gridID, NULL) == 0 )
     {
@@ -382,8 +378,8 @@ int gridGenArea(int gridID, double* area)
     {
       if ( lgrid_gen_bounds )
 	{
-	  int nlon = gridInqXsize(gridID);
-	  int nlat = gridInqYsize(gridID);
+	  size_t nlon = gridInqXsize(gridID);
+	  size_t nlat = gridInqYsize(gridID);
 	  double dlon = 0;
 	  if ( nlon == 1 ) dlon = 1;
 
@@ -413,7 +409,7 @@ int gridGenArea(int gridID, double* area)
 #pragma omp parallel for default(none)  \
   shared(findex,gridsize,area,nv,grid_corner_lon,grid_corner_lat,grid_center_lon,grid_center_lat)
 #endif
-  for ( long i = 0; i < gridsize; ++i )
+  for ( size_t i = 0; i < gridsize; ++i )
     {
       int lprogress = 1;
       if ( cdo_omp_get_thread_num() != 0 ) lprogress = 0;
@@ -434,16 +430,16 @@ int gridGenArea(int gridID, double* area)
   if ( cdoVerbose )
     {
       double total_area = 0;
-      for ( long i = 0; i < gridsize; ++i ) total_area += area[i];
+      for ( size_t i = 0; i < gridsize; ++i ) total_area += area[i];
       cdoPrint("Total area = %g steradians", total_area);
     }
 
   if ( gridsize < 20 )
     {
       double total_area = 0;
-      for ( long i = 0; i < gridsize; ++i ) total_area += area[i];
+      for ( size_t i = 0; i < gridsize; ++i ) total_area += area[i];
       int nzero = 0;
-      for ( long i = 0; i < gridsize; ++i ) if ( IS_EQUAL(area[i], 0.) ) nzero++;
+      for ( size_t i = 0; i < gridsize; ++i ) if ( IS_EQUAL(area[i], 0.) ) nzero++;
       if ( IS_EQUAL(total_area, 0.) ) status = 2;
     }
 
diff --git a/src/grid_from_name.cc b/src/grid_from_name.cc
index 2b94d14..6164218 100644
--- a/src/grid_from_name.cc
+++ b/src/grid_from_name.cc
@@ -90,14 +90,14 @@ void gen_grid_lonlat(griddes_t *grid, const char *pline, double inc, double lon1
   if ( lon1 >= lon2 || lat1 >= lat2 )
     cdoAbort("Invalid grid box: lon1=%g lon2=%g lat1=%g lat2=%g", lon1, lon2, lat1, lat2);
 
-  int nlon = (int) ((lon2 - lon1)/inc + 0.5);
-  int nlat = (int) ((lat2 - lat1)/inc + 0.5);
+  size_t nlon = (size_t) ((lon2 - lon1)/inc + 0.5);
+  size_t nlat = (size_t) ((lat2 - lat1)/inc + 0.5);
 
   double *xvals = (double*) Malloc(nlon*sizeof(double));
   double *yvals = (double*) Malloc(nlat*sizeof(double));
 
-  for ( int i = 0; i < nlon; ++i ) xvals[i] = lon1 + inc/2 + i*inc;
-  for ( int i = 0; i < nlat; ++i ) yvals[i] = lat1 + inc/2 + i*inc;
+  for ( size_t i = 0; i < nlon; ++i ) xvals[i] = lon1 + inc/2 + i*inc;
+  for ( size_t i = 0; i < nlat; ++i ) yvals[i] = lat1 + inc/2 + i*inc;
 
   if ( gridtype == GRID_LONLAT )
     {
@@ -110,11 +110,11 @@ void gen_grid_lonlat(griddes_t *grid, const char *pline, double inc, double lon1
     }
   else
     {
-      double gridsize = nlon*nlat;
+      size_t gridsize = nlon*nlat;
       double *xvals2D = (double*) Malloc(gridsize*sizeof(double));
       double *yvals2D = (double*) Malloc(gridsize*sizeof(double));
-      for ( int j = 0; j < nlat; j++ )
-        for ( int i = 0; i < nlon; i++ )
+      for ( size_t j = 0; j < nlat; j++ )
+        for ( size_t i = 0; i < nlon; i++ )
           {
             xvals2D[j*nlon+i] = xvals[i];
             yvals2D[j*nlon+i] = yvals[j];
diff --git a/src/grid_print.cc b/src/grid_print.cc
index c805616..52df415 100644
--- a/src/grid_print.cc
+++ b/src/grid_print.cc
@@ -139,18 +139,18 @@ void grid_print_attributes(FILE *fp, int gridID)
 static
 void grid_print_kernel(int gridID, int opt, FILE *fp)
 {
-  int xdim, ydim;
+  size_t xdim, ydim;
   char attstr[CDI_MAX_NAME];
   char attstr2[CDI_MAX_NAME];
-  size_t nxvals = (size_t) gridInqXvals(gridID, NULL);
-  size_t nyvals = (size_t) gridInqYvals(gridID, NULL);
+  size_t nxvals = gridInqXvals(gridID, NULL);
+  size_t nyvals = gridInqYvals(gridID, NULL);
   size_t nxbounds = (size_t) gridInqXbounds(gridID, NULL);
   size_t nybounds = (size_t) gridInqYbounds(gridID, NULL);
 
+  size_t gridsize = gridInqSize(gridID);
+  size_t xsize    = gridInqXsize(gridID);
+  size_t ysize    = gridInqYsize(gridID);
   int type     = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
-  int xsize    = gridInqXsize(gridID);
-  int ysize    = gridInqYsize(gridID);
   int nvertex  = gridInqNvertex(gridID);
   int prec     = gridInqDatatype(gridID);
   int xstrlen  = gridInqXIsc(gridID);
@@ -159,35 +159,35 @@ void grid_print_kernel(int gridID, int opt, FILE *fp)
   char **xcvals = NULL;
   if ( xstrlen )
     {
-      xcvals = (char **) Malloc(xsize * sizeof(char *));
-      for ( int i = 0; i < xsize; i++ ) xcvals[i] = (char*) Malloc((xstrlen+1) * sizeof(char));
+      xcvals = (char **) Malloc(xsize*sizeof(char *));
+      for ( size_t i = 0; i < xsize; i++ ) xcvals[i] = (char*) Malloc((xstrlen+1)*sizeof(char));
       gridInqXCvals(gridID, xcvals);
-      for ( int i = 0; i < xsize; i++ ) xcvals[i][xstrlen] = 0;
-      for ( int i = 0; i < xsize; i++ ) 
+      for ( size_t i = 0; i < xsize; i++ ) xcvals[i][xstrlen] = 0;
+      for ( size_t i = 0; i < xsize; i++ ) 
         for ( int k = xstrlen-1; k; k-- ) if ( xcvals[i][k] == ' ' ) xcvals[i][k] = 0; else break;
     }
 
   char **ycvals = NULL;
   if ( ystrlen )
     {
-      ycvals = (char **) Malloc(ysize * sizeof(char *));
-      for ( int i = 0; i < ysize; i++ ) ycvals[i] = (char*) Malloc((ystrlen+1) * sizeof(char));
+      ycvals = (char **) Malloc(ysize*sizeof(char *));
+      for ( size_t i = 0; i < ysize; i++ ) ycvals[i] = (char*) Malloc((ystrlen+1)*sizeof(char));
       gridInqYCvals(gridID, ycvals);
-      for ( int i = 0; i < ysize; i++ ) ycvals[i][ystrlen] = 0;
-      for ( int i = 0; i < ysize; i++ ) 
+      for ( size_t i = 0; i < ysize; i++ ) ycvals[i][ystrlen] = 0;
+      for ( size_t i = 0; i < ysize; i++ ) 
         for ( int k = ystrlen-1; k; k-- ) if ( ycvals[i][k] == ' ' ) ycvals[i][k] = 0; else break;
     }
 
   int dig = (prec == CDI_DATATYPE_FLT64) ? CDO_dbl_digits : CDO_flt_digits;
 
-  fprintf(fp, "gridtype  = %s\n" "gridsize  = %d\n", gridNamePtr(type), gridsize);
+  fprintf(fp, "gridtype  = %s\n" "gridsize  = %zu\n", gridNamePtr(type), gridsize);
 
   if ( type != GRID_GME )
     {
       if ( type != GRID_UNSTRUCTURED && type != GRID_SPECTRAL && type != GRID_FOURIER )
         {
-          if ( xsize > 0 ) fprintf(fp, "xsize     = %d\n", xsize);
-          if ( ysize > 0 ) fprintf(fp, "ysize     = %d\n", ysize);
+          if ( xsize > 0 ) fprintf(fp, "xsize     = %zu\n", xsize);
+          if ( ysize > 0 ) fprintf(fp, "ysize     = %zu\n", ysize);
         }
 
       if ( nxvals > 0 || xcvals )
@@ -312,11 +312,11 @@ void grid_print_kernel(int gridID, int opt, FILE *fp)
               fprintf(fp, "x%ss  = \"%.*s\"", attstr, xstrlen, xcvals[0]);
             else
               fprintf(fp, "xstrings  = \"%.*s\"", xstrlen, xcvals[0]);
-            for ( int i = 1; i < xsize; i++ )
+            for ( size_t i = 1; i < xsize; i++ )
               fprintf(fp, ", \"%.*s\"", xstrlen, xcvals[i]);
             fprintf(fp, "\n");
 
-            for ( int i = 0; i < xsize; i++ ) Free(xcvals[i]);
+            for ( size_t i = 0; i < xsize; i++ ) Free(xcvals[i]);
             Free(xcvals);
           }
 
@@ -362,11 +362,11 @@ void grid_print_kernel(int gridID, int opt, FILE *fp)
               fprintf(fp, "x%ss  = \"%.*s\"", attstr, ystrlen, ycvals[0]);
             else
               fprintf(fp, "ystrings  = \"%.*s\"", ystrlen, ycvals[0]);
-            for ( int i = 1; i < ysize; i++ )
+            for ( size_t i = 1; i < ysize; i++ )
               fprintf(fp, ", \"%.*s\"", ystrlen, ycvals[i]);
             fprintf(fp, "\n");
 
-            for ( int i = 0; i < ysize; i++ ) Free(ycvals[i]);
+            for ( size_t i = 0; i < ysize; i++ ) Free(ycvals[i]);
             Free(ycvals);
           }
 
diff --git a/src/grid_read.cc b/src/grid_read.cc
index b2c44c9..8da1f02 100644
--- a/src/grid_read.cc
+++ b/src/grid_read.cc
@@ -101,11 +101,11 @@ void grid_read_data(size_t ikv, size_t nkv, kvmap_t *kvmap, griddes_t *grid, siz
           else if ( STR_IS_EQ(datatype, "float") )   grid->datatype = CDI_DATATYPE_FLT32;
 	  else cdoAbort("Invalid datatype : %s (zaxis description file: %s)", datatype, dname);
         }
-      else if ( STR_IS_EQ(key, "gridsize") )       grid->size = parameter2int(value);
-      else if ( STR_IS_EQ(key, "xsize") )          grid->xsize = parameter2int(value);
-      else if ( STR_IS_EQ(key, "nlon") )           grid->xsize = parameter2int(value);
-      else if ( STR_IS_EQ(key, "ysize") )          grid->ysize = parameter2int(value);
-      else if ( STR_IS_EQ(key, "nlat") )           grid->ysize = parameter2int(value);
+      else if ( STR_IS_EQ(key, "gridsize") )       grid->size = parameter2sizet(value);
+      else if ( STR_IS_EQ(key, "xsize") )          grid->xsize = parameter2sizet(value);
+      else if ( STR_IS_EQ(key, "nlon") )           grid->xsize = parameter2sizet(value);
+      else if ( STR_IS_EQ(key, "ysize") )          grid->ysize = parameter2sizet(value);
+      else if ( STR_IS_EQ(key, "nlat") )           grid->ysize = parameter2sizet(value);
       else if ( STR_IS_EQ(key, "truncation") )     grid->ntr = parameter2int(value);
       else if ( STR_IS_EQ(key, "np") )             grid->np = parameter2int(value);
       else if ( STR_IS_EQ(key, "complexpacking") ) grid->lcomplex = parameter2int(value);
diff --git a/src/grid_search.cc b/src/grid_search.cc
index e3e24e1..9388225 100644
--- a/src/grid_search.cc
+++ b/src/grid_search.cc
@@ -1,4 +1,4 @@
-#if defined(HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #include "config.h"
 #endif
 
@@ -69,6 +69,7 @@ float distance(const float *restrict a, const float *restrict b)
 void gridsearch_set_method(const char *methodstr)
 {
   if      ( strcmp(methodstr, "kdtree")  == 0 ) gridsearch_method_nn = GS_KDTREE;
+  else if ( strcmp(methodstr, "kdsph")   == 0 ) gridsearch_method_nn = GS_KDSPH;
   else if ( strcmp(methodstr, "nearpt3") == 0 ) gridsearch_method_nn = GS_NEARPT3;
   else if ( strcmp(methodstr, "full")    == 0 ) gridsearch_method_nn = GS_FULL;
   else
@@ -76,15 +77,25 @@ void gridsearch_set_method(const char *methodstr)
 }
 
 
-struct gridsearch *gridsearch_create_reg2d(bool lcyclic, size_t nx, size_t ny, const double *restrict lons, const double *restrict lats)
+void gridsearch_extrapolate(struct gridsearch *gs)
+{
+  gs->extrapolate = true;
+}
+
+
+struct gridsearch *gridsearch_create_reg2d(bool is_cyclic, size_t dims[2], const double *restrict lons, const double *restrict lats)
 {
   struct gridsearch *gs = (struct gridsearch *) Calloc(1, sizeof(struct gridsearch));
 
-  gs->nx = nx;
-  gs->ny = ny;
+  gs->is_cyclic = is_cyclic;
+  gs->is_reg2d = true;
+  gs->dims[0] = dims[0];
+  gs->dims[1] = dims[1];
+  size_t nx = dims[0];
+  size_t ny = dims[0];
 
-  unsigned nxm = nx;
-  if ( lcyclic ) nxm++;
+  size_t nxm = nx;
+  if ( is_cyclic ) nxm++;
 
   double *reg2d_center_lon = (double *) Malloc(nxm*sizeof(double));
   double *reg2d_center_lat = (double *) Malloc(ny*sizeof(double));
@@ -156,6 +167,39 @@ struct kdNode *gs_create_kdtree(size_t n, const double *restrict lons, const dou
 }
 
 
+struct kdNode *gs_create_kdsph(size_t n, const double *restrict lons, const double *restrict lats)
+{
+  struct kd_point *pointlist = (struct kd_point *) Malloc(n * sizeof(struct kd_point)); // kd_point contains 3d point
+  // see  example_cartesian.c
+  if ( cdoVerbose ) printf("kdtree lib spherical init: n=%zu  nthreads=%d\n", n, ompNumThreads);
+  kdata_t min[2], max[2];
+  min[0] = min[1] =  1e9;
+  max[0] = max[1] = -1e9;
+  kdata_t *restrict point;
+#if defined(HAVE_OPENMP4)
+#pragma omp simd
+#endif
+  for ( size_t i = 0; i < n; i++ ) 
+    {
+      point = pointlist[i].point;
+      point[0] = lons[i];
+      point[1] = lats[i];
+      point[2] = 0; // dummy
+      for ( size_t j = 0; j < 2; ++j )
+        {
+          min[j] = point[j] < min[j] ? point[j] : min[j];
+          max[j] = point[j] > max[j] ? point[j] : max[j];
+        }
+      pointlist[i].index = i;
+    }
+
+  struct kdNode *kdt = kd_sph_buildTree(pointlist, n, min, max, ompNumThreads);
+  if ( pointlist ) Free(pointlist);
+
+  return kdt;
+}
+
+
 void gs_destroy_nearpt3(struct gsNear *near)
 {
   if ( near )
@@ -274,6 +318,7 @@ struct gridsearch *gridsearch_create_nn(size_t n, const double *restrict lons, c
   if ( n == 0 ) return gs;
 
   if      ( gs->method_nn == GS_KDTREE  ) gs->kdt  = gs_create_kdtree(n, lons, lats);
+  else if ( gs->method_nn == GS_KDSPH   ) gs->kdt  = gs_create_kdsph(n, lons, lats);
   else if ( gs->method_nn == GS_NEARPT3 ) gs->near = gs_create_nearpt3(n, lons, lats);
   else if ( gs->method_nn == GS_FULL    ) gs->full = gs_create_full(n, lons, lats);
 
@@ -320,10 +365,11 @@ double gs_set_range(double *prange)
   return range;
 }
 
-
-kdNode *gs_nearest_kdtree(kdNode *kdt, double lon, double lat, double *prange)
+static
+size_t gs_nearest_kdtree(kdNode *kdt, double lon, double lat, double *prange)
 {
-  if ( kdt == NULL ) return NULL;
+  size_t index = GS_NOT_FOUND;
+  if ( kdt == NULL ) return index;
   
   float range0 = gs_set_range(prange);
   kdata_t range = KDATA_SCALE(range0);
@@ -337,11 +383,37 @@ kdNode *gs_nearest_kdtree(kdNode *kdt, double lon, double lat, double *prange)
   if ( !(frange < range0) ) node = NULL;
   if ( prange ) *prange = frange;
 
-  return node;
+  if ( node ) index = node->index;
+
+  return index;
+}
+
+static
+size_t gs_nearest_kdsph(kdNode *kdt, double lon, double lat, double *prange)
+{
+  size_t index = GS_NOT_FOUND;
+  if ( kdt == NULL ) return index;
+  
+  float range0 = gs_set_range(prange);
+  kdata_t range = KDATA_SCALE(range0);
+
+  kdata_t point[2];
+  point[0] = lon;
+  point[1] = lat;
+
+  kdNode *node = kd_nearest(kdt, point, &range, 3);
+
+  float frange = KDATA_INVSCALE(range);
+  if ( !(frange < range0) ) node = NULL;
+  if ( prange ) *prange = frange;
+
+  if ( node ) index = node->index;
+
+  return index;
 }
 
 
-unsigned gs_nearest_nearpt3(struct gsNear *near, double lon, double lat, double *prange)
+size_t gs_nearest_nearpt3(struct gsNear *near, double lon, double lat, double *prange)
 {
   size_t index = GS_NOT_FOUND;
   if ( near == NULL ) return index;
@@ -367,7 +439,7 @@ unsigned gs_nearest_nearpt3(struct gsNear *near, double lon, double lat, double
       float range = distance(point, point0);
       if ( range < range0 )
         {
-           index = (unsigned) closestpt;
+          index = (size_t) closestpt;
            *prange = range;
         }
     }
@@ -424,23 +496,13 @@ size_t gridsearch_nearest(struct gridsearch *gs, double lon, double lat, double
 
   if ( gs )
     {
-      if ( gs->method_nn == GS_KDTREE )
-        {
-          kdNode *node = gs_nearest_kdtree(gs->kdt, lon, lat, prange);
-          if ( node ) index = (int) node->index;
-        }
-      else if ( gs->method_nn == GS_NEARPT3 )
-        {
-          index = gs_nearest_nearpt3(gs->near, lon, lat, prange);
-        }
-      else if ( gs->method_nn == GS_FULL )
-        {
-          index = gs_nearest_full(gs->full, lon, lat, prange);
-        }
-      else
-        {
-          cdoAbort("gridsearch_nearest::method_nn undefined!");
-        }
+      // clang-format off
+      if      ( gs->method_nn == GS_KDTREE )  index = gs_nearest_kdtree(gs->kdt, lon, lat, prange);
+      else if ( gs->method_nn == GS_KDSPH )   index = gs_nearest_kdsph(gs->kdt, lon, lat, prange);
+      else if ( gs->method_nn == GS_NEARPT3 ) index = gs_nearest_nearpt3(gs->near, lon, lat, prange);
+      else if ( gs->method_nn == GS_FULL )    index = gs_nearest_full(gs->full, lon, lat, prange);
+      else cdoAbort("gridsearch_nearest::method_nn undefined!");
+      // clang-format on
     }
 
   return index;
@@ -527,7 +589,7 @@ void knn_check_distance(size_t num_neighbors, const size_t *restrict nbr_add, do
 
 void gridsearch_knn_init(struct gsknn *knn)
 {
-  unsigned ndist = knn->ndist;
+  size_t ndist = knn->ndist;
   size_t *restrict add = knn->add;
   double *restrict dist = knn->dist;
 
diff --git a/src/grid_search.h b/src/grid_search.h
index a9eaf92..289bf03 100644
--- a/src/grid_search.h
+++ b/src/grid_search.h
@@ -2,24 +2,23 @@
 #define _GRID_SEARCH_H_
 
 #include <stdbool.h>
-#include <limits.h>
 #include "kdtreelib/kdtree.h"
 #include "nearpt3c.h"
 
-#define GS_NOT_FOUND  ULONG_MAX
+#define GS_NOT_FOUND  SIZE_MAX
 
 
-enum T_GRIDSEARCH_METHOD_NN  {GS_FULL=1, GS_KDTREE, GS_NEARPT3};
+enum T_GRIDSEARCH_METHOD_NN  {GS_FULL=1, GS_KDTREE, GS_KDSPH, GS_NEARPT3};
 
 struct gsFull {
-  unsigned n;
+  size_t n;
   const double *plons;
   const double *plats;
   float **pts;
 };
 
 struct gsNear {
-  unsigned n;
+  size_t n;
   const double *plons;
   const double *plats;
   Coord_T **pts;
@@ -27,9 +26,12 @@ struct gsNear {
 };
 
 struct gridsearch {
+  bool extrapolate;
+  bool is_cyclic;
+  bool is_reg2d;
   int method_nn;
   size_t n;
-  size_t nx, ny;
+  size_t dims[2];
 
   struct gsNear *near;
   struct kdNode *kdt;
@@ -44,8 +46,8 @@ struct gridsearch {
 };
 
 struct gsknn {
-  unsigned ndist;
-  unsigned size;
+  size_t   ndist;
+  size_t   size;
   bool    *mask;
   size_t  *add;
   size_t  *tmpadd;
@@ -57,11 +59,12 @@ struct gsknn *gridsearch_knn_new(size_t size);
 void gridsearch_knn_delete(struct gsknn *knn);
 size_t gridsearch_knn(struct gridsearch *gs, struct gsknn *knn, double plon, double plat);
 
-struct gridsearch *gridsearch_create_reg2d(bool lcyclic, size_t nx, size_t ny, const double *restrict lons, const double *restrict lats);
+struct gridsearch *gridsearch_create_reg2d(bool is_cyclic, size_t dims[2], const double *restrict lons, const double *restrict lats);
 struct gridsearch *gridsearch_create(size_t n, const double *restrict lons, const double *restrict lats);
 struct gridsearch *gridsearch_create_nn(size_t n, const double *restrict lons, const double *restrict lats);
 void gridsearch_delete(struct gridsearch *gs);
 size_t gridsearch_nearest(struct gridsearch *gs, double lon, double lat, double *range);
 struct pqueue *gridsearch_qnearest(struct gridsearch *gs, double lon, double lat, double *prange, size_t nnn);
+void gridsearch_extrapolate(struct gridsearch *gs);
 
 #endif
diff --git a/src/griddes.cc b/src/griddes.cc
index 70d5b66..52702f7 100644
--- a/src/griddes.cc
+++ b/src/griddes.cc
@@ -140,13 +140,13 @@ int gridDefine(griddes_t grid)
 	    if ( grid.ysize == 0 ) Error("ysize undefined!");
 	  }
 
-	if ( grid.size == 0 ) grid.size = (long)grid.xsize*grid.ysize;
+	if ( grid.size == 0 ) grid.size = grid.xsize*grid.ysize;
 
-	if ( grid.size != (long)grid.xsize*grid.ysize )
-	  Error("Inconsistent grid declaration: xsize*ysize!=gridsize (xsize=%d ysize=%d gridsize=%d)",
+	if ( grid.size != grid.xsize*grid.ysize )
+	  Error("Inconsistent grid declaration: xsize*ysize!=gridsize (xsize=%zu ysize=%zu gridsize=%zu)",
 		grid.xsize, grid.ysize, grid.size);
 
-	if ( grid.size < 0 || grid.size > INT_MAX ) Error("grid size (%ld) out of bounds (0 - %d)!", grid.size, INT_MAX);
+	//if ( grid.size < 0 || grid.size > INT_MAX ) Error("grid size (%ld) out of bounds (0 - %d)!", grid.size, INT_MAX);
 
 	gridID = gridCreate(grid.type, grid.size);
 
@@ -166,7 +166,7 @@ int gridDefine(griddes_t grid)
 	      {
 		grid.nvertex = 2;
 		grid.xbounds = (double*) Malloc(grid.xsize*grid.nvertex*sizeof(double));
-		for ( int i = 0; i < (int) grid.xsize-1; i++ )
+		for ( size_t i = 0; i < grid.xsize-1; ++i )
 		  {
 		    grid.xbounds[2*i+1]   = 0.5*(grid.xvals[i] + grid.xvals[i+1]);
 		    grid.xbounds[2*(i+1)] = 0.5*(grid.xvals[i] + grid.xvals[i+1]);
@@ -186,7 +186,7 @@ int gridDefine(griddes_t grid)
 	      {
 		grid.nvertex = 2;
 		grid.ybounds = (double*) Malloc(grid.ysize*grid.nvertex*sizeof(double));
-		for ( int i = 0; i < (int) grid.ysize-1; i++ )
+		for ( size_t i = 0; i < grid.ysize-1; ++i )
 		  {
 		    grid.ybounds[2*i+1]   = 0.5*(grid.yvals[i] + grid.yvals[i+1]);
 		    grid.ybounds[2*(i+1)] = 0.5*(grid.yvals[i] + grid.yvals[i+1]);
diff --git a/src/griddes.h b/src/griddes.h
index 99f3da7..45b1e7c 100644
--- a/src/griddes.h
+++ b/src/griddes.h
@@ -30,9 +30,9 @@ typedef struct {
   int    *rowlon;
   bool    genBounds;
   int     nvertex;
-  long    size;
-  int     xsize;
-  int     ysize;
+  size_t  size;
+  size_t  xsize;
+  size_t  ysize;
   int     np;
   int     lcomplex;
   bool    def_xfirst;
diff --git a/src/griddes_h5.cc b/src/griddes_h5.cc
index 9839715..7e102d4 100644
--- a/src/griddes_h5.cc
+++ b/src/griddes_h5.cc
@@ -1,11 +1,11 @@
-#if defined(HAVE_CONFIG_H)
-#  include "config.h"
+#ifdef  HAVE_CONFIG_H
+#include "config.h"
 #endif
 
 #define H5_USE_16_API
 
-#if defined(HAVE_LIBHDF5)
-#  include "hdf5.h"
+#ifdef  HAVE_LIBHDF5
+#include "hdf5.h"
 #endif
 
 #include <cdi.h>
@@ -42,7 +42,7 @@ herr_t obj_info(hid_t loc_id, const char *name, void *objname)
 	/*cdoAbort(" Unable to identify an object %s", name);*/
 	break;
       }
-  }
+    }
 
   return lexist;
 }
@@ -58,10 +58,10 @@ int h5find_object(hid_t file_id, const  char *name)
 #endif
 
 static
-void fill_gridvals(int xsize, int ysize, double *xvals, double *yvals)
+void fill_gridvals(size_t xsize, size_t ysize, double *xvals, double *yvals)
 {
-  int i, j, ii, jj;
-  int index, index2;
+  size_t i, j, ii, jj;
+  size_t index, index2;
 
   double xmin = -180;
   double xmax =  180;
@@ -361,8 +361,8 @@ int gridFromH5file(const char *gridfile)
 	}
       H5Tclose(native_type);
 
-      grid.xsize = (int)dims_out[1];
-      grid.ysize = (int)dims_out[0];
+      grid.xsize = dims_out[1];
+      grid.ysize = dims_out[0];
       grid.size  = grid.xsize*grid.ysize;
 
       grid.xvals = (double*) Malloc(grid.size*sizeof(double));
@@ -377,9 +377,9 @@ int gridFromH5file(const char *gridfile)
 	{
 	  int *iarray = (int*) Malloc(grid.size*sizeof(int));
 	  status = H5Dread(lon_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	  for ( int i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
+	  for ( size_t i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
 	  status = H5Dread(lat_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	  for ( int i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
+	  for ( size_t i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
 	  Free(iarray);
 	}
 
@@ -401,7 +401,7 @@ int gridFromH5file(const char *gridfile)
       double xscale = 1, yscale = 1;
       double xoffset = 0, yoffset = 0;
       hid_t grp_id;
-      int i;
+      size_t i;
 
       grp_id = H5Gopen(file_id, "/where/lon/what");
       if ( grp_id >= 0 )
@@ -483,8 +483,8 @@ int gridFromH5file(const char *gridfile)
 	    }
 	  H5Tclose(native_type);
 
-	  grid.xsize = (int)dims_out[1];
-	  grid.ysize = (int)dims_out[0];
+	  grid.xsize = dims_out[1];
+	  grid.ysize = dims_out[0];
 	  grid.size  = grid.xsize*grid.ysize;
 
 	  grid.xvals = (double*) Malloc(grid.size*sizeof(double));
@@ -499,9 +499,9 @@ int gridFromH5file(const char *gridfile)
 	    {
 	      int *iarray = (int*) Malloc(grid.size*sizeof(int));
 	      status = H5Dread(lon_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	      for ( int i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
+	      for ( size_t i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
 	      status = H5Dread(lat_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	      for ( int i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
+	      for ( size_t i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
 	      Free(iarray);
 	    }
 
diff --git a/src/griddes_nc.cc b/src/griddes_nc.cc
index 488bec3..403c767 100644
--- a/src/griddes_nc.cc
+++ b/src/griddes_nc.cc
@@ -72,7 +72,7 @@ int gridFromNCfile(const char *gridfile)
        nc_inq_dimid(nc_file_id, "grid_rank", &nc_gridrank_id)    == NC_NOERR &&
        nc_inq_dimid(nc_file_id, "grid_corners", &nc_gridcorn_id) == NC_NOERR )
     {
-      nce(nc_inq_dimlen(nc_file_id, nc_gridsize_id, &grid_size)); grid.size = (int) grid_size;
+      nce(nc_inq_dimlen(nc_file_id, nc_gridsize_id, &grid_size)); grid.size = grid_size;
       nce(nc_inq_dimlen(nc_file_id, nc_gridrank_id, &grid_rank));
       nce(nc_inq_dimlen(nc_file_id, nc_gridcorn_id, &grid_nvertex)); grid.nvertex = (int) grid_nvertex;
   
@@ -125,7 +125,7 @@ int gridFromNCfile(const char *gridfile)
 
       if ( nc_inq_varid(nc_file_id, "grid_imask", &nc_gridmask_id) == NC_NOERR )
 	{
-	  int i;
+	  size_t i;
 	  grid.mask = (int*) Malloc(grid.size*sizeof(int));
 	  nce(nc_get_var_int(nc_file_id, nc_gridmask_id, grid.mask));
 	  for ( i = 0; i < grid.size; ++i )
@@ -173,7 +173,7 @@ void writeNCgrid(const char *gridfile, int gridID, int *grid_imask)
 
 
   int gridtype = gridInqType(gridID);
-  int gridsize = gridInqSize(gridID);
+  size_t gridsize = gridInqSize(gridID);
 
   nc_type xtype = (gridInqDatatype(gridID) == CDI_DATATYPE_FLT64) ? NC_DOUBLE : NC_FLOAT;
 
diff --git a/src/gridreference.cc b/src/gridreference.cc
index a210611..344a941 100644
--- a/src/gridreference.cc
+++ b/src/gridreference.cc
@@ -217,7 +217,7 @@ int referenceToGrid(int gridID1)
 	{
 	  if ( cdoVerbose ) cdoPrint("Horizontal grid file used: %s", gridpath);
       
-	  int gridsize = gridInqSize(gridID1);
+	  size_t gridsize = gridInqSize(gridID1);
 
 	  // int number = gridInqNumber(gridID1);
 	  int position = gridInqPosition(gridID1);
@@ -233,7 +233,7 @@ int referenceToGrid(int gridID1)
 	      if ( gridInqSize(gridID) == gridsize )
 		gridID2 = gridDuplicate(gridID);
 	      else
-		cdoWarning("Grid size %d on position %d do not match! Reference=%s", gridsize, position, gridpath);
+		cdoWarning("Grid size %zu on position %d do not match! Reference=%s", gridsize, position, gridpath);
 	    }
 	  else if ( position == 0 )
 	    {
diff --git a/src/interpol.cc b/src/interpol.cc
index b300e39..e58b9d5 100644
--- a/src/interpol.cc
+++ b/src/interpol.cc
@@ -202,18 +202,18 @@ double intlinarr2p(long nxm, long nym, double **fieldm, const double *xm, const
 
 static
 void intlinarr2(double missval, int lon_is_circular,
-		long nxm, long nym,  const double *restrict fieldm, const double *restrict xm, const double *restrict ym,
-		long gridsize2, double *field, const double *restrict x, const double *restrict y)
+		size_t nxm, size_t nym,  const double *restrict fieldm, const double *restrict xm, const double *restrict ym,
+		size_t gridsize2, double *field, const double *restrict x, const double *restrict y)
 {
-  long nlon1 = nxm;
+  size_t nlon1 = nxm;
   double findex = 0;
 
   if ( lon_is_circular ) nlon1--;
-  long gridsize1 = nlon1*nym;
+  size_t gridsize1 = nlon1*nym;
 
   bool *grid1_mask = (bool*) Malloc(gridsize1*sizeof(bool));
-  for ( long jj = 0; jj < nym; ++jj )
-    for ( long ii = 0; ii < nlon1; ++ii )
+  for ( size_t jj = 0; jj < nym; ++jj )
+    for ( size_t ii = 0; ii < nlon1; ++ii )
       grid1_mask[jj*nlon1+ii] = !DBL_IS_EQUAL(fieldm[jj*nlon1+ii], missval);
 
   progressInit();
@@ -222,9 +222,9 @@ void intlinarr2(double missval, int lon_is_circular,
 #pragma omp parallel for default(none) \
   shared(ompNumThreads, field, fieldm, x, y, xm, ym, nxm, nym, gridsize2, missval, findex, nlon1, lon_is_circular, grid1_mask)
 #endif
-  for ( int i = 0; i < gridsize2; ++i )
+  for ( size_t i = 0; i < gridsize2; ++i )
     {
-      int src_add[4];                /*  address for the four source points    */
+      size_t src_add[4];                /*  address for the four source points    */
       int lprogress = 1;
       if ( cdo_omp_get_thread_num() != 0 ) lprogress = 0;
 
@@ -241,7 +241,7 @@ void intlinarr2(double missval, int lon_is_circular,
 
       if ( lfound )
 	{
-	  long iix = ii;
+	  size_t iix = ii;
 	  if ( lon_is_circular && iix == (nxm-1) ) iix = 0;
 	  src_add[0] = (jj-1)*nlon1+(ii-1);
 	  src_add[1] = (jj-1)*nlon1+(iix);
@@ -325,8 +325,8 @@ void intgridbil(field_type *field1, field_type *field2)
   double *array2 = field2->ptr;
   double missval = field1->missval;
 
-  int nlon1 = gridInqXsize(gridID1);
-  int nlat1 = gridInqYsize(gridID1);
+  size_t nlon1 = gridInqXsize(gridID1);
+  size_t nlat1 = gridInqYsize(gridID1);
 
   int lon_is_circular = 0;
   
@@ -334,7 +334,7 @@ void intgridbil(field_type *field1, field_type *field2)
   if ( grid_is_distance_generic(gridID1) && grid_is_distance_generic(gridID2) ) lgeorefgrid = false;
 
   double **array1_2D = (double **) Malloc(nlat1*sizeof(double *));
-  for ( int ilat = 0; ilat < nlat1; ilat++ )
+  for ( size_t ilat = 0; ilat < nlat1; ilat++ )
     array1_2D[ilat] = array1 + ilat*nlon1;
 
   if ( lgeorefgrid )
@@ -364,8 +364,8 @@ void intgridbil(field_type *field1, field_type *field2)
       if ( lon_is_circular ) lon1[nlon1-1] = lon1[0] + 2*M_PI;
     }
   
-  int xsize2 = gridInqXsize(gridID2);
-  int ysize2 = gridInqYsize(gridID2);
+  size_t xsize2 = gridInqXsize(gridID2);
+  size_t ysize2 = gridInqYsize(gridID2);
 
   if ( xsize2 == 1 && ysize2 == 1 )
     {
@@ -387,7 +387,7 @@ void intgridbil(field_type *field1, field_type *field2)
 	  lon1 = (double*) Realloc(lon1, (nlon1+1)*sizeof(double));
 	  double *array = (double*) Malloc(nlat1*(nlon1+1)*sizeof(double));
 
-	  for ( int ilat = 0; ilat < nlat1; ilat++ )
+	  for ( size_t ilat = 0; ilat < nlat1; ilat++ )
 	    {
 	      array1_2D[ilat] = array + ilat*(nlon1+1);  
 	      memcpy(array1_2D[ilat], field[ilat], nlon1*sizeof(double));
@@ -424,7 +424,7 @@ void intgridbil(field_type *field1, field_type *field2)
             cdoAbort("Target grid has no coordinate values!");
         }
       
-      int gridsize2 = gridInqSize(gridID2);
+      size_t gridsize2 = gridInqSize(gridID2);
 
       double *xvals2 = (double*) Malloc(gridsize2*sizeof(double));
       double *yvals2 = (double*) Malloc(gridsize2*sizeof(double));
@@ -439,7 +439,7 @@ void intgridbil(field_type *field1, field_type *field2)
           grid_to_radian(xunits, gridsize2, xvals2, "grid2 center lon"); 
           grid_to_radian(xunits, gridsize2, yvals2, "grid2 center lat"); 
 
-          for ( int i = 0; i < gridsize2; ++i )
+          for ( size_t i = 0; i < gridsize2; ++i )
             {
               if ( xvals2[i] < lon1[0]       ) xvals2[i] += 2*M_PI;
               if ( xvals2[i] > lon1[nlon1-1] ) xvals2[i] -= 2*M_PI;
@@ -453,8 +453,8 @@ void intgridbil(field_type *field1, field_type *field2)
           gridInqXvals(gridID2, xcoord);
           gridInqYvals(gridID2, ycoord);
   
-          for ( int j = 0; j < ysize2; ++j )
-            for ( int i = 0; i < xsize2; ++i )
+          for ( size_t j = 0; j < ysize2; ++j )
+            for ( size_t i = 0; i < xsize2; ++i )
               {
                 xvals2[j*xsize2+i] = xcoord[i]; 
                 yvals2[j*xsize2+i] = ycoord[j]; 
@@ -468,8 +468,8 @@ void intgridbil(field_type *field1, field_type *field2)
 		 nlon1, nlat1, array1, lon1, lat1,
 		 gridsize2, array2, xvals2, yvals2);
 
-      int nmiss = 0;
-      for ( int i = 0; i < gridsize2; ++i )
+      size_t nmiss = 0;
+      for ( size_t i = 0; i < gridsize2; ++i )
 	if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
       field2->nmiss = nmiss;
@@ -496,7 +496,7 @@ void interpolate(field_type *field1, field_type *field2)
   int gridIDo;
   double *arrayOut;
   double missval;
-  int nmiss;
+  size_t nmiss;
   long ilon, ilat, nxlon, nxlat, olon, olat;
   long l11, l12, l21, l22, l1, l2;
   double volon1, volon2, volat1, volat2;
diff --git a/src/kdtreelib/kdtree.h b/src/kdtreelib/kdtree.h
index 74638a0..47d3af4 100644
--- a/src/kdtreelib/kdtree.h
+++ b/src/kdtreelib/kdtree.h
@@ -10,10 +10,11 @@
                              changed *min to min[KD_MAX_DIM]
                              changed *max to max[KD_MAX_DIM]
                              _compPoints: compare index if points[axis] are equal
-                             replace qsortR by libc:qsort (speedup 25%)
+                   20171102: renamed kd_buildArg() to kd_initArg(), changed interface and memory handling
+                             changed data pointer to size_t
 */
-#ifndef _KDTREE_H_
-#define _KDTREE_H_
+#ifndef  KDTREE_H_
+#define  KDTREE_H_
 
 #include <math.h>
 #include <pthread.h>
@@ -59,7 +60,7 @@ typedef long kdata_t;
 
 typedef struct kd_point {
     kdata_t point[KD_MAX_DIM];
-    unsigned index;
+    size_t index;
 } kd_point;
 
 
@@ -84,7 +85,7 @@ typedef struct kdNode {
     kdata_t min[KD_MAX_DIM];      /*!<vector to the min coordinates of the hyperrectangle */
     kdata_t max[KD_MAX_DIM];      /*!<vector to the max coordinates of the hyperrectangle */
     int split;                    /*!<axis along which the tree bifurcates */
-    unsigned index;               /*!<optional index value */
+    size_t index;                 /*!<optional index value */
 } kdNode;
 
 /*!
@@ -102,9 +103,9 @@ typedef struct resItem {
  */
 typedef struct pqueue {
     struct resItem **d;         /*!<pointer to an array of result items */
-    uint32_t size;              /*!<current length of the queue */
-    uint32_t avail;             /*!<currently allocated queue elements */
-    uint32_t step;              /*!<step size in which new elements are allocated */
+    size_t size;              /*!<current length of the queue */
+    size_t avail;             /*!<currently allocated queue elements */
+    size_t step;              /*!<step size in which new elements are allocated */
 } pqueue;
 
 /*!
@@ -115,7 +116,7 @@ typedef struct kd_thread_data {
     struct kd_point *points;
     kdata_t min[KD_MAX_DIM];
     kdata_t max[KD_MAX_DIM];
-    unsigned long nPoints;
+    size_t nPoints;
     int max_threads;
     int depth;
     int dim;
@@ -126,7 +127,7 @@ typedef struct kd_thread_data {
 #define KD_UNORDERED (0)
 
 /* functions for the priority queue */
-struct pqueue *pqinit(struct pqueue *q, uint32_t n);
+struct pqueue *pqinit(struct pqueue *q, size_t n);
 int pqinsert(struct pqueue *q, struct resItem *d);
 struct resItem **pqremove_min(struct pqueue *q, struct resItem **d);
 struct resItem **pqremove_max(struct pqueue *q, struct resItem **d);
@@ -152,22 +153,16 @@ void kd_printNode(struct kdNode *node);
 void kd_printTree(struct kdNode *node);
 
 /* Functions for building and destroying trees */
-void kd_freeNode(kdNode * node);
-struct kdNode *kd_allocNode(struct kd_point *points, unsigned long pivot,
+struct kdNode *kd_allocNode(struct kd_point *points, size_t pivot,
                             kdata_t *min, kdata_t *max, int dim, int axis);
 void kd_destroyTree(struct kdNode *node);
-struct kd_thread_data *kd_buildArg(struct kd_point *points,
-                                   unsigned long nPoints,
-                                   kdata_t *min, kdata_t *max,
-                                   int depth, int max_threads,
-                                   int dim);
-struct kdNode *kd_buildTree(struct kd_point *points, unsigned long nPoints,
+void kd_initArg(struct kd_thread_data *d, struct kd_point *points, size_t nPoints,
+                kdata_t *min, kdata_t *max, int depth, int max_threads, int dim);
+struct kdNode *kd_buildTree(struct kd_point *points, size_t nPoints,
                             kdata_t *min, kdata_t *max, int dim, int max_threads);
 void *kd_doBuildTree(void *threadarg);
-struct kdNode *kd_sph_buildTree(struct kd_point *points,
-                                unsigned long nPoints,
-                                kdata_t *min, kdata_t *max,
-                                int max_threads);
+struct kdNode *kd_sph_buildTree(struct kd_point *points, size_t nPoints,
+                                kdata_t *min, kdata_t *max, int max_threads);
 void *kd_sph_doBuildTree(void *threadarg);
 
 /* Functions for range searches 
@@ -180,12 +175,11 @@ struct pqueue *kd_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max
                                  int dim);
 int kd_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max, int dim,
                         struct pqueue *res);
-struct kdNode *kd_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
-                          int dim);
+struct kdNode *kd_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq, int dim);
 struct pqueue *kd_qnearest(struct kdNode *node, kdata_t *p,
-                           kdata_t *max_dist_sq, unsigned int q, int dim);
+                           kdata_t *max_dist_sq, size_t q, int dim);
 int kd_doQnearest(struct kdNode *node, kdata_t *p,
-                  kdata_t *max_dist_sq, unsigned int q, int dim,
+                  kdata_t *max_dist_sq, size_t q, int dim,
                   struct pqueue *res);
 struct pqueue *kd_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                         int dim, int ordered);
@@ -202,9 +196,9 @@ int kd_sph_doOrtRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max,
 struct kdNode *kd_sph_nearest(struct kdNode *node, kdata_t *p,
                               kdata_t *max_dist_sq);
 struct pqueue *kd_sph_qnearest(struct kdNode *node, kdata_t *p,
-                               kdata_t *max_dist_sq, unsigned int q);
+                               kdata_t *max_dist_sq, size_t q);
 int kd_sph_doQnearest(struct kdNode *node, kdata_t *p,
-                      kdata_t *max_dist_sq, unsigned int q, struct pqueue *res);
+                      kdata_t *max_dist_sq, size_t q, struct pqueue *res);
 struct pqueue *kd_sph_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
                             int ordered);
 int kd_sph_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
@@ -214,4 +208,4 @@ int kd_sph_doRange(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
 int kd_insertResTree(struct kdNode *node, struct pqueue *res);
 
 
-#endif                          /* _KDTREE_H_ */
+#endif                          /* KDTREE_H_ */
diff --git a/src/kdtreelib/kdtree_cartesian.cc b/src/kdtreelib/kdtree_cartesian.cc
index faef76a..b1e7e83 100644
--- a/src/kdtreelib/kdtree_cartesian.cc
+++ b/src/kdtreelib/kdtree_cartesian.cc
@@ -24,10 +24,10 @@ kdata_t square(const kdata_t x)
 static constexpr
 kdata_t kd_dist_sq(const kdata_t *restrict a, const kdata_t *restrict b)
 {
-  return (square((a[0]-b[0]))+square((a[1]-b[1]))+square((a[2]-b[2])));
+  return square((a[0]-b[0]))+square((a[1]-b[1]))+square((a[2]-b[2]));
 }
 
-inline
+
 kdata_t kd_min(kdata_t x, kdata_t y)
 {
     return x < y ? x : y;
@@ -70,16 +70,13 @@ kdata_t kd_min(kdata_t x, kdata_t y)
  * \return root node of the tree
  */
 struct kdNode *
-kd_buildTree(struct kd_point *points, unsigned long nPoints,
+kd_buildTree(struct kd_point *points, size_t nPoints,
              kdata_t *min, kdata_t *max, int dim, int max_threads)
 {
-    struct kd_thread_data *my_data;
-    struct kdNode *tree;
-
-    my_data = kd_buildArg(points, nPoints, min, max, 0, max_threads, dim);
-    tree = (kdNode *)kd_doBuildTree(my_data);
-    free(my_data);
-    return tree;
+  struct kd_thread_data my_data;
+  kd_initArg(&my_data, points, nPoints, min, max, 0, max_threads, dim);
+  struct kdNode *tree = (kdNode *)kd_doBuildTree(&my_data);
+  return tree;
 }
 
 
@@ -163,12 +160,11 @@ struct pqueue *
 kd_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max, int dim)
 {
     struct pqueue *res;
-    uint32_t i;
 
     if ((res = pqinit(NULL, 1)) == NULL)
         return NULL;
     if (!kd_doOrtRangeSearch(node, min, max, dim, res)) {
-        for(i = 0; i < res->size; i++) {
+        for(size_t i = 0; i < res->size; i++) {
             free(res->d[i]);
         }
         free(res->d);
@@ -304,13 +300,13 @@ kd_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq, int dim)
  */
 struct pqueue *
 kd_qnearest(struct kdNode *node, kdata_t *p,
-            kdata_t *max_dist_sq, unsigned int q, int dim)
+            kdata_t *max_dist_sq, size_t q, int dim)
 {
     struct pqueue *res = pqinit(NULL, q + 2);
     if ( res == NULL) return NULL;
     
     if ( !kd_doQnearest(node, p, max_dist_sq, q + 1, dim, res) ) {
-        for ( uint32_t i = 0; i < res->size; ++i ) free(res->d[i]);
+        for ( size_t i = 0; i < res->size; ++i ) free(res->d[i]);
         free(res->d);
         free(res);
         return NULL;
@@ -329,73 +325,75 @@ kd_qnearest(struct kdNode *node, kdata_t *p,
  * return 1 if okay, zero in case of problems
  */
 // Uwe Schulzweida: extract kd_check_dist() from kd_doQnearest()
-static int
+static bool
 kd_check_dist(struct kdNode *node, kdata_t *p,
-              kdata_t *max_dist_sq, unsigned int q, struct pqueue *res)
+              kdata_t *max_dist_sq, size_t q, struct pqueue *res)
 {
-    kdata_t dist_sq = kd_dist_sq(node->location, p);
-    if ( dist_sq < *max_dist_sq && kd_isleaf(node) ) {
-        struct resItem *point = (struct resItem *) kd_malloc(sizeof(struct resItem), "kd_doQnearest: ");
-        if ( point == NULL) return 0;
-        point->node = node;
-        point->dist_sq = dist_sq;
-        pqinsert(res, point);
+  kdata_t dist_sq = kd_dist_sq(node->location, p);
+  if ( dist_sq < *max_dist_sq && kd_isleaf(node) )
+    {
+      struct resItem *point = (struct resItem *) kd_malloc(sizeof(struct resItem), "kd_doQnearest: ");
+      if ( point == NULL) return false;
+      point->node = node;
+      point->dist_sq = dist_sq;
+      pqinsert(res, point);
     }
 
-    if ( res->size > q ) {
-        struct resItem *item;
-        pqremove_max(res, &item);
-        free(item);
-        if ( res->size > 1 ) {
-            /*
-             * Only inspect the queue if there are items left 
-             */
-            pqpeek_max(res, &item);
-            *max_dist_sq = item->dist_sq;
-        } else {
-            /*
-             * Nothing was found within the max search radius 
-             */
-            *max_dist_sq = 0;
+  if ( res->size > q )
+    {
+      struct resItem *item;
+      pqremove_max(res, &item);
+      free(item);
+      if ( res->size > 1 )
+        {
+          // Only inspect the queue if there are items left 
+          pqpeek_max(res, &item);
+          *max_dist_sq = item->dist_sq;
+        }
+      else
+        {
+          // Nothing was found within the max search radius 
+          *max_dist_sq = 0;
         }
     }
 
-    return 1;
+  return true;
 }
 
 int
 kd_doQnearest(struct kdNode *node, kdata_t *p,
-              kdata_t *max_dist_sq, unsigned int q, int dim, struct pqueue *res)
+              kdata_t *max_dist_sq, size_t q, int dim, struct pqueue *res)
 {
-    if ( !node ) return 1;
+  if ( !node ) return 1;
 
-    if ( !kd_check_dist(node, p, max_dist_sq, q, res) ) return 0;
+  if ( !kd_check_dist(node, p, max_dist_sq, q, res) ) return 0;
 
-    struct kdNode *nearer, *further;
-    if ( p[node->split] < node->location[node->split] ) {
-        nearer  = node->left;
-        further = node->right;
-    } else {
-        nearer  = node->right;
-        further = node->left;
-    }
-    if ( !kd_doQnearest(nearer, p, max_dist_sq, q, dim, res) ) return 0;
+  struct kdNode *nearer, *further;
+  if ( p[node->split] < node->location[node->split] ) {
+    nearer  = node->left;
+    further = node->right;
+  } else {
+    nearer  = node->right;
+    further = node->left;
+  }
+  if ( !kd_doQnearest(nearer, p, max_dist_sq, q, dim, res) ) return 0;
 
-    if ( !further ) return 1;
+  if ( !further ) return 1;
 
-    kdata_t dx = kd_min(KDATA_ABS(p[node->split] - further->min[node->split]),
-                        KDATA_ABS(p[node->split] - further->max[node->split]));
+  kdata_t dx = kd_min(KDATA_ABS(p[node->split] - further->min[node->split]),
+                      KDATA_ABS(p[node->split] - further->max[node->split]));
     
-    if ( *max_dist_sq > kd_sqr(dx) ) {
-        /*
-         * some part of the further hyper-rectangle is in the search
-         * radius, search the further node 
-         */
-        if (!kd_doQnearest(further, p, max_dist_sq, q, dim, res)) return 0;
+  if ( *max_dist_sq > kd_sqr(dx) ) {
+    /*
+     * some part of the further hyper-rectangle is in the search
+     * radius, search the further node 
+     */
+    if (!kd_doQnearest(further, p, max_dist_sq, q, dim, res)) return 0;
 
-        if (!kd_check_dist(node, p, max_dist_sq, q, res)) return 0;
-    }
-    return 1;
+    if (!kd_check_dist(node, p, max_dist_sq, q, res)) return 0;
+  }
+
+  return 1;
 }
 
 
@@ -423,7 +421,7 @@ kd_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
     if ( res == NULL ) return NULL;
     
     if ( !kd_doRange(node, p, max_dist_sq, dim, res, ordered) ) {
-        for( uint32_t i = 0; i < res->size; ++i ) {
+        for( size_t i = 0; i < res->size; ++i ) {
             free(res->d[i]);
         }
         free(res->d);
diff --git a/src/kdtreelib/kdtree_common.cc b/src/kdtreelib/kdtree_common.cc
index 559e758..6ef19fd 100644
--- a/src/kdtreelib/kdtree_common.cc
+++ b/src/kdtreelib/kdtree_common.cc
@@ -59,7 +59,7 @@ kd_printNode(struct kdNode *node)
   printf("Corners: (%f, %f)\t(%f, %f)\n", node->min[0], node->min[1],
          node->max[0], node->max[1]);
   printf("Children: %p\t%p\n", (void *) node->left, (void *) node->right);
-  printf("Index: %u\n", node->index);
+  printf("Index: %zu\n", node->index);
 
   printf("\n");
 }
@@ -79,6 +79,18 @@ kd_printTree(struct kdNode *node)
 
 /* End helper functions */
 
+void kd_initArg(struct kd_thread_data *d, struct kd_point *points, size_t nPoints,
+                kdata_t *min, kdata_t *max, int depth, int max_threads, int dim)
+{
+  d->points = points;
+  d->nPoints = nPoints;
+  memcpy(d->min, min, dim*sizeof(kdata_t));
+  memcpy(d->max, max, dim*sizeof(kdata_t));
+  d->depth = depth;
+  d->max_threads = max_threads;
+  d->dim = dim;
+}
+
 /* ******************************************************************
    
    Functions for building and destroying trees 
@@ -87,15 +99,15 @@ kd_printTree(struct kdNode *node)
 
 void *kd_doBuildTree(void *threadarg)
 {
-  kdata_t tmpMinLeft[KD_MAX_DIM], tmpMaxLeft[KD_MAX_DIM], tmpMinRight[KD_MAX_DIM], tmpMaxRight[KD_MAX_DIM];
+  kdata_t tmpMaxLeft[KD_MAX_DIM], tmpMinRight[KD_MAX_DIM];
   struct kdNode *node;
   pthread_t threads[2];
   pthread_attr_t attr;
-  struct kd_thread_data *argleft, *argright;
+  struct kd_thread_data argleft, argright;
   struct kd_thread_data *my_data = (struct kd_thread_data *) threadarg;
 
   struct kd_point *points = my_data->points;
-  unsigned long nPoints = my_data->nPoints;
+  size_t nPoints = my_data->nPoints;
   kdata_t *min = my_data->min;
   kdata_t *max = my_data->max;
   int depth = my_data->depth;
@@ -120,25 +132,19 @@ void *kd_doBuildTree(void *threadarg)
    */
   pmergesort(points, nPoints, sortaxis, max_threads);
 
-  unsigned long pivot = nPoints / 2;
+  size_t pivot = nPoints / 2;
   if ((node = kd_allocNode(points, pivot, min, max, sortaxis, dim)) == NULL)
     return NULL;
 
-  memcpy(tmpMinLeft, min, dim * sizeof(kdata_t));
   memcpy(tmpMaxLeft, max, dim * sizeof(kdata_t));
   tmpMaxLeft[sortaxis] = node->location[sortaxis];
-  argleft = kd_buildArg(points, pivot, tmpMinLeft, tmpMaxLeft,
-                        depth + 1, max_threads / 2, dim);
-  if (!argleft) {
-    kd_destroyTree(node);
-    return NULL;
-  }
+  kd_initArg(&argleft, points, pivot, min, tmpMaxLeft,
+             depth + 1, max_threads / 2, dim);
 
   if (max_threads > 1) {
-    pthread_create(&threads[0], &attr, kd_doBuildTree, (void *) argleft);
+    pthread_create(&threads[0], &attr, kd_doBuildTree, (void *) &argleft);
   } else {
-    node->left = (kdNode *)kd_doBuildTree((void *) argleft);
-    free(argleft);
+    node->left = (kdNode *)kd_doBuildTree((void *) &argleft);
     if (!node->left) {
       kd_destroyTree(node);
       return NULL;
@@ -146,21 +152,14 @@ void *kd_doBuildTree(void *threadarg)
   }
 
   memcpy(tmpMinRight, min, dim * sizeof(kdata_t));
-  memcpy(tmpMaxRight, max, dim * sizeof(kdata_t));
   tmpMinRight[sortaxis] = node->location[sortaxis];
-  argright = kd_buildArg(&points[pivot], nPoints - pivot,
-                         tmpMinRight, tmpMaxRight, depth + 1,
-                         max_threads / 2, dim);
-  if (!argright) {
-    kd_destroyTree(node);
-    return NULL;
-  }
+  kd_initArg(&argright, &points[pivot], nPoints - pivot, tmpMinRight, max,
+             depth + 1, max_threads / 2, dim);
 
   if (max_threads > 1) {
-    pthread_create(&threads[1], &attr, kd_doBuildTree, (void *) argright);
+    pthread_create(&threads[1], &attr, kd_doBuildTree, (void *) &argright);
   } else {
-    node->right = (kdNode *)kd_doBuildTree((void *) argright);
-    free(argright);
+    node->right = (kdNode *)kd_doBuildTree((void *) &argright);
     if (!node->right) {
       kd_destroyTree(node);
       return NULL;
@@ -169,9 +168,7 @@ void *kd_doBuildTree(void *threadarg)
 
   if (max_threads > 1) {
     pthread_join(threads[0], (void **) (&node->left));
-    free(argleft);
     pthread_join(threads[1], (void **) (&node->right));
-    free(argright);
     if (!node->left || !node->right) {
       kd_destroyTree(node);
       return NULL;
@@ -181,40 +178,15 @@ void *kd_doBuildTree(void *threadarg)
   return (void *) node;
 }
 
-
-void
-kd_freeNode(kdNode *node)
+static
+void kd_freeNode(kdNode *node)
 {
   if ( node ) free(node);
-  return;
-}
-
-
-struct kd_thread_data *
-kd_buildArg(struct kd_point *points,
-            unsigned long nPoints,
-            kdata_t *min, kdata_t *max,
-            int depth, int max_threads, int dim)
-{
-  struct kd_thread_data *d;
-
-  if ((d = (kd_thread_data *)kd_malloc(sizeof(kd_thread_data), "kd_thread_data")) == NULL)
-    return NULL;
-
-  d->points = points;
-  d->nPoints = nPoints;
-  memcpy(d->min, min, dim*sizeof(kdata_t));
-  memcpy(d->max, max, dim*sizeof(kdata_t));
-  d->depth = depth;
-  d->max_threads = max_threads;
-  d->dim = dim;
-
-  return d;
 }
 
 
 struct kdNode *
-kd_allocNode(struct kd_point *points, unsigned long pivot,
+kd_allocNode(struct kd_point *points, size_t pivot,
              kdata_t *min, kdata_t *max, int axis, int dim)
 {
   struct kdNode *node;
diff --git a/src/kdtreelib/kdtree_spherical.cc b/src/kdtreelib/kdtree_spherical.cc
index ff41230..5aa0d1e 100644
--- a/src/kdtreelib/kdtree_spherical.cc
+++ b/src/kdtreelib/kdtree_spherical.cc
@@ -128,16 +128,13 @@ kd_sph_orth_dist(kdata_t *p1, kdata_t *p2, int split)
  * \return root node of the tree
  */
 struct kdNode *
-kd_sph_buildTree(struct kd_point *points, unsigned long nPoints,
+kd_sph_buildTree(struct kd_point *points, size_t nPoints,
                  kdata_t *min, kdata_t *max, int max_threads)
 {
-    struct kd_thread_data *my_data;
-    struct kdNode *tree;
-
-    my_data = kd_buildArg(points, nPoints, min, max, 0,max_threads, 2);
-    tree = (kdNode *)kd_doBuildTree(my_data);
-    free(my_data);
-    return tree;
+  struct kd_thread_data my_data;
+  kd_initArg(&my_data, points, nPoints, min, max, 0,max_threads, 2);
+  struct kdNode *tree = (kdNode *)kd_doBuildTree(&my_data);
+  return tree;
 }
 
 
@@ -277,12 +274,11 @@ struct pqueue *
 kd_sph_ortRangeSearch(struct kdNode *node, kdata_t *min, kdata_t *max)
 {
     struct pqueue *res;
-    uint32_t i;
 
     if ((res = pqinit(NULL, 1)) == NULL)
         return NULL;
     if (!kd_sph_doOrtRangeSearch(node, min, max, res)) {
-        for(i = 0; i < res->size; i++) {
+        for(size_t i = 0; i < res->size; i++) {
             free(res->d[i]);
         }
         free(res->d);
@@ -432,15 +428,14 @@ kd_sph_nearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq)
  */
 struct pqueue *
 kd_sph_qnearest(struct kdNode *node, kdata_t *p,
-                kdata_t *max_dist_sq, unsigned int q)
+                kdata_t *max_dist_sq, size_t q)
 {
     struct pqueue *res;
-    uint32_t i;
 
     if ((res = pqinit(NULL, q + 2)) == NULL)
         return NULL;
     if (!kd_sph_doQnearest(node, p, max_dist_sq, q + 1, res)) {
-        for(i = 0; i < res->size; i++) {
+        for(size_t i = 0; i < res->size; i++) {
             free(res->d[i]);
         }
         free(res->d);
@@ -461,7 +456,7 @@ kd_sph_qnearest(struct kdNode *node, kdata_t *p,
  */
 int
 kd_sph_doQnearest(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq,
-                  unsigned int q, struct pqueue *res)
+                  size_t q, struct pqueue *res)
 {
     struct kdNode *nearer, *further;
     struct resItem *point, *item;
@@ -588,12 +583,11 @@ struct pqueue *
 kd_sph_range(struct kdNode *node, kdata_t *p, kdata_t *max_dist_sq, int ordered)
 {
     struct pqueue *res;
-    uint32_t i;
 
     if ((res = pqinit(NULL, 1)) == NULL)
         return NULL;
     if (!kd_sph_doRange(node, p, max_dist_sq, res, ordered)) {
-        for(i = 0; i < res->size; i++) {
+        for(size_t i = 0; i < res->size; i++) {
             free(res->d[i]);
         }
         free(res->d);
diff --git a/src/kdtreelib/pmergesort.cc b/src/kdtreelib/pmergesort.cc
index 57e6968..895a012 100644
--- a/src/kdtreelib/pmergesort.cc
+++ b/src/kdtreelib/pmergesort.cc
@@ -25,13 +25,15 @@ void *mergesort_t(void *args);
 
 int pmergesort(struct kd_point *base, size_t nmemb, int axis, int max_threads)
 {
-    struct kd_point *tmp;
-    param_t args;
+    struct kd_point *tmp = NULL;
 
-    if ((tmp = (struct kd_point*)calloc(nmemb, sizeof(struct kd_point))) == NULL) {
+    if ( max_threads > 1 )
+      if ((tmp = (struct kd_point*)calloc(nmemb, sizeof(struct kd_point))) == NULL) {
         perror("malloc");
         return 0;
-    }
+      }
+
+    param_t args;
     args.a = base;
     args.b = tmp;
     args.first = 0;
@@ -41,7 +43,8 @@ int pmergesort(struct kd_point *base, size_t nmemb, int axis, int max_threads)
 
     mergesort_t(&args);
 
-    free(tmp);
+    if (tmp) free(tmp);
+
     return 1;
 }
 
diff --git a/src/kdtreelib/pqueue.cc b/src/kdtreelib/pqueue.cc
index 9fdfc2c..7881985 100644
--- a/src/kdtreelib/pqueue.cc
+++ b/src/kdtreelib/pqueue.cc
@@ -22,9 +22,9 @@
    Ripped off wikipedia.
 */
 inline int
-floorLog2(uint32_t n)
+floorLog2(size_t n)
 {
-    uint32_t pos = 0;
+    size_t pos = 0;
     if (n >= 1 << 16) {
         n >>= 16;
         pos += 16;
@@ -54,7 +54,7 @@ floorLog2(uint32_t n)
    (min-sorted level). 
 */
 inline int
-is_max_level(int i)
+is_max_level(size_t i)
 {
     return floorLog2(i) % 2;
 }
@@ -63,7 +63,7 @@ is_max_level(int i)
 
 /* Swap nodes i and j in the priority queue q */
 void
-pq_swap_nodes(struct pqueue *q, uint32_t i, uint32_t j)
+pq_swap_nodes(struct pqueue *q, size_t i, size_t j)
 {
     struct resItem *tmp;
 
@@ -74,11 +74,11 @@ pq_swap_nodes(struct pqueue *q, uint32_t i, uint32_t j)
 
 
 /* Return the array index of the maximum node */
-uint32_t
+size_t
 get_max_index(struct pqueue *q)
 {
 
-    uint32_t i;
+    size_t i;
     if (!q)
         return 0;
 
@@ -128,7 +128,7 @@ get_max_index(struct pqueue *q)
 
 /* Move a node up the tree */
 void
-bubble_up_min(struct pqueue *q, uint32_t i)
+bubble_up_min(struct pqueue *q, size_t i)
 {
     /*
      * if node has a grandparent 
@@ -141,7 +141,7 @@ bubble_up_min(struct pqueue *q, uint32_t i)
 
 
 void
-bubble_up_max(struct pqueue *q, uint32_t i)
+bubble_up_max(struct pqueue *q, size_t i)
 {
     /*
      * if node has a grandparent 
@@ -154,7 +154,7 @@ bubble_up_max(struct pqueue *q, uint32_t i)
 
 
 void
-bubble_up(struct pqueue *q, uint32_t i)
+bubble_up(struct pqueue *q, size_t i)
 {
     if (!is_max_level(i)) {
         if (i > 1 && PQPRIO(q->d[i]) > PQPRIO(q->d[i / 2])) {
@@ -182,10 +182,10 @@ bubble_up(struct pqueue *q, uint32_t i)
 
 /* Get index of the smallest child or grandchild of q->d[i].
    Caller must ensure that q->d[i] has at least one child. */
-uint32_t
-pq_get_min_child_index(struct pqueue *q, uint32_t i)
+size_t
+pq_get_min_child_index(struct pqueue *q, size_t i)
 {
-    uint32_t m;
+    size_t m;
 
     /*
      * First Child 
@@ -226,10 +226,10 @@ pq_get_min_child_index(struct pqueue *q, uint32_t i)
 
 /* Get index of the largest children and grandchildren of q->d[i].
    Caller must ensure that q->d[i] has at least one child. */
-uint32_t
-pq_get_max_child_index(struct pqueue * q, uint32_t i)
+size_t
+pq_get_max_child_index(struct pqueue * q, size_t i)
 {
-    uint32_t m;
+    size_t m;
 
     /*
      * First Child 
@@ -271,7 +271,7 @@ pq_get_max_child_index(struct pqueue * q, uint32_t i)
 
 /* Move a node down the tree */
 void
-trickle_down(struct pqueue *q, uint32_t i)
+trickle_down(struct pqueue *q, size_t i)
 {
     if (is_max_level(i))
         trickle_down_max(q, i);
@@ -281,9 +281,9 @@ trickle_down(struct pqueue *q, uint32_t i)
 
 
 void
-trickle_down_max(struct pqueue *q, uint32_t i)
+trickle_down_max(struct pqueue *q, size_t i)
 {
-    uint32_t m;
+    size_t m;
 
     /*
      * if A[i] has children 
@@ -313,9 +313,9 @@ trickle_down_max(struct pqueue *q, uint32_t i)
 }
 
 void
-trickle_down_min(struct pqueue *q, uint32_t i)
+trickle_down_min(struct pqueue *q, size_t i)
 {
-    uint32_t m;
+    size_t m;
 
     /*
      * if A[i] has children 
@@ -369,7 +369,7 @@ trickle_down_min(struct pqueue *q, uint32_t i)
  *
  */
 struct pqueue *
-pqinit(struct pqueue *q, uint32_t n)
+pqinit(struct pqueue *q, size_t n)
 {
     struct pqueue *tmp = q;
 
@@ -403,7 +403,7 @@ int
 pqinsert(struct pqueue *q, struct resItem *d)
 {
     struct resItem **tmp;
-    uint32_t i, newsize;
+    size_t i, newsize;
 
     if (!q)
         return 0;
@@ -473,7 +473,7 @@ pqremove_min(struct pqueue *q, struct resItem **d)
 struct resItem **
 pqremove_max(struct pqueue *q, struct resItem **d)
 {
-    uint32_t i;
+    size_t i;
 
     if (!q || q->size == 1)
         return NULL;
diff --git a/src/kdtreelib/pqueue.h b/src/kdtreelib/pqueue.h
index 68d85df..5f5406b 100644
--- a/src/kdtreelib/pqueue.h
+++ b/src/kdtreelib/pqueue.h
@@ -8,17 +8,17 @@
 
 #define PQPRIO(p) (p->dist_sq)
 
-int floorLog2(uint32_t n);
+int floorLog2(size_t n);
 int is_max_level(int i);
-uint32_t get_max_index(struct pqueue *q);
-uint32_t pq_get_min_child_index(struct pqueue *q, uint32_t i);
-uint32_t pq_get_max_child_index(struct pqueue *q, uint32_t i);
-void pq_swap_nodes(struct pqueue *q, uint32_t i, uint32_t j);
-void trickle_down(struct pqueue *q, uint32_t i);
-void trickle_down_min(struct pqueue *q, uint32_t i);
-void trickle_down_max(struct pqueue *q, uint32_t i);
-void bubble_up(struct pqueue *q, uint32_t i);
-void bubble_up_min(struct pqueue *q, uint32_t i);
-void bubble_up_max(struct pqueue *q, uint32_t i);
+size_t get_max_index(struct pqueue *q);
+size_t pq_get_min_child_index(struct pqueue *q, size_t i);
+size_t pq_get_max_child_index(struct pqueue *q, size_t i);
+void pq_swap_nodes(struct pqueue *q, size_t i, size_t j);
+void trickle_down(struct pqueue *q, size_t i);
+void trickle_down_min(struct pqueue *q, size_t i);
+void trickle_down_max(struct pqueue *q, size_t i);
+void bubble_up(struct pqueue *q, size_t i);
+void bubble_up_min(struct pqueue *q, size_t i);
+void bubble_up_max(struct pqueue *q, size_t i);
 
 #endif
diff --git a/src/lib/ncl/Makefile.am b/src/lib/ncl/Makefile.am
new file mode 100644
index 0000000..1d3ed60
--- /dev/null
+++ b/src/lib/ncl/Makefile.am
@@ -0,0 +1,6 @@
+## Process this file with automake to produce Makefile.in
+#
+if USE_F77
+noinst_LTLIBRARIES = libncl.la
+libncl_la_SOURCES = rvdv.f
+endif
diff --git a/contrib/Makefile.in b/src/lib/ncl/Makefile.in
similarity index 69%
copy from contrib/Makefile.in
copy to src/lib/ncl/Makefile.in
index a9577ba..2d99e94 100644
--- a/contrib/Makefile.in
+++ b/src/lib/ncl/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -13,8 +13,19 @@
 # PARTICULAR PURPOSE.
 
 @SET_MAKE@
+
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -77,11 +88,11 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = contrib
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs COPYING
+subdir = src/lib/ncl
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -90,10 +101,21 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libncl_la_LIBADD =
+am__libncl_la_SOURCES_DIST = rvdv.f
+ at USE_F77_TRUE@am_libncl_la_OBJECTS = rvdv.lo
+libncl_la_OBJECTS = $(am_libncl_la_OBJECTS)
+AM_V_lt = $(am__v_lt_ at AM_V@)
+am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+ at USE_F77_TRUE@am_libncl_la_rpath =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -106,14 +128,50 @@ AM_V_at = $(am__v_at_ at AM_V@)
 am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
 am__v_at_0 = @
 am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
+DEFAULT_INCLUDES = -I. at am__isrc@ -I$(top_builddir)/src
+F77COMPILE = $(F77) $(AM_FFLAGS) $(FFLAGS)
+LTF77COMPILE = $(LIBTOOL) $(AM_V_lt) --tag=F77 $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(F77) $(AM_FFLAGS) $(FFLAGS)
+AM_V_F77 = $(am__v_F77_ at AM_V@)
+am__v_F77_ = $(am__v_F77_ at AM_DEFAULT_V@)
+am__v_F77_0 = @echo "  F77     " $@;
+am__v_F77_1 = 
+F77LD = $(F77)
+F77LINK = $(LIBTOOL) $(AM_V_lt) --tag=F77 $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(F77LD) $(AM_FFLAGS) $(FFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_F77LD = $(am__v_F77LD_ at AM_V@)
+am__v_F77LD_ = $(am__v_F77LD_ at AM_DEFAULT_V@)
+am__v_F77LD_0 = @echo "  F77LD   " $@;
+am__v_F77LD_1 = 
+SOURCES = $(libncl_la_SOURCES)
+DIST_SOURCES = $(am__libncl_la_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -156,18 +214,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -243,6 +305,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -290,11 +353,14 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = makecompl.rb cdoCompletion.bash cdoCompletion.tcsh cdoCompletion.zsh
-CLEANFILES = `ls cdoCompletion.*`
+
+#
+ at USE_F77_TRUE@noinst_LTLIBRARIES = libncl.la
+ at USE_F77_TRUE@libncl_la_SOURCES = rvdv.f
 all: all-am
 
 .SUFFIXES:
+.SUFFIXES: .f .lo .o .obj
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -304,10 +370,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	      exit 1;; \
 	  esac; \
 	done; \
-	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/Makefile'; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib/ncl/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
-	  $(AUTOMAKE) --foreign contrib/Makefile
-.PRECIOUS: Makefile
+	  $(AUTOMAKE) --foreign src/lib/ncl/Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -326,17 +391,92 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
 	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libncl.la: $(libncl_la_OBJECTS) $(libncl_la_DEPENDENCIES) $(EXTRA_libncl_la_DEPENDENCIES) 
+	$(AM_V_F77LD)$(F77LINK) $(am_libncl_la_rpath) $(libncl_la_OBJECTS) $(libncl_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.f.o:
+	$(AM_V_F77)$(F77COMPILE) -c -o $@ $<
+
+.f.obj:
+	$(AM_V_F77)$(F77COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.f.lo:
+	$(AM_V_F77)$(LTF77COMPILE) -c -o $@ $<
+
 mostlyclean-libtool:
 	-rm -f *.lo
 
 clean-libtool:
 	-rm -rf .libs _libs
-tags TAGS:
-
-ctags CTAGS:
 
-cscope cscopelist:
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
 
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
 	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -370,7 +510,7 @@ distdir: $(DISTFILES)
 	done
 check-am: all-am
 check: check-am
-all-am: Makefile all-local
+all-am: Makefile $(LTLIBRARIES)
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -394,7 +534,6 @@ install-strip:
 mostlyclean-generic:
 
 clean-generic:
-	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
 	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
@@ -405,11 +544,13 @@ maintainer-clean-generic:
 	@echo "it deletes files that may require special tools to rebuild."
 clean: clean-am
 
-clean-am: clean-generic clean-libtool mostlyclean-am
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
 
 distclean: distclean-am
 	-rm -f Makefile
-distclean-am: clean-am distclean-generic
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
 
 dvi: dvi-am
 
@@ -457,7 +598,8 @@ maintainer-clean-am: distclean-am maintainer-clean-generic
 
 mostlyclean: mostlyclean-am
 
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
 
 pdf: pdf-am
 
@@ -471,38 +613,22 @@ uninstall-am:
 
 .MAKE: install-am install-strip
 
-.PHONY: all all-am all-local check check-am clean clean-generic \
-	clean-libtool cscopelist-am ctags-am distclean \
-	distclean-generic distclean-libtool distdir dvi dvi-am html \
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
 	html-am info info-am install install-am install-data \
 	install-data-am install-dvi install-dvi-am install-exec \
 	install-exec-am install-html install-html-am install-info \
 	install-info-am install-man install-pdf install-pdf-am \
 	install-ps install-ps-am install-strip installcheck \
 	installcheck-am installdirs maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-generic \
-	mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
-	uninstall-am
-
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
 
-completions:
-	if hash ruby >/dev/null 2>&1 ; then \
-	  ruby -KN $(srcdir)/makecompl.rb -o cdoCompletion; \
-	fi
-
-cdoCompletion.bash cdoCompletion.zsh cdoCompletion.tcsh: completions
-
-test:
-	if hash ruby >/dev/null 2>&1 ; then \
-	    cd ruby;ruby test/test_cdo.rb \
-	fi
-	if hash python >/dev/null 2>&1 ; then \
-	    cd python; python test/test_cdo.py \
-	fi
+.PRECIOUS: Makefile
 
-#if MAINTAINER_MODE
-all-local: completions
-#endif
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/lib/ncl/rvdv.f b/src/lib/ncl/rvdv.f
new file mode 100644
index 0000000..82fd5f1
--- /dev/null
+++ b/src/lib/ncl/rvdv.f
@@ -0,0 +1,456 @@
+C NCLFORTSTART
+      SUBROUTINE DVRFIDF(U,V,GLAT,GLON,MLON,NLAT,XMSG,IOPT,RV,IER)
+      IMPLICIT NONE
+
+c relative vorticity via finite differences
+c NCL: rv = uv2vr_cfd (u,v,lat,lon,cyclic)
+
+c            xmsg = u at _FillValue
+c            nlat,mlon = dimsizes (u)
+c            iopt= cyclic
+
+c relative vorticity via centered finite difference approach (rv)
+c .  rv = dv/dx-du/dy+(u/a)tan(lat)   where "d" means partial derivitive
+c reference: Bluestein p113-114 [was not the original reference]
+c            Halt-Martin p314   [ nothing on rv] 
+
+c assumptions:
+c .   (1) latitudes  monotonically increasing  [eg: glat(2) > glat(1)]
+c .                  latitudes may be unequally spaced
+c .   (2) longitudes monotonically increasing  [eg: glon(2) > glon(1)]
+c .                  longitudes are assmed to be equally spaced
+c .   (3) if iopt=1 then the grids are cyclic in x
+c .                  eg: for T42 grid mlon=128, nlat=64
+c .                      cyclic point should NOT be included
+c .
+c                                          ! INPUT
+      INTEGER MLON,NLAT
+      DOUBLE PRECISION U(MLON,NLAT),V(MLON,NLAT),GLAT(NLAT),GLON(MLON),
+     +                 XMSG
+      INTEGER IOPT
+
+c                                          ! OUTPUT
+      DOUBLE PRECISION RV(MLON,NLAT)
+      INTEGER IER
+C NCLEND
+c                                          ! LOCAL  (dynamic/adjustable)
+      DOUBLE PRECISION CLAT(NLAT),DX(NLAT),DLON,DX2(NLAT),DLON2,
+     +                 DY2(NLAT),DYTOP,DYBOT,RE,RAD,RCON,
+     +                 POLAT,TLATRE(NLAT)
+      INTEGER ML,NL,MLSTRT,MLEND,MLM1,MLP1,JOPT
+
+c                                          ! error chk stuff
+      IER = 0
+      IF (MLON.LT.1 .OR. NLAT.LT.1) THEN
+          IER = 1
+          RETURN
+      END IF
+      IF (ABS(GLAT(1)).gt.90.D0 .OR. ABS(GLAT(NLAT)).GT.90.D0) THEN
+          IER = 2
+          RETURN
+      END IF
+
+
+      RE = 6.37122D06
+      RAD = 4.D0*ATAN(1.D0)/180.D0
+      RCON = RE*RAD
+      JOPT = ABS(IOPT)
+c                                 ! pre-compute cos(lat)
+      DO NL = 1,NLAT
+          CLAT(NL)   = COS(RAD*GLAT(NL))
+      END DO
+c                                 ! pre-compute tan(lat)/re
+c                                 ! pole pts will not be used below
+      DO NL = 1,NLAT
+         IF (ABS(GLAT(NL)).LT.90.D0) THEN
+             TLATRE(NL) = TAN(RAD*GLAT(NL))/RE
+         ELSE
+             IF (GLAT(NL).EQ.90.D0) THEN
+                 POLAT = 0.5*(GLAT(NL)+GLAT(NL-1))
+                 TLATRE(NL) = TAN(RAD*POLAT)/RE
+             ELSE
+                 POLAT = 0.5*(GLAT(NL)+GLAT(NL+1))
+                 TLATRE(NL) = TAN(RAD*POLAT)/RE
+             END IF
+         END IF
+      END DO
+        
+c                                          ! initialize to msg
+      DO NL = 1,NLAT
+          DO ML = 1,MLON
+              RV(ML,NL) = XMSG
+          END DO
+      END DO
+c                                          ! calculate "1/dy" [bot, top]
+      DYBOT = 1.D0/ (RCON* (GLAT(2)-GLAT(1)))
+      DYTOP = 1.D0/ (RCON* (GLAT(NLAT)-GLAT(NLAT-1)))
+c                                          ! calculate "1/(2*dy)"
+      DO NL = 2,NLAT - 1
+          DY2(NL) = 1.D0/ (RCON* (GLAT(NL+1)-GLAT(NL-1)))
+      END DO
+c                                       ! calculate "1/dx" [left, right]
+c                                       ! and "1/(2*dx)
+      DLON = GLON(2) - GLON(1)
+      DLON2 = GLON(3) - GLON(1)
+
+      DO NL = 1,NLAT
+          IF (ABS(GLAT(NL)).NE.90.D0) THEN
+              DX(NL) = 1.D0/ (RCON*DLON*CLAT(NL))
+              DX2(NL) = 1.D0/ (RCON*DLON2*CLAT(NL))
+          ELSE
+              DX(NL) = 0.0D0
+              DX2(NL) = 0.0D0
+          END IF
+      END DO
+c                                          ! set subscript range
+      IF (JOPT.EQ.1 .OR. JOPT.EQ.3) THEN
+          MLSTRT = 1
+          MLEND = MLON
+      ELSE
+          MLSTRT = 2
+          MLEND = MLON - 1
+      END IF
+c                                          ! longitude loop
+      DO ML = MLSTRT,MLEND
+c                                          ! iopt=0 or 1
+          MLM1 = ML - 1
+          MLP1 = ML + 1
+          IF (ML.EQ.1) MLM1 = MLON
+          IF (ML.EQ.MLON) MLP1 = 1
+c                                          ! rv in grid body
+          DO NL = 2,NLAT - 1
+              IF (V(MLP1,NL).NE.XMSG .AND. V(MLM1,NL).NE.XMSG .AND.
+     +            U(ML,NL+1).NE.XMSG .AND. U(ML,NL-1).NE.XMSG .AND.
+     +            U(ML,NL)  .NE.XMSG) THEN
+
+                  RV(ML,NL) = (V(MLP1,NL)-V(MLM1,NL))*DX2(NL) -
+     +                        (U(ML,NL+1)-U(ML,NL-1))*DY2(NL) +
+     +                         U(ML,NL)*TLATRE(NL) 
+
+              END IF
+          END DO
+
+          IF (JOPT.GE.2) THEN
+c                                   ! bottom bound (nl=1)
+              IF (V(MLP1,1).NE.XMSG .AND. V(MLM1,1).NE.XMSG .AND.
+     +            U(ML,2)  .NE.XMSG .AND. U(ML,1)  .NE.XMSG) THEN
+
+                  RV(ML,1) = (V(MLP1,1)-V(MLM1,1))*DX2(1) -
+     +                       (U(ML,2)-U(ML,1))*DYBOT      +
+     +                        U(ML,1)*TLATRE(1)
+              END IF
+c                                   ! top bound   (nl=nlat)
+              IF (V(MLP1,NLAT).NE.XMSG .AND. V(MLM1,NLAT).NE.XMSG .AND.
+     +            U(ML,NLAT)  .NE.XMSG .AND. U(ML,NLAT-1).NE.XMSG)THEN
+
+                  RV(ML,NLAT) = (V(MLP1,NLAT)-V(MLM1,NLAT))*DX2(NLAT) -
+     +                          (U(ML,NLAT)-U(ML,NLAT-1))*DYTOP       +
+     +                           U(ML,NLAT)*TLATRE(NLAT)
+              END IF
+          END IF
+      END DO
+c                                   ! ?left/right bound?
+      IF (JOPT.EQ.2) THEN
+          DO NL = 2,NLAT - 1
+c                                   ! left bound (ml=1)
+              IF (V(2,NL).NE.XMSG   .AND. V(1,NL)  .NE.XMSG .AND.
+     +            U(1,NL+1).NE.XMSG .AND. U(1,NL-1).NE.XMSG .AND.
+     +            U(1,NL)  .NE.XMSG) THEN
+
+                  RV(1,NL) = (V(2,NL)-V(1,NL))*DX(NL)      -
+     +                       (U(1,NL+1)-U(1,NL-1))*DY2(NL) +
+     +                        U(1,NL)*TLATRE(NL)
+              END IF
+c                                   ! right bound (ml=mlon)
+              IF (V(MLON,NL)  .NE.XMSG .AND. V(MLON-1,NL).NE.XMSG .AND.
+     +            U(MLON,NL+1).NE.XMSG .AND. U(MLON,NL-1).NE.XMSG .AND.
+     +            U(MLON,NL)  .NE.XMSG) THEN
+
+                  RV(MLON,NL) = (V(MLON,NL)-V(MLON-1,NL))*DX(NL)    -
+     +                          (U(MLON,NL+1)-U(MLON,NL-1))*DY2(NL) +
+     +                           U(MLON,NL)*TLATRE(NL)
+              END IF
+          END DO
+      END IF
+c                                   ! special at +/-90 use average
+      DO NL = 1,NLAT,NLAT - 1
+        IF (ABS(GLAT(NL)).EQ.90.D0) CALL DUSEAVE(RV(1,NL),MLON,XMSG)
+      END DO
+c                                   ! special for corners (jopt=2 only)
+c                                   ! use linear extrapolation from
+c                                   ! two directions
+      IF (JOPT.EQ.2) THEN
+          CALL DLNEXTRP(RV,MLON,NLAT,XMSG)
+      END IF
+
+      RETURN
+      END
+
+c NCLFORTSTART
+      SUBROUTINE DDVFIDF(U,V,GLAT,GLON,MLON,NLAT,XMSG,IOPT,DV,IER)
+      IMPLICIT NONE
+
+c divergence via centered finite differences
+c . div = dv/dy+du/dx-(v/re)*tan(lat)  where "d" ==> partial derivitive
+c 
+c reference: Bluestein p113-114 
+c            Halt-Martin p314   
+
+c NCL: dv = uv2dv_cfd (u,v,lat,lon,cyclic)
+c            xmsg = u at _FillValue
+c            nlat,mlon = dimsizes (u)
+c            iopt= cyclic
+
+c assumptions:
+c .   (1) latitudes  monotonically increasing  [eg: glat(2) > glat(1)]
+c .                  latitudes may be unequally spaced
+c .   (2) longitudes monotonically increasing  [eg: glon(2) > glon(1)]
+c .                  longitudes are assmed to be equally spaced
+c .   (3) if iopt=1 then the grids are cyclic in x
+c .                  eg: for T42 grid mlon=128, nlat=64
+c .                      cyclic point should NOT be included
+c .
+
+c                                          ! INPUT
+      INTEGER MLON,NLAT
+      DOUBLE PRECISION U(MLON,NLAT),V(MLON,NLAT),GLAT(NLAT),GLON(MLON),
+     +                 XMSG
+      INTEGER IOPT
+
+c                                          ! OUTPUT
+      DOUBLE PRECISION DV(MLON,NLAT)
+      INTEGER IER
+C NCLEND
+c                                          ! LOCAL  (dynamic/adjustable)
+      DOUBLE PRECISION CLAT(NLAT),DX(NLAT),DLON,DX2(NLAT),DLON2,
+     +                 DY2(NLAT),DYTOP,DYBOT,RE,RAD,RCON,
+     +                 POLAT,TLATRE(NLAT)
+      INTEGER ML,NL,MLSTRT,MLEND,MLM1,MLP1,JOPT
+
+c                                          ! error chk stuff
+      IER = 0
+      IF (MLON.LT.1 .OR. NLAT.LT.1) THEN
+          IER = 1
+          RETURN
+      END IF
+      IF (ABS(GLAT(1)).gt.90.D0 .OR. ABS(GLAT(NLAT)).GT.90.D0) THEN
+          IER = 2
+          RETURN
+      END IF
+
+      RE = 6.37122D06
+      RAD = 4.D0*ATAN(1.D0)/180.D0
+      RCON = RE*RAD
+      JOPT = ABS(IOPT)
+c                                 ! pre-compute cos(lat)
+      DO NL = 1,NLAT
+          CLAT(NL)   = COS(RAD*GLAT(NL))
+      END DO
+c                                 ! pre-compute tan(lat)/re
+c                                 ! pole pts will not be used below
+      DO NL = 1,NLAT
+         IF (ABS(GLAT(NL)).LT.90.D0) THEN
+             TLATRE(NL) = TAN(RAD*GLAT(NL))/RE
+         ELSE
+             IF (GLAT(NL).EQ.90.D0) THEN
+                 POLAT = 0.5*(GLAT(NL)+GLAT(NL-1))
+                 TLATRE(NL) = TAN(RAD*POLAT)/RE
+             ELSE
+                 POLAT = 0.5*(GLAT(NL)+GLAT(NL+1))
+                 TLATRE(NL) = TAN(RAD*POLAT)/RE
+             END IF
+         END IF
+      END DO
+c                                          ! initialize to msg
+      DO NL = 1,NLAT
+          DO ML = 1,MLON
+              DV(ML,NL) = XMSG
+          END DO
+      END DO
+c                                          ! calculate "1/dy" [bot, top]
+      DYBOT = 1.D0/ (RCON* (GLAT(2)-GLAT(1)))
+      DYTOP = 1.D0/ (RCON* (GLAT(NLAT)-GLAT(NLAT-1)))
+c                                          ! calculate "1/(2*dy)"
+      DO NL = 2,NLAT - 1
+          DY2(NL) = 1.D0/ (RCON* (GLAT(NL+1)-GLAT(NL-1)))
+      END DO
+c                                       ! calculate "1/dx" [left, right]
+c                                       ! and "1/(2*dx)
+      DLON = GLON(2) - GLON(1)
+      DLON2 = GLON(3) - GLON(1)
+
+      DO NL = 1,NLAT
+          IF (ABS(GLAT(NL)).NE.90.D0) THEN
+              DX(NL) = 1.D0/ (RCON*DLON*CLAT(NL))
+              DX2(NL) = 1.D0/ (RCON*DLON2*CLAT(NL))
+          ELSE
+              DX(NL) = 0.0D0
+              DX2(NL) = 0.0D0
+          END IF
+      END DO
+c                                          ! set subscript range
+      IF (JOPT.EQ.1 .OR. JOPT.EQ.3) THEN
+          MLSTRT = 1
+          MLEND = MLON
+      ELSE
+          MLSTRT = 2
+          MLEND = MLON - 1
+      END IF
+
+      DO ML = MLSTRT,MLEND
+          MLM1 = ML - 1
+          MLP1 = ML + 1
+          IF (ML.EQ.1) MLM1 = MLON
+          IF (ML.EQ.MLON) MLP1 = 1
+c                                          ! dv in grid body
+          DO NL = 2,NLAT - 1
+              IF (V(ML,NL+1).NE.XMSG .AND. V(ML,NL-1).NE.XMSG .AND.
+     +            U(MLP1,NL).NE.XMSG .AND. U(MLM1,NL).NE.XMSG .AND.
+     +            V(ML,NL)  .NE.XMSG) THEN
+
+                  DV(ML,NL) = (V(ML,NL+1)-V(ML,NL-1))*DY2(NL) +
+     +                        (U(MLP1,NL)-U(MLM1,NL))*DX2(NL) -
+     +                         V(ML,NL)*TLATRE(NL) 
+              END IF
+          END DO
+c                                   ! ?bottom/top bound? 
+          IF (JOPT.GE.2) THEN
+c                                   ! bottom bound (nl=1)
+              IF (V(ML,2)  .NE.XMSG .AND. V(ML,1)  .NE.XMSG .AND.
+     +            U(MLP1,2).NE.XMSG .AND. U(MLM1,1).NE.XMSG) THEN
+
+                  DV(ML,1) = (V(ML,2)-V(ML,1))*DYBOT      +
+     +                       (U(MLP1,1)-U(MLM1,1))*DX2(1) -
+     +                        V(ML,1)*TLATRE(1)
+              END IF
+c                                   ! top bound   (nl=nlat)
+              IF (V(ML,NLAT).NE.XMSG   .AND. V(ML,NLAT-1).NE.XMSG .AND.
+     +            U(MLP1,NLAT).NE.XMSG .AND. U(MLM1,NLAT).NE.XMSG) THEN
+
+                  DV(ML,NLAT) = (V(ML,NLAT)-V(ML,NLAT-1))*DYTOP      +
+     +                          (U(MLP1,NLAT)-U(MLM1,NLAT))*DX2(NLAT)-
+     +                           V(ML,NLAT)*TLATRE(NLAT)
+              END IF
+          END IF
+      END DO
+c                                   ! ?left/right bound?
+      IF (JOPT.EQ.2) THEN
+          DO NL = 2,NLAT - 1
+c                                   ! left bound (ml=1)
+              IF (V(1,NL+1).NE.XMSG .AND. V(1,NL-1).NE.XMSG .AND.
+     +            U(2,NL)  .NE.XMSG .AND. U(1,NL)  .NE.XMSG .AND.
+     +            V(1,NL)  .NE.XMSG) THEN
+
+                  DV(1,NL) = (V(1,NL+1)-V(1,NL-1))*DY2(NL) +
+     +                       (U(2,NL)-U(1,NL))*DX(NL) -
+     +                        V(1,NL)*TLATRE(NL)
+              END IF
+c                                   ! right bound (ml=mlon)
+              IF (V(MLON,NL+1).NE.XMSG .AND. V(MLON,NL-1).NE.XMSG .AND.
+     +            U(MLON,NL)  .NE.XMSG .AND. U(MLON-1,NL).NE.XMSG .AND.
+     +            V(MLON,NL)  .NE.XMSG) THEN
+
+                  DV(MLON,NL) = (V(MLON,NL+1)-V(MLON,NL-1))*DY2(NL) +
+     +                          (U(MLON,NL)-U(MLON-1,NL))*DX(NL) -
+     +                           V(MLON,NL)*TLATRE(NL)
+              END IF
+          END DO
+      END IF
+c                                   ! special at +/-90 use average
+      DO NL = 1,NLAT,NLAT - 1
+        IF (ABS(GLAT(NL)).EQ.90.D0) CALL DUSEAVE(DV(1,NL),MLON,XMSG)
+      END DO
+c                                   ! special for corners (jopt=2 only)
+c                                   ! use linear extrapolation from
+c                                   ! two directions
+      IF (JOPT.EQ.2) THEN
+          CALL DLNEXTRP(DV,MLON,NLAT,XMSG)
+      END IF
+
+      RETURN
+      END
+
+      SUBROUTINE DLNEXTRP(X,MLON,NLAT,XMSG)
+      IMPLICIT NONE
+
+c linearly extrapolate from two directions [take average]
+c .   for the corner pts
+
+      INTEGER MLON,NLAT
+      DOUBLE PRECISION X(MLON,NLAT),XMSG
+
+      INTEGER ML,NL
+
+      DO NL = 1,NLAT,NLAT - 1
+          DO ML = 1,MLON,MLON - 1
+              IF (X(ML,NL).EQ.XMSG) THEN
+                  IF (NL.EQ.1 .AND. ML.EQ.1) THEN
+                      IF (X(ML,NL+1).NE.XMSG .AND.
+     +                    X(ML,NL+2).NE.XMSG .AND.
+     +                    X(ML+1,NL).NE.XMSG .AND.
+     +                    X(ML+2,NL).NE.XMSG) THEN
+                          X(ML,NL) = (2.D0*X(ML,NL+1)-X(ML,NL+2)+
+     +                               2.D0*X(ML+1,NL)-X(ML+2,NL))*0.5D0
+                      END IF
+                  END IF
+                  IF (NL.EQ.1 .AND. ML.EQ.MLON) THEN
+                      IF (X(ML,NL+1).NE.XMSG .AND.
+     +                    X(ML,NL+2).NE.XMSG .AND.
+     +                    X(ML-1,NL).NE.XMSG .AND.
+     +                    X(ML-2,NL).NE.XMSG) THEN
+                          X(ML,NL) = (2.D0*X(ML,NL+1)-X(ML,NL+2)+
+     +                               2.D0*X(ML-1,NL)-X(ML-2,NL))*0.5D0
+                      END IF
+                  END IF
+                  IF (NL.EQ.NLAT .AND. ML.EQ.1) THEN
+                      IF (X(ML,NL-1).NE.XMSG .AND.
+     +                    X(ML,NL-2).NE.XMSG .AND.
+     +                    X(ML+1,NL).NE.XMSG .AND.
+     +                    X(ML+2,NL).NE.XMSG) THEN
+                          X(ML,NL) = (2.D0*X(ML,NL-1)-X(ML,NL-2)+
+     +                               2.D0*X(ML+1,NL)-X(ML+2,NL))*0.5D0
+                      END IF
+                  END IF
+                  IF (NL.EQ.NLAT .AND. ML.EQ.MLON) THEN
+                      IF (X(ML,NL-1).NE.XMSG .AND.
+     +                    X(ML,NL-2).NE.XMSG .AND.
+     +                    X(ML-1,NL).NE.XMSG .AND.
+     +                    X(ML-2,NL).NE.XMSG) THEN
+                          X(ML,NL) = (2.D0*X(ML,NL-1)-X(ML,NL-2)+
+     +                               2.D0*X(ML-1,NL)-X(ML-2,NL))*0.5D0
+                      END IF
+                  END IF
+              END IF
+          END DO
+      END DO
+
+      RETURN
+      END
+
+      SUBROUTINE DUSEAVE(X,MLON,XMSG)
+      IMPLICIT NONE
+c calculate average and use at all input grid points: +/- 90 only
+      INTEGER MLON
+      DOUBLE PRECISION X(MLON),XMSG
+c                                   ! local
+      INTEGER ML
+      DOUBLE PRECISION AVE,CNT
+
+      AVE = 0.0D0
+      CNT = 0.0D0
+      DO ML = 1,MLON
+          IF (X(ML).NE.XMSG) THEN
+              AVE = AVE + X(ML)
+              CNT = CNT + 1.0D0
+          END IF
+      END DO
+
+      IF (CNT.NE.0.0D0) THEN
+          AVE = AVE/CNT
+          DO ML = 1,MLON
+              X(ML) = AVE
+          END DO
+      END IF
+
+      RETURN
+      END
diff --git a/src/libncl.h b/src/libncl.h
new file mode 100644
index 0000000..3db3876
--- /dev/null
+++ b/src/libncl.h
@@ -0,0 +1,26 @@
+#ifndef LIBNCL_H
+#define LIBNCL_H
+
+#include "cf_interface.h"
+/*
+void DCFINDIF(double *,double *,int *,double *,
+              double *,int *,int *, double *,
+              double *,int *,double *,int *);
+
+void DVRFIDF(double *, double *, double *, double *, int, int, double, int, double *, int *);
+void DDVFIDF(double *, double *, double *, double *, int, int, double, int, double *, int *);
+*/
+
+// LIBNCL Fortran routines
+
+#ifdef HAVE_CF_INTERFACE
+
+PROTOCCALLSFSUB10(DDVFIDF, ddvfidf, DOUBLEV, DOUBLEV, DOUBLEV, DOUBLEV, INT, INT, DOUBLE, INT, DOUBLEV, PINT)
+#define DDVFIDF(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) CCALLSFSUB10(DDVFIDF, ddvfidf, DOUBLEV, DOUBLEV, DOUBLEV, DOUBLEV, INT, INT, DOUBLE, INT, DOUBLEV, PINT, A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)
+
+PROTOCCALLSFSUB10(DVRFIDF, dvrfidf, DOUBLEV, DOUBLEV, DOUBLEV, DOUBLEV, INT, INT, DOUBLE, INT, DOUBLEV, PINT)
+#define DVRFIDF(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) CCALLSFSUB10(DVRFIDF, dvrfidf, DOUBLEV, DOUBLEV, DOUBLEV, DOUBLEV, INT, INT, DOUBLE, INT, DOUBLEV, PINT, A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)
+
+#endif
+
+#endif
diff --git a/src/modules.cc b/src/modules.cc
index 18ef3fc..ac79b86 100644
--- a/src/modules.cc
+++ b/src/modules.cc
@@ -15,7 +15,7 @@
   GNU General Public License for more details.
 */
 
-#if defined(HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #include "config.h"
 #endif
 
@@ -123,6 +123,7 @@ void *Merstat(void *argument);
 void *Monarith(void *argument);
 void *Mrotuv(void *argument);
 void *Mrotuvb(void *argument);
+void *NCL_wind(void *argument);
 void *Ninfo(void *argument);
 void *Nmldump(void *argument);
 void *Output(void *argument);
@@ -376,6 +377,7 @@ void *Samplegrid(void *argument); // "samplegrid", "subgrid"
 #define  MonarithOperators      {"monadd", "monsub", "monmul", "mondiv"}
 #define  MrotuvOperators        {"mrotuv"}
 #define  MrotuvbOperators       {"mrotuvb"}
+#define  NCL_windOperators      {"uv2dv_cfd", "uv2vr_cfd"}
 #define  NinfoOperators         {"nyear", "nmon", "ndate", "ntime", "ncode", "npar", "nlevel", "ngridpoints", "ngrids"}
 #define  NmldumpOperators       {"nmldump", "kvldump"}
 #define  OutputOperators        {"output", "outputint", "outputsrv", "outputext", "outputf", "outputts", \
@@ -893,6 +895,7 @@ void init_modules()
   add_module("Monarith"      , {Monarith      , MonarithHelp      , MonarithOperators      , 1 , CDI_REAL , 2  , 1  });
   add_module("Mrotuv"        , {Mrotuv        , {}                , MrotuvOperators        , 1 , CDI_REAL , 1  , 2  });
   add_module("Mrotuvb"       , {Mrotuvb       , {}                , MrotuvbOperators       , 1 , CDI_REAL , 2  , 1  });
+  add_module("NCL_wind"      , {NCL_wind      , NCL_windHelp      , NCL_windOperators      , 1 , CDI_REAL , 1  , 1  });
   add_module("Ninfo"         , {Ninfo         , NinfoHelp         , NinfoOperators         , 1 , CDI_BOTH , 1  , 0  });
   add_module("Nmldump"       , {Nmldump       , {}                , NmldumpOperators       , 0 , CDI_REAL , 0  , 0  });
   add_module("Output"        , {Output        , OutputHelp        , OutputOperators        , 1 , CDI_REAL , -1 , 0  });
diff --git a/src/nearpt3c.cc b/src/nearpt3c.cc
new file mode 100644
index 0000000..1e807e1
--- /dev/null
+++ b/src/nearpt3c.cc
@@ -0,0 +1,32 @@
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#if defined(ENABLE_NEARPT3)
+#include "nearpt3x.h"
+#endif
+
+#include "nearpt3c.h"
+
+void *nearpt3_preprocess(const int nfixpts, Coord_T **pts)
+{
+#if defined(ENABLE_NEARPT3)
+  return (void *) nearpt3::Preprocess(nfixpts, pts);
+#endif
+}
+
+
+int nearpt3_query(void *g, const Coord_T *q)
+{
+#if defined(ENABLE_NEARPT3)
+  return nearpt3::Query((nearpt3::Grid_T<Coord_T> *) g, q);
+#endif
+}
+
+
+void nearpt3_destroy(void *g)
+{
+#if defined(ENABLE_NEARPT3)
+  nearpt3::Destroy((nearpt3::Grid_T<Coord_T> *) g);
+#endif
+}
diff --git a/src/nearpt3c.h b/src/nearpt3c.h
index 867db6e..eafa20c 100644
--- a/src/nearpt3c.h
+++ b/src/nearpt3c.h
@@ -6,12 +6,6 @@ typedef float Coord_T;
 #define NPT3SFACT 32000
 #define NPT3SCALE(x) (0.5+(x+1)*NPT3SFACT)
 
-#if defined(__cplusplus)
-extern "C" {
-#endif
 void *nearpt3_preprocess(const int nfixpts, Coord_T **pts);
 int nearpt3_query(void *g, const Coord_T *q);
 void nearpt3_destroy(void *g);
-#if defined(__cplusplus)
-}
-#endif
diff --git a/src/nearpt3x.h b/src/nearpt3x.h
new file mode 100644
index 0000000..f405636
--- /dev/null
+++ b/src/nearpt3x.h
@@ -0,0 +1,645 @@
+// Time-stamp: </wrf/c/nearpt3/nearpt3.cc, Mon,  5 Dec 2005, 23:00:33 EST, http://wrfranklin.org/>
+
+// Nearest point query in E3.
+
+// There are 2 user-callable subroutines:
+//  preprocess:   insert fixed points into a uniform grid. 
+// query: find the closest fixed point to a query point.
+
+// W. Randolph Franklin
+// nearpt3 AT wrfranklin.org (Plaintext preferred; attachments deprecated)
+// http://www.ecse.rpi.edu/Homepages/wrf/
+
+// Uwe Schulzweida: replaced boost arrays by C arrays
+//                  replaced boost vector by C arrays
+//                  changed square and Distance2 to float
+
+
+#include <algorithm>
+//#include <boost/multi_array.hpp> 
+#include <iomanip>
+#include <iostream>
+#include <fstream>
+#include <math.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <limits.h>
+#include <float.h>
+
+#include "compare.h"
+
+
+using namespace std;
+//using boost::array;
+
+// Print an expression's name then its value, possibly followed by a comma or endl.  
+// Ex: cout << PRINTC(x) << PRINTN(y);
+
+#define PRINT(arg)  #arg "=" << (arg)
+#define PRINTC(arg)  #arg "=" << (arg) << ", "
+#define PRINTN(arg)  #arg "=" << (arg) << endl
+
+
+// clamp_USI     Convert to an unsigned short int while clamping
+
+template <typename T>
+unsigned short int clamp_USI(T a) {
+  const unsigned short int m(USHRT_MAX);
+  const T mm(static_cast<T>(m));
+  return  
+    static_cast<unsigned short int>(a > mm ? mm : (a > 0 ? static_cast<unsigned short int>(a) : 0));
+}
+
+
+namespace nearpt3 {   // start of namespace nearpt3
+
+  double ng_factor = 1.6;   //  ng = ng_factor* cbrt(nfixpts)
+
+#ifdef STATS
+    static const int Cells_Checked_to_Closest_Point_Per_Query_Size(5000);
+#endif
+
+  float square(const float x) {
+    return x*x;
+  }
+
+  template <typename Coord_T>
+  float Distance2(const Coord_T a[3], const Coord_T b[3]) {
+    return (square((a[0]-b[0]))+square((a[1]-b[1]))+square((a[2]-b[2])));
+  }
+
+
+  // cellsearchorder:
+  // First 3 elements of each row:  the order in which to search (one 48th-ant of the) cells adjacent to the current cell.
+  // 4th element:   where, in cellsearchorder, to stop searching after the first point is found.
+  const static int  cellsearchorder[][4] = {
+#include "cellsearchorder.h"
+  };
+  // Number of cells in cellsearchorder (before expanding symmetries).
+  const static int ncellsearchorder = 
+    sizeof(nearpt3::cellsearchorder) / sizeof(nearpt3::cellsearchorder[0][0])/4;
+
+  typedef short int Cell3_Index_T;           // Type of a cell index
+  class Cell3 {     //   Cell ID, expressed as a triple.of Cell3_Index_T.
+  public:
+    Cell3_Index_T c[3];
+
+    Cell3(const Cell3_Index_T x, const Cell3_Index_T y, const Cell3_Index_T z) {
+      c[0] = x; c[1] = y; c[2] = z; }
+
+    Cell3(const Cell3 &a) { c[0] = a[0]; c[1] = a[1]; c[2] = a[2]; }
+
+    Cell3() { c[0] = -1; c[1] = -1; c[2] = -1; }
+
+    Cell3_Index_T & operator[] (const int i)  {  return c[i];  }
+
+    const Cell3_Index_T & operator[] (const int i) const {  return c[i];  }
+
+    const Cell3 operator+(const Cell3 &d) const {
+      Cell3 r;
+      r[0] = c[0]+d[0];
+      r[1] = c[1]+d[1];
+      r[2] = c[2]+d[2];
+      return r;
+    }
+
+    const Cell3 operator*(const int *d) const {
+      Cell3 r;
+      r[0] = c[0]*d[0];
+      r[1] = c[1]*d[1];
+      r[2] = c[2]*d[2];
+      return r;
+    }
+
+    bool operator==(const Cell3 &d)  const {
+      return c[0]==d[0] && c[1]==d[1] && c[2]==d[2];
+    }
+
+    //    const Cell3 operator*(const int *) const;
+  };
+
+  //  ostream& operator<<(ostream&, const Cell3& );
+
+
+
+
+  void write(ostream &o, const Cell3& c) {
+    o << '(' << c[0] << ',' << c[1] << ',' << c[2] << ") ";
+  }
+
+
+  // Grid_T is the main data structure to store the preprocessed points in a grid, plus auxiliary info.
+
+  template<typename Coord_T>
+  class Grid_T{
+  public:                  // start of Grid_T
+    int ng;                // Number of grid cells on a side
+    int ng3;               // ng*ng*ng
+    double r_cell;        // cellindex = coord*r_cell+d_cell;
+    double d_cell[3]; 
+    int nfixpts;           // number of fixed points.
+    //  const array<Coord_T,3>  * pts;   // pointer to user-supplied points.
+    Coord_T  **pts;     // pointer to user-supplied points.
+    int *cells;  // The indices (in pts) of the points in each cell, for all the cells.
+    int *base;   // Dope vector pointing to the start of each cell, in cells.  The i-th point of 
+    // the j-th cell is cells[base[j]+i].   Also, initially this is used to count the number of points per cell.
+
+#ifdef STATS
+    int   Max_Cells_Checked_to_1st_Point_Per_Query;
+    float Average_Cells_Checked_to_1st_Point_Per_Query;
+    int Tot_Cells_Checked_to_1st_Point_Per_Query;
+    int *Cells_Checked_to_1st_Point_Per_Query;
+    int *Cells_Checked_to_Closest_Point_Per_Query;
+    int *Points_Checked_Per_Query;
+#endif
+
+    // check and clip cannot be members of Cell3 since they need access to ng.
+
+    // Check if this is a legal cell.
+    bool check(const Cell3 a) const;
+
+    // clip is needed because roundoff errors may cause a number to be slightly outside the legal range. 
+    void clip(Cell3 &a);
+
+    template<typename T> 
+    void Check_Range(const string msg, const int i, const T x, const T lo, const T hi);
+
+    void Check_Range(const string msg, const int i, const Cell3 x);
+
+    // cellid_to_int: Convert Cell ID from 3 short ints to one int.  The following static_casts are
+    // to prevent an overflow during the multiplication in case ng is short int.  If the arg is out
+    // of range, as might happen for a query, then return -1.
+
+    int cellid_to_int(const Cell3 a) const;
+
+
+    // Compute_Cell_Containing_Point: Return the cell number containing point p.  Note the p is a
+    // array<Coord_T, 3>, not an id of a point.  This is necessary since
+    // Compute_Cell_Containing_Point is used for both fixed and query points.
+
+    const Cell3 Compute_Cell_Containing_Point(const Coord_T p[3]);
+
+    // N_Points_in_This_Cell: Return the number of fixed points in cell ic.  If the arg is out of
+    // range, as will happen for a really distant query, then return 0.
+
+    int N_Points_in_This_Cell(const int ic);
+
+    // querythiscell: Query cell thiscell with query point querypt.  Return closestpt, the index of
+    // the closest fixed point in the cell, and dist2, the square of the distance.  Return -1 if
+    // there are no points in this cell.
+
+    void querythiscell(const Cell3 thiscell, const Coord_T querypt[3], 
+		       int &closestpt, double &dist2);
+
+    // Query_Fast_Case: Return the id of the closest fixed point to query point iq, for the fast case
+    // of the query point cell containing at least one fixed point.
+
+    // If that cell has no fixed point, then return -1.
+
+    int Query_Fast_Case(const Coord_T q[3],   const Cell3 querycell);
+
+  };   // End of Grid_T
+
+
+#ifdef STATS
+  int N_Cells_Checked_to_1st_Point_This_Query;
+  int N_Points_Checked_This_Query;
+#endif
+  int N_Cells_Checked_to_Closest_Point_This_Query;
+
+  // Check if this is a legal cell.
+  template<typename Coord_T> bool  nearpt3::Grid_T<Coord_T>::check(const Cell3 a) const {
+    if (a[0] < 0 || a[0] >= ng ) return false;
+    if (a[1] < 0 || a[1] >= ng ) return false;
+    if (a[2] < 0 || a[2] >= ng ) return false;
+    return true;
+  }
+
+  // clip is needed because roundoff errors may cause a number to be slightly outside the legal range. 
+  template<typename Coord_T> void nearpt3::Grid_T<Coord_T>:: clip(Cell3 &a) {
+
+    //    a[0] = min(ng-1, max(0, a[0]));
+
+    if (a[0] < 0) a[0] = 0;
+    if (a[0] >= ng) a[0] = ng-1;
+    if (a[1] < 0) a[1] = 0;
+    if (a[1] >= ng) a[1] = ng-1;
+    if (a[2] < 0) a[2] = 0;
+    if (a[2] >= ng) a[2] = ng-1;
+  }
+
+  template<typename T> 
+  void Check_Range(const string msg, const int i, const T x, const T lo, const T hi) {
+    if (x<lo || x>hi) {
+      cout << "ERROR, number out of range: " << msg << ' ' << PRINTC(i) << PRINTC(x) << PRINTC(lo) << PRINTN(hi);
+      throw "Number out of range";
+    }
+  }
+
+  template<typename Coord_T> void nearpt3::Grid_T<Coord_T> :: 
+  Check_Range(const string msg, const int i, const Cell3 x) {
+    if (!check(x)) {
+      cout << "ERROR, cell3 out of the range [0,ng): " << msg << ' ' << PRINTC(i) << PRINTC(x[0]) << PRINTC(x[1]) << PRINTC(x[2]) << PRINTN(ng);
+      throw "Cell3 out of range";
+    }
+  }
+
+
+  // cellid_to_int: Convert Cell ID from 3 short ints to one int.  The following static_casts are
+  // to prevent an overflow during the multiplication in case ng is short int.  If the arg is out
+  // of range, as might happen for a query, then return -1.
+
+  template<typename Coord_T> int nearpt3::Grid_T<Coord_T>::
+  cellid_to_int(const Cell3 a) const { 
+    if (a[0]<0 || a[0] >=ng || a[1]<0 || a[1] >=ng || a[2]<0 || a[2] >=ng) return -1;
+    return  (static_cast<int> (a[0])*ng + static_cast<int>(a[1]))*ng + a[2]; 
+  }
+
+
+
+  // Compute_Cell_Containing_Point: Return the cell number containing point p.  Note the p is a
+  // array<Coord_T, 3>, not an id of a point.  This is necessary since
+  // Compute_Cell_Containing_Point is used for both fixed and query points.
+
+  template<typename Coord_T> const nearpt3::Cell3 nearpt3::Grid_T<Coord_T>::
+  Compute_Cell_Containing_Point(const Coord_T p[3]) {
+    const short int ix = static_cast<short int>(static_cast<double>(p[0])*r_cell+d_cell[0]);   // This must truncate not round.
+    const short int iy = static_cast<short int>(static_cast<double>(p[1])*r_cell+d_cell[1]);
+    const short int iz = static_cast<short int>(static_cast<double>(p[2])*r_cell+d_cell[2]);
+    Cell3 c(ix, iy, iz);
+    return c;
+  }
+
+  // N_Points_in_This_Cell: Return the number of fixed points in cell ic.  If the arg is out of
+  // range, as will happen for a really distant query, then return 0.
+
+  template<typename Coord_T> int nearpt3::Grid_T<Coord_T> :: 
+  N_Points_in_This_Cell(const int ic) {
+    if (ic<0) return 0;
+    return base[ic+1] - base[ic];
+  }
+
+
+  // querythiscell: Query cell thiscell with query point querypt.  Return closestpt, the index of
+  // the closest fixed point in the cell, and dist2, the square of the distance.  Return -1 if
+  // there are no points in this cell.
+
+  template<typename Coord_T> void nearpt3::Grid_T<Coord_T> :: 
+  querythiscell(const Cell3 thiscell, const Coord_T querypt[3], 
+		int &closestpt, double &dist2) {
+    closestpt = -1;
+    dist2 = FLT_MAX;
+    int ic = cellid_to_int(thiscell);
+    const int ppc = N_Points_in_This_Cell(ic);
+    for (int i=0; i<ppc; i++) {
+      const int ip = base[ic]+i;
+      const double d2 = (double) Distance2(pts[cells[ip]], querypt);
+      if (d2 < dist2 || (d2<=dist2 && cells[ip]<closestpt)) {
+	dist2 = d2;
+	closestpt = cells[ip];
+      }
+    }
+    return;
+  }
+
+
+
+  // Query_Fast_Case: Return the index of the closest fixed point to query point iq, for the fast case
+  // of the query point cell containing at least one fixed point.
+
+  // If that cell has no fixed point, then return -1.
+
+  template<typename Coord_T> int nearpt3::Grid_T<Coord_T> :: 
+  Query_Fast_Case(const Coord_T q[3],   const Cell3 querycell) 
+  {               //  Query_Fast_Case
+    const int queryint(cellid_to_int(querycell));
+    const int npitc(N_Points_in_This_Cell(queryint));
+    if (npitc<=0) return -1;   // Are there any points in this cell?
+    // Find the closest point in this cell.
+    int closestpt = -1;
+    double dist2 = FLT_MAX;
+    for (int i=base[queryint]; i<base[queryint+1]; i++) {
+      const double d2 = (double) Distance2(pts[cells[i]], q);
+      if (d2 < dist2 || (d2<=dist2 && cells[i]<closestpt)) {
+	dist2 = d2;
+	closestpt = cells[i];
+      }
+    }
+
+    const double distf = sqrt(dist2) * 1.00001; // fudge factor for roundoff error
+
+    //    cerr /* << PRINTC(q) */ << PRINTC(querycell[0])<< PRINTC(querycell[1])<< PRINTC(querycell[2]) << PRINTN(dist2);
+
+    Coord_T lopt[3], hipt[3];
+    for (int i=0; i<3; i++) {
+      lopt[i] = static_cast<unsigned short int> (clamp_USI(static_cast<double>(q[i]) - distf));
+      hipt[i] = static_cast<unsigned short int> (clamp_USI(static_cast<double>(q[i]) + distf + 1.0));
+    }
+
+    //    cerr << PRINTC(lopt) << PRINTN(hipt);
+    Cell3 locell(Compute_Cell_Containing_Point(lopt));
+    Cell3 hicell(Compute_Cell_Containing_Point(hipt));
+
+    clip(locell);   // If the block of cells around the query goes outside the universe,...
+    clip(hicell);   // then clip it.
+
+    //    cerr << PRINTC(locell[0]) << PRINTC(locell[1]) << PRINTC(locell[2]) << PRINTC(hicell[0])<< PRINTC(hicell[2])<< PRINTC(hicell[2]);
+
+#ifdef STATS
+    N_Cells_Checked_to_1st_Point_This_Query = 1;
+    N_Cells_Checked_to_Closest_Point_This_Query = 
+      (hicell[0]-locell[0]+1)*(hicell[1]-locell[1]+1)*(hicell[2]-locell[2]+1);
+#endif
+
+    if (locell == querycell && hicell == querycell) return closestpt;
+
+    for (Coord_T x=locell[0]; x<=hicell[0]; x++)
+      for (Coord_T y=locell[1]; y<=hicell[1]; y++) {
+	// Do a whole z-row of cells at once.
+	const int i01 = (static_cast<int>(x)*ng + static_cast<int>(y))*ng;
+	const int i0 = i01 + locell[2];
+	const int i1 = i01 + hicell[2];
+	const int hibase=base[i1+1];
+	for (int i=base[i0]; i<hibase; i++) {
+	  const double d2 = (double) Distance2(pts[cells[i]], q);
+	  if (d2 < dist2 || (IS_EQUAL(d2,dist2) && cells[i]<closestpt)) {
+	    dist2 = d2;
+	    closestpt = cells[i];
+	  }
+	}
+      }
+    if (closestpt<0) throw "closestpt<0 at end of Query_Fast_Case but this cell has a point";
+    return closestpt;
+  }         // Query_Fast_Case
+
+
+
+  //   PREPROCESS
+
+  template<typename Coord_T> Grid_T<Coord_T> * 
+  //   Preprocess(const int nfixpts, const array<Coord_T, 3> pts[]) { // preprocess
+    Preprocess(const int nfixpts, Coord_T **pts) { // preprocess
+    Grid_T<Coord_T> *g;
+    g = new Grid_T<Coord_T>;
+    g->nfixpts = nfixpts;
+    int &ng = g->ng;
+    ng = static_cast<int> (ng_factor * cbrt(static_cast<double>(nfixpts)));
+
+    ng = min(2000, max(1, ng));
+    g->ng3 = ng * ng * ng;
+    g->pts = pts;
+
+
+    // The following check might catch a scrambled cellsearchorder file.
+    for (int i=1; i< ncellsearchorder; i++) 
+      if (nearpt3::cellsearchorder[i-1][3] > nearpt3::cellsearchorder[i][3]) 
+	throw "cellsearchorder is not monotonic";
+
+    double lo[3];
+    double hi[3];
+    for(int i=0;i<3;i++) {
+      lo[i] = DBL_MAX;
+      hi[i] = -1.e300;
+    }
+    for (int n=0; n<nfixpts; n++) {
+      for(int i=0;i<3;i++) {
+	lo[i] = min(lo[i], static_cast<double>(pts[n][i]));
+	hi[i] = max(hi[i], static_cast<double>(pts[n][i]));
+      }
+    }
+    double s[3];
+    for(int i=0; i<3; i++) {  
+      s[i] = 0.99 * ng / (hi[i]-lo[i]);  // allow for a little future roundoff error.
+    }
+    g->r_cell = min(min(s[0], s[1]), s[2]);
+
+    for(int i=0; i<3; i++) {
+      g->d_cell[i] = ((ng-1)-(lo[i]+hi[i])*g->r_cell) * 0.5;
+    }
+
+
+    // Initially use base to count the number of points per cell.
+    g->base = 0;
+    g->base = new int[g->ng3+1];
+    for (int ic=0; ic < g->ng3; ic++) g->base[ic] = 0;
+
+    for (int ip=0; ip<nfixpts; ip++) {       // Count number of points in each cell.
+      const nearpt3::Cell3 c(g->Compute_Cell_Containing_Point(pts[ip]));
+      g->Check_Range("Cell in pointspercell++", ip, c);
+      const int k = g->cellid_to_int(c);
+#ifdef DEBUG
+      cout << PRINTC(ip) << PRINTC(pts[ip]) << PRINTN(c.c);
+#endif
+      if (k<0) throw "illegal k in Preprocess";
+      g->base[k]++;
+      if (g->base[k] > 1000000) {        // Catch an error
+	throw "base entry unreasonably large";
+      }
+    }
+
+    // Now change base[i] from storing the number of points in cell #i to storing the number of
+    // points before cell #i.
+
+#ifdef STATS
+    const float Average_Points_Per_Cell
+      (static_cast<float>(nfixpts)/static_cast<float>(g->ng3)); 
+    int Max_Points_Per_Cell(0);
+    const int Points_Per_Cell_Size(500);
+    int Points_Per_Cell[Points_Per_Cell_Size];
+    for ( int i = 0; i < 500; ++i ) Points_Per_Cell[i] = 0;
+#endif
+
+    int k = g->base[0];
+    g->base[0] = 0;
+    for (int ic=1; ic< g->ng3; ic++) {
+      int ppc = g->base[ic];
+#ifdef STATS
+      Max_Points_Per_Cell = max(Max_Points_Per_Cell, ppc);
+      Points_Per_Cell[min(ppc,Points_Per_Cell_Size-1)]++;
+#endif
+      g->base[ic] = g->base[ic-1] + k;
+      k = ppc;
+    }
+    g->base[g->ng3] = g->base[g->ng3-1]+k;
+    if (g->base[g->ng3] != nfixpts) {
+      cout << "ERROR: Internal inconsistency; wrong " << PRINTN(g->base[g->ng3]);
+      throw "Internal inconsistency";
+    }
+
+    g->cells = 0;
+    g->cells = new int[nfixpts];
+
+    // Set the last point of each cell to count how many points have been inserted into that cell so far. 
+    for (int i=1; i<= g->ng3; i++)
+      if ( (g->base)[i]-1 >= 0 ) // Uwe Schulzweida: check bounds
+        (g->cells)[(g->base)[i]-1] = 0;
+
+    // Insert the points into the grid.
+
+    for (int ip=0; ip<nfixpts; ip++) {    
+      const int ic(g->cellid_to_int(g->Compute_Cell_Containing_Point(pts[ip])));
+      const int Points_In_This_Cell = g->cells[g->base[ic+1]-1]++;
+      g->cells[g->base[ic]+Points_In_This_Cell] = ip;
+    }
+
+#ifdef STATS
+    cout << PRINTC(nfixpts) << PRINTC(ng) << PRINTC(Average_Points_Per_Cell) 
+	 << PRINTN(Max_Points_Per_Cell);
+    cout << "Histogram of the number of cells containing K points, 0<=K<" << Points_Per_Cell_Size << ":\n";
+    for(int i=0; i< Points_Per_Cell_Size; i++) {
+      if (Points_Per_Cell[i]>0) cout << i << ": " << Points_Per_Cell[i] << endl;
+    }
+    g->Cells_Checked_to_Closest_Point_Per_Query = new int[Cells_Checked_to_Closest_Point_Per_Query_Size];
+    g->Cells_Checked_to_1st_Point_Per_Query = new int[Cells_Checked_to_Closest_Point_Per_Query_Size];
+    g->Points_Checked_Per_Query = new int[Cells_Checked_to_Closest_Point_Per_Query_Size];
+#endif
+
+#ifdef DEBUG
+    cout << PRINTN(ng);
+    cout << "base: ";
+    for (int i=0; i<= g->ng3; i++) cout << i << ':' << g->base[i] << ' ';
+    cout << endl << "cells: ";
+    for (int i=0; i<nfixpts; i++) cout << i << ':' << g->cells[i] << ' ';
+    cout << endl;
+#endif
+
+    return g;
+
+  }    // preprocess
+
+
+  template <typename Coord_T>
+  void Destroy( Grid_T<Coord_T> *g ) { // Destroy
+    delete(g->cells);
+    delete(g->base);
+    delete(g);
+  }
+
+  // QUERY:  Return the id of the closest fixed point to query point iq.
+
+  template <typename Coord_T>
+  int Query( Grid_T<Coord_T> *g, const Coord_T q[3]) { // Query
+
+#ifdef STATS
+    N_Points_Checked_This_Query = 0;
+#endif
+
+    nearpt3::Cell3 querycell(g->Compute_Cell_Containing_Point(q));
+
+    // Usually the cell containing the query point has a fixed point.   This is faster to handle.
+
+    int closestpt(g->Query_Fast_Case(q, querycell));
+    if (closestpt>=0) {
+#ifdef STATS
+      g->Cells_Checked_to_Closest_Point_Per_Query[min(Cells_Checked_to_Closest_Point_Per_Query_Size-1, N_Cells_Checked_to_Closest_Point_This_Query)]++;
+#endif
+      return closestpt;
+    }
+
+    double dist(DBL_MAX);
+    bool foundit(false);   // Did we find a fixed point yet?
+    int nstop(ncellsearchorder);
+    N_Cells_Checked_to_Closest_Point_This_Query = 0;
+#ifdef STATS
+    N_Cells_Checked_to_1st_Point_This_Query = 0;
+#endif
+
+    //  Query cells in the order given in cellsearchorder until we find a cell with a point.  Then
+    //  keep querying out a little farther in case there is a closer point in another cell.
+
+    // nstop will be changed inside the loop.
+
+    for (int isort=0; isort<nstop; isort++) {  // isort loop
+      int thisclosest;
+      double thisdist;
+      Cell3 s (cellsearchorder[isort][0], cellsearchorder[isort][1], 
+	       cellsearchorder[isort][2]);
+
+      //  Derive the 47 other reflected cells from a particular cell being // searched.  That is, from
+      //  cell (1,2,3), generate (1,3,2), (1,3,-2), etc
+
+      for (int isign=0; isign<8; isign++) {      // Iterate over all combinations of signs;
+	static const int sign3[8][3] = {{1,1,1},{1,1,-1},{1,-1,1},{1,-1,-1},{-1,1,1},
+					{-1,1,-1},{-1,-1,1},{-1,-1,-1}};
+	if (s[0]==0 && sign3[isign][0]== -1) continue;
+	if (s[1]==0 && sign3[isign][1]== -1) continue;
+	if (s[2]==0 && sign3[isign][2]== -1) continue;
+
+	const Cell3 s2(s*sign3[isign]);
+
+	for (int iperm=0; iperm<6; iperm++) {   // Iterate over all permutations of coordinates.
+	  switch (iperm) {
+	  case 1:
+	    if (s[1]==s[2]) continue;
+	    break;
+	  case 2: 
+	    if (s[0]==s[1]) continue;
+	    break;
+	  case 3:
+	  case 4:
+	    if (s[0]==s[1] && s[0]==s[2]) continue;
+	    break;
+	  case 5:
+	    if (s[0]==s[2]) continue;
+	    break;
+	  }
+	  static const int perm3[6][3] = {{0,1,2},{0,2,1},{1,0,2},{1,2,0},{2,0,1},{2,1,0}};
+	  const Cell3 s3(s2[perm3[iperm][0]], s2[perm3[iperm][1]], s2[perm3[iperm][2]]);
+	  const Cell3 c2(querycell+s3);
+	  if (!g->check(c2)) continue;  // outside the universe?
+	  N_Cells_Checked_to_Closest_Point_This_Query++;
+	  g->querythiscell(c2, q, thisclosest, thisdist);
+	  if (thisclosest < 0) continue;
+
+	  // If two fixed points are the same distance from the query, then return the one with the
+	  // smallest index.  This removes ambiguities, but complicates the code in several places.
+
+	  if (thisdist<dist || (IS_EQUAL(thisdist,dist) && thisclosest<closestpt)) {
+	    dist = thisdist;
+	    closestpt = thisclosest;
+	    if (!foundit) {
+	      foundit = true;
+	      nstop = cellsearchorder[isort][3];
+	      if (nstop >= ncellsearchorder) {
+		// It took so long to find any cell with a point that cellsearchorder doesn't have
+		// enough cells to be sure of finding the closest point.  Fall back to naive
+		// exhaustive searching.
+		goto L_end_isort;
+	      }
+	    }
+	  }
+	}
+      }
+    }
+  L_end_isort: if (closestpt>=0) {
+#ifdef STATS
+      g->Cells_Checked_to_Closest_Point_Per_Query[min(Cells_Checked_to_Closest_Point_Per_Query_Size-1, N_Cells_Checked_to_Closest_Point_This_Query)]++;
+#endif
+      return closestpt;   
+    }
+    // No nearby points, so exhaustively search over all the fixed points.   
+    for (int i=0; i< g->nfixpts; i++) {
+      double d = (double) Distance2(q, g->pts[i]);
+      if (d< dist || (IS_EQUAL(d,dist) && i < closestpt)) {
+	dist = d;
+	closestpt = i;
+      }
+    }
+    return closestpt;  
+  }
+
+}  // end of namespace nearpt3
+
+
+/*
+template<typename Coord_T> 
+ostream &operator<<(ostream &o, const array<Coord_T,3> &c) {
+  o << '(' << c[0] << ',' << c[1] << ',' << c[2] << ')';
+  return o;
+}
+*/
diff --git a/src/operator_help.h b/src/operator_help.h
index c519612..b549df1 100644
--- a/src/operator_help.h
+++ b/src/operator_help.h
@@ -1502,6 +1502,7 @@ std::vector<std::string> ExprHelp = {
     "    abs(x)  "    "    Absolute value of x",
     "    floor(x)"    "    Round to largest integral value not greater than x",
     "    ceil(x) "    "    Round to smallest integral value not less than x",
+    "    float(x)"    "    32-bit float value of x",
     "    int(x)  "    "    Integer value of x",
     "    nint(x) "    "    Nearest integer value of x",
     "    sqr(x)  "    "    Square of x",
@@ -5146,12 +5147,39 @@ std::vector<std::string> CMORliteHelp = {
     "    convert  STRING   Converts the units if necessary",
 };
 
+std::vector<std::string> NCL_windHelp = {
+    "NAME",
+    "    uv2vr_cfd, uv2dv_cfd - Wind transformation",
+    "",
+    "SYNOPSIS",
+    "    <operator>[,u,v,boundOpt,outMode]  infile outfile",
+    "",
+    "DESCRIPTION",
+    "    This module contains CDO operators with an interface to NCL functions.",
+    "    The corresponding NCL functions have the same name. A more detailed description",
+    "    of those NCL function can be found on the NCL homepage https://www.ncl.ucar.edu.",
+    "",
+    "OPERATORS",
+    "    uv2vr_cfd  U and V wind to relative vorticity",
+    "               Computes relative vorticity for a latitude-longitude grid using centered finite differences.",
+    "               The grid need not be global and missing values are allowed.",
+    "    uv2dv_cfd  U and V wind to divergence",
+    "               Computes divergence for a latitude-longitude grid using centered finite differences.",
+    "               The grid need not be global and missing values are allowed.",
+    "",
+    "PARAMETER",
+    "    u         STRING   Name of variable u (default: u)",
+    "    v         STRING   Name of variable v (default: v)",
+    "    boundOpt  INTEGER  Boundary condition option (0-3) (default: 0/1 for cyclic grids)",
+    "    outMode   STRING   Output mode new/append (default: new)",
+};
+
 std::vector<std::string> CMORHelp = {
     "NAME",
     "    cmor - Climate Model Output Rewriting to produce CMIP-compliant data",
     "",
     "SYNOPSIS",
-    "    cmor,MIPtable[,cmor_name=VarList,[key=value,...]]  infile",
+    "    cmor,MIPtable[,cmor_name=VarList[,key=value[,...]]]  infile",
     "",
     "DESCRIPTION",
     "    ",
diff --git a/src/par_io.cc b/src/par_io.cc
index 0e68a76..0dbf971 100644
--- a/src/par_io.cc
+++ b/src/par_io.cc
@@ -17,7 +17,8 @@
 void *readRecord(void *arg)
 {
   int streamID;
-  int *varID, *levelID, *nmiss;
+  int *varID, *levelID;
+  size_t *nmiss;
   double *array;
   read_arg_t *read_arg = (read_arg_t *) arg;
 
@@ -36,7 +37,7 @@ void *readRecord(void *arg)
 }
 
 
-void parReadRecord(int streamID, int *varID, int *levelID, double *array, int *nmiss, par_io_t *parIO)
+void parReadRecord(int streamID, int *varID, int *levelID, double *array, size_t *nmiss, par_io_t *parIO)
 {
   int lpario = FALSE;
   int recID = 0, nrecs = 0;
diff --git a/src/par_io.h b/src/par_io.h
index 3b59c5a..a3c20e4 100644
--- a/src/par_io.h
+++ b/src/par_io.h
@@ -1,5 +1,5 @@
-#ifndef _PAR_IO_H
-#define _PAR_IO_H
+#ifndef PAR_IO_H
+#define PAR_IO_H
 
 #if defined(HAVE_CONFIG_H)
 #  include "config.h"
@@ -12,14 +12,16 @@
 
 typedef struct {
   int streamID;
-  int *varID, *levelID, *nmiss;
+  int *varID, *levelID;
+  size_t *nmiss;
   double *array;
 }
 read_arg_t;
 
 
 typedef struct {
-  int varID, levelID, nmiss;
+  int varID, levelID;
+  size_t nmiss;
   double *array;
   int array_size;
   int recID, nrecs;
@@ -32,6 +34,6 @@ typedef struct {
 par_io_t;
 
 
-void parReadRecord(int streamID, int *varID, int *levelID, double *array, int *nmiss, par_io_t *parIO);
+void parReadRecord(int streamID, int *varID, int *levelID, double *array, size_t *nmiss, par_io_t *parIO);
 
-#endif  /* _PAR_IO_H */
+#endif  /* PAR_IO_H */
diff --git a/src/pipe.cc b/src/pipe.cc
index b0797e8..bc4d094 100644
--- a/src/pipe.cc
+++ b/src/pipe.cc
@@ -402,12 +402,12 @@ pipe_t::pipeDefRecord(int p_varID, int p_levelID)
  * @param pipe pipe that has the wanted data
  */
 void
-pipe_t::pipeReadPipeRecord(double *p_data, int vlistID, int *p_nmiss)
+pipe_t::pipeReadPipeRecord(double *p_data, int vlistID, size_t *p_nmiss)
 {
   if (!p_data)
     Error("No data pointer for %s", name.c_str());
 
-  int datasize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  size_t datasize = gridInqSize(vlistInqVarGrid(vlistID, varID));
   nvals += datasize;
   if (vlistNumber(vlistID) != CDI_REAL)
     datasize *= 2;
@@ -443,7 +443,7 @@ pipeGetReadTarget(pstream_t *pstreamptr, pstream_t *pstreamptr_in)
 }
 */
 void
-pipe_t::pipeReadRecord(int p_vlistID, double *data, int *nmiss)
+pipe_t::pipeReadRecord(int p_vlistID, double *data, size_t *nmiss)
 {
   *nmiss = 0;
 
@@ -477,7 +477,7 @@ pipe_t::pipeReadRecord(int p_vlistID, double *data, int *nmiss)
 }
 
 void
-pipe_t::pipeWriteRecord(double *p_data, int p_nmiss)
+pipe_t::pipeWriteRecord(double *p_data, size_t p_nmiss)
 {
   /*
   if ( ! usedata ) return;
diff --git a/src/pipe.h b/src/pipe.h
index 4ace564..d208acb 100644
--- a/src/pipe.h
+++ b/src/pipe.h
@@ -53,9 +53,9 @@ public:
   int pipeInqTimestep(int p_tsID);
   int pipeInqRecord(int *varID, int *levelID);
 
-  void pipeWriteRecord(double *p_data, int p_nmiss);
-  void pipeReadRecord(int p_vlistID, double *data, int *nmiss);
-  void pipeReadPipeRecord(double *data, int vlistID, int *p_nmiss);
+  void pipeWriteRecord(double *p_data, size_t p_nmiss);
+  void pipeReadRecord(int p_vlistID, double *data, size_t *nmiss);
+  void pipeReadPipeRecord(double *data, int vlistID, size_t *p_nmiss);
 
   bool EOP;
   bool usedata;
@@ -63,10 +63,10 @@ public:
   int nrecs;
   int varID, levelID;
   int recIDr, recIDw, tsIDr, tsIDw;
-  int nmiss;
+  size_t nmiss;
   double *data;
   // pstream_t *pstreamptr_in;
-  /* unsigned long */ off_t nvals;
+  size_t nvals;
 
   std::mutex m_mutex;
   std::condition_variable tsDef, tsInq, vlistDef, isclosed;
diff --git a/src/printinfo.h b/src/printinfo.h
index 052055b..c916acf 100644
--- a/src/printinfo.h
+++ b/src/printinfo.h
@@ -125,7 +125,7 @@ void printFiletype(int streamID, int vlistID)
 static
 void print_xvals(int gridID, int dig)
 {
-  int xsize = gridInqXsize(gridID);
+  size_t xsize = gridInqXsize(gridID);
   if ( xsize > 0 && gridInqXvals(gridID, NULL) )
     {
       char xname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
@@ -151,7 +151,7 @@ void print_xvals(int gridID, int dig)
 static
 void print_yvals(int gridID, int dig)
 {
-  int ysize = gridInqYsize(gridID);
+  size_t ysize = gridInqYsize(gridID);
   if ( ysize > 0 && gridInqYvals(gridID, NULL) )
     {
       char yname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
@@ -209,23 +209,23 @@ void print_xyvals2D(int gridID, int dig)
       int gridtype = gridInqType(gridID);
       if ( gridtype == GRID_CURVILINEAR )
         {
-          int xsize = gridInqXsize(gridID);
+          size_t xsize = gridInqXsize(gridID);
           if ( xsize > 1 )
             {
               double *xvals = (double*) malloc((size_t)xsize*sizeof(double));
-              for ( int i = 0; i < xsize; ++i ) xvals[i] = xvals2D[i];
+              for ( size_t i = 0; i < xsize; ++i ) xvals[i] = xvals2D[i];
               xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-              for ( int i = 2; i < xsize; i++ )
+              for ( size_t i = 2; i < xsize; i++ )
                 if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc ) { xinc = 0; break; }
               free(xvals);
             }
-          int ysize = gridInqYsize(gridID);
+          size_t ysize = gridInqYsize(gridID);
           if ( ysize > 1 )
             {
               double *yvals = (double*) malloc((size_t)ysize*sizeof(double));
-              for ( int i = 0; i < ysize; ++i ) yvals[i] = yvals2D[i*xsize];
+              for ( size_t i = 0; i < ysize; ++i ) yvals[i] = yvals2D[i*xsize];
               yinc = fabs(yvals[ysize-1] - yvals[0])/(ysize-1);
-              for ( int i = 2; i < ysize; i++ )
+              for ( size_t i = 2; i < ysize; i++ )
                 if ( fabs(fabs(yvals[i-1] - yvals[i]) - yinc) > 0.01*yinc ) { yinc = 0; break; }
               free(yvals);
             }
diff --git a/src/process.cc b/src/process.cc
index 21f9a10..307994f 100644
--- a/src/process.cc
+++ b/src/process.cc
@@ -43,6 +43,7 @@
 #include "pthread.h"
 
 #include <map>
+#include <stack>
 
 #if defined(HAVE_LIBPTHREAD)
 pthread_mutex_t processMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -50,12 +51,44 @@ pthread_mutex_t processMutex = PTHREAD_MUTEX_INITIALIZER;
 
 constexpr bool PROCESS_DEBUG = false;
 
+static process_t *root_process;
 static std::map<int, process_t> Process;
 
 static int NumProcess = 0;
 static int NumProcessActive = 0;
 
-process_t::process_t(int p_ID) : m_ID(p_ID) { initProcess(); }
+process_t::process_t(int p_ID, char *operatorCommand) : m_ID(p_ID)
+{
+  initProcess();
+  operatorName = getOperatorName(operatorCommand);
+  setOperatorArgv(operatorCommand);
+  m_operatorCommand = operatorCommand;
+
+  defPrompt();  // has to be called after get operatorName
+
+  m_module = getModule(operatorName);
+}
+
+void
+process_t::setOperatorArgv(char *operatorArguments)
+{
+  if (operatorArguments)
+    {
+      char *operatorArg = operatorArguments;
+      // fprintf(stderr, "processDefArgument: %d %s\n", oargc, operatorArg);
+
+      while ((operatorArg = strchr(operatorArg, ',')) != NULL)
+        {
+          *operatorArg = '\0';
+          *operatorArg++;
+          if (strlen(operatorArg))
+            {
+              oargv.push_back(operatorArg);
+            }
+        }
+    }
+  oargc = oargv.size();
+}
 
 void
 process_t::initProcess()
@@ -70,15 +103,14 @@ process_t::initProcess()
   a_utime = 0;
   a_stime = 0;
   cputime = 0;
-  nvals = NULL;
-  nvars = NULL;
-  ntimesteps = NULL;
+  nvals = 0;
+  nvars = 0;
+  ntimesteps = 0;
 
-  streamCnt = 0;
+  m_streamCnt = 0;
 
   oargc = 0;
-  xoperator = "UNINITALIZED";
-  operatorName = "UNINITALIZED";
+  m_operatorCommand = "UNINITALIZED";
   operatorArg = "UNINITALIZED";
 
   noper = 0;
@@ -95,15 +127,15 @@ process_t::getOutStreamCnt()
   return outputStreams.size();
 }
 
-int
-processCreate(void)
+process_t *
+processCreate(char *command)
 {
 #if defined(HAVE_LIBPTHREAD)
   pthread_mutex_lock(&processMutex);
 #endif
 
   int processID = NumProcess++;
-  Process.insert(std::make_pair(processID, process_t(processID)));
+  Process.insert(std::make_pair(processID, process_t(processID, command)));
 
   NumProcessActive++;
 
@@ -114,7 +146,7 @@ processCreate(void)
   if (processID >= MAX_PROCESS)
     Error("Limit of %d processes reached!", MAX_PROCESS);
 
-  return processID;
+  return &Process.find(processID)->second;
 }
 
 process_t &
@@ -125,7 +157,7 @@ processSelf(void)
 
   pthread_mutex_lock(&processMutex);
 
-  for ( auto &id_process_pair : Process)
+  for (auto &id_process_pair : Process)
     if (id_process_pair.second.l_threadID)
       {
         if (pthread_equal(id_process_pair.second.threadID, thID))
@@ -135,11 +167,9 @@ processSelf(void)
           }
       }
 
-  std::cout << "returning the 0th process" << std::endl;
   pthread_mutex_unlock(&processMutex);
 
 #endif
-  std::cout << "returning the std process 0" << std::endl;
   return Process.find(0)->second;
 }
 
@@ -176,12 +206,12 @@ processNumsActive(void)
 }
 
 void
-processAddNvals(off_t nvals)
+processAddNvals(size_t nvals)
 {
   processSelf().nvals += nvals;
 }
 
-off_t
+size_t
 processInqNvals(int processID)
 {
   return Process.find(processID)->second.nvals;
@@ -302,14 +332,12 @@ processInqOpername(void)
 }
 
 void
-processDefPrompt(const char *opername)
+process_t::defPrompt()
 {
-  process_t &process = processSelf();
-
-  if (process.m_ID == 0)
-    sprintf(process.prompt, "%s %s", Progname, opername);
+  if (m_ID == 0)
+    sprintf(prompt, "%s %s", CDO_progname, operatorName);
   else
-    sprintf(process.prompt, "%s(%d) %s", Progname, process.m_ID + 1, opername);
+    sprintf(prompt, "%s(%d) %s", CDO_progname, m_ID + 1, operatorName);
 }
 
 const char *
@@ -385,7 +413,7 @@ glob_pattern(const char *restrict string)
 int
 cdoStreamCnt(void)
 {
-  int cnt = processSelf().streamCnt;
+  int cnt = processSelf().m_streamCnt;
   return cnt;
 }
 
@@ -394,7 +422,7 @@ cdoStreamName(int cnt)
 {
   process_t &process = processSelf();
 
-  if (cnt > process.streamCnt || cnt < 0)
+  if (cnt > process.m_streamCnt || cnt < 0)
     Error("count %d out of range!", cnt);
 
   return &(process.streamNames[cnt]);
@@ -403,13 +431,13 @@ cdoStreamName(int cnt)
 const char *
 processOperator(void)
 {
-  return processSelf().xoperator;
+  return processSelf().m_operatorCommand;
 }
 
-static int skipInputStreams(int argc,  std::vector<char *> &argv, int globArgc, int nstreams);
+static int skipInputStreams(int argc, std::vector<char *> &argv, int globArgc, int nstreams);
 
 static int
-getGlobArgc(int argc,  std::vector<char *> &argv, int globArgc)
+getGlobArgc(int argc, std::vector<char *> &argv, int globArgc)
 {
   char *opername = &argv[globArgc][1];
   char *comma_position = strchr(opername, ',');
@@ -436,7 +464,7 @@ getGlobArgc(int argc,  std::vector<char *> &argv, int globArgc)
 }
 
 static int
-skipInputStreams(int argc, std::vector<char*>& argv, int globArgc, int nstreams)
+skipInputStreams(int argc, std::vector<char *> &argv, int globArgc, int nstreams)
 {
   while (nstreams > 0)
     {
@@ -459,7 +487,7 @@ skipInputStreams(int argc, std::vector<char*>& argv, int globArgc, int nstreams)
 }
 
 static int
-getStreamCnt(int argc, std::vector<char *>& argv)
+getStreamCnt(int argc, std::vector<char *> &argv)
 {
   int streamCnt = 0;
   int globArgc = 1;
@@ -479,10 +507,49 @@ getStreamCnt(int argc, std::vector<char *>& argv)
   return streamCnt;
 }
 
-static void
-setStreamNames(int argc, std::vector<char *> &argv)
+/*
+static void setStreamNames(int argc, std::vector<char *> *argv)
+{
+    //check for output of first
+    int current_argv_entry;
+    std::vector<pstream_t*> &current_instreams = root_process->inputStreams;
+    std::vector<pstream_t*> &current_outstreams = root_process->outputStreams;
+
+}
+*/
+void
+process_t::setStreams(int argc, std::vector<char *> &argv)
+{
+  int streamCnt = getStreamCnt(argc, argv);
+
+  nvals = 0;
+  nvars = 0;
+  ntimesteps = 0;
+
+  m_streamCnt = 0; /* filled in setStreamNames */
+  if (streamCnt)
+    streamNames = std::vector<argument_t>(streamCnt);
+  for (int i = 0; i < streamCnt; i++)
+    {
+      streamNames[i].argc = 0;
+      streamNames[i].args = NULL;
+    }
+
+  setStreamNames(argc, argv);
+
+  int status = checkStreamCnt();
+
+  if (status == 0 && streamCnt != streamCnt)
+    Error("Internal problem with stream count %d %d", streamCnt, streamCnt);
+  /*
+  for ( i = 0; i < streamCnt; i++ )
+    fprintf(stderr, "setStreams: stream %d %s\n", i+1, process.streamNames[i].args);
+  */
+}
+
+void
+process_t::setStreamNames(int argc, std::vector<char *> &argv)
 {
-  process_t &process = processSelf();
   int i, ac;
   int globArgc = 1;
   int globArgcStart;
@@ -498,25 +565,34 @@ setStreamNames(int argc, std::vector<char *> &argv)
           globArgc = getGlobArgc(argc, argv, globArgc);
           len = 0;
           for (i = globArgcStart; i < globArgc; i++)
-            len += strlen(argv[i]) + 1;
+            {
+              len += strlen(argv[i]) + 1;
+            }
           streamname = (char *) Calloc(1, len);
           for (i = globArgcStart; i < globArgc; i++)
             {
               strcat(streamname, argv[i]);
               if (i < globArgc - 1)
-                strcat(streamname, " ");
+                {
+                  strcat(streamname, " ");
+                }
             }
           for (i = 1; i < len - 1; i++)
-            if (streamname[i] == '\0')
-              streamname[i] = ' ';
-          process.streamNames[process.streamCnt].args = streamname;
+            {
+              if (streamname[i] == '\0')
+                {
+                  streamname[i] = ' ';
+                }
+            }
+
+          streamNames[m_streamCnt].args = streamname;
           ac = globArgc - globArgcStart;
           // printf("setStreamNames:  ac %d  streamname1: %s\n", ac, streamname);
-          process.streamNames[process.streamCnt].argv.resize(ac);
+          streamNames[m_streamCnt].argv.resize(ac);
           for (i = 0; i < ac; ++i)
-            process.streamNames[process.streamCnt].argv[i] = argv[i + globArgcStart];
-          process.streamNames[process.streamCnt].argc = ac;
-          process.streamCnt++;
+            streamNames[m_streamCnt].argv[i] = argv[i + globArgcStart];
+          streamNames[m_streamCnt].argc = ac;
+          m_streamCnt++;
           // printf("setStreamNames:  streamname1: %s\n", streamname);
         }
       else
@@ -524,13 +600,13 @@ setStreamNames(int argc, std::vector<char *> &argv)
           len = strlen(argv[globArgc]) + 1;
           streamname = (char *) Malloc(len);
           strcpy(streamname, argv[globArgc]);
-          process.streamNames[process.streamCnt].args = streamname;
+          streamNames[m_streamCnt].args = streamname;
           ac = 1;
-          process.streamNames[process.streamCnt].argv.resize(ac);
-          process.streamNames[process.streamCnt].argv[0] = argv[globArgc];
-          process.streamNames[process.streamCnt].argc = ac;
-          process.streamNames[process.streamCnt].args = streamname;
-          process.streamCnt++;
+          streamNames[m_streamCnt].argv.resize(ac);
+          streamNames[m_streamCnt].argv[0] = argv[globArgc];
+          streamNames[m_streamCnt].argc = ac;
+          streamNames[m_streamCnt].args = streamname;
+          m_streamCnt++;
           // printf("setStreamNames:  streamname2: %s\n", streamname);
           globArgc++;
         }
@@ -610,7 +686,7 @@ expand_wildcards(process_t &process, int streamCnt)
       process.streamNames.resize(streamCnt);
 
       // move output streams to the end
-      for (int i = 1; i < process.streamCnt; ++i)
+      for (int i = 1; i < process.m_streamCnt; ++i)
         process.streamNames[i + glob_arg->argc - 1] = process.streamNames[i];
 
       for (int i = 0; i < glob_arg->argc; ++i)
@@ -624,7 +700,7 @@ expand_wildcards(process_t &process, int streamCnt)
             cdoPrint("         >%s<", glob_arg->argv[i]);
         }
 
-      process.streamCnt = streamCnt;
+      process.m_streamCnt = streamCnt;
     }
 
   Free(glob_arg);
@@ -633,7 +709,7 @@ expand_wildcards(process_t &process, int streamCnt)
   return 1;
 }
 
-static int
+int
 checkStreamCnt(void)
 {
   process_t &process = processSelf();
@@ -661,29 +737,29 @@ checkStreamCnt(void)
   // printf(" streamInCnt, streamOutCnt %d %d\n", streamInCnt, streamOutCnt);
   if (streamInCnt == -1)
     {
-      streamInCnt = process.streamCnt - streamOutCnt;
+      streamInCnt = process.m_streamCnt - streamOutCnt;
       if (streamInCnt < 1)
         cdoAbort("Input streams missing!");
     }
 
   if (streamOutCnt == -1)
     {
-      streamOutCnt = process.streamCnt - streamInCnt;
+      streamOutCnt = process.m_streamCnt - streamInCnt;
       if (streamOutCnt < 1)
         cdoAbort("Output streams missing!");
     }
   // printf(" streamInCnt, streamOutCnt %d %d\n", streamInCnt, streamOutCnt);
 
   streamCnt = streamInCnt + streamOutCnt;
-  // printf(" streamCnt %d %d\n", process.streamCnt, streamCnt);
+  // printf(" streamCnt %d %d\n", process.m_streamCnt, streamCnt);
 
-  if (process.streamCnt > streamCnt)
+  if (process.m_streamCnt > streamCnt)
     cdoAbort("Too many streams!"
              " Operator needs %d input and %d output streams.",
              streamInCnt,
              streamOutCnt);
 
-  if (process.streamCnt < streamCnt)
+  if (process.m_streamCnt < streamCnt)
     cdoAbort("Too few streams specified!"
              " Operator needs %d input and %d output streams.",
              streamInCnt,
@@ -712,62 +788,120 @@ checkStreamCnt(void)
   return status;
 }
 
-static void
-setStreams(int argc, std::vector<char *> &argv)
+bool
+process_t::hasAllInputs()
 {
-  process_t &process = processSelf();
-  int streamCnt = getStreamCnt(argc, argv);
+  // std::cout << m_module.streamInCnt << " " << childProcesses.size() + inputStreams.size() << std::endl;
+  return m_module.streamInCnt == (childProcesses.size() + inputStreams.size());
+}
 
-  process.nvals = 0;
-  process.nvars = 0;
-  process.ntimesteps = 0;
+#include <fstream>
+void print_creation_results(std::ofstream &p_outfile)
+{
+ p_outfile << std::endl << "RESULTS:" << std::endl;
+  for (auto &process : Process)
+    {
+      p_outfile << "process: " << process.second.operatorName << " has children: " << std::endl;
+      for (auto child : process.second.childProcesses)
+        {
+          p_outfile << child->m_ID << ", ";
+        }
+      for (auto outstream : process.second.inputStreams)
+        {
+          p_outfile << "S: " << outstream->self << " ";
+        }
+    }
+  p_outfile << std::endl;
 
-  process.streamCnt = 0; /* filled in setStreamNames */
-  if (streamCnt)
-    process.streamNames = std::vector<argument_t>(streamCnt);
-  for (int i = 0; i < streamCnt; i++)
+}
+
+void
+createProcesses(int argc, char **argv)
+{
+  std::ofstream outfile("processCreation.txt");
+
+  for (int i = 0; i < argc; i++)
     {
-      process.streamNames[i].argc = 0;
-      process.streamNames[i].args = NULL;
+      outfile << argv[i] << " ";
     }
+  outfile << std::endl;
 
-  setStreamNames(argc, argv);
+  root_process = processCreate(argv[0]);
 
-  int status = checkStreamCnt();
+  process_t *current_process;
+  process_t *parent_process;
 
-  if (status == 0 && process.streamCnt != streamCnt)
-    Error("Internal problem with stream count %d %d", process.streamCnt, streamCnt);
-  /*
-  for ( i = 0; i < streamCnt; i++ )
-    fprintf(stderr, "setStreams: stream %d %s\n", i+1, process.streamNames[i].args);
-  */
+  int idx = 1;
+  std::stack<process_t *> call_stack;
+
+  call_stack.push(root_process);
+  current_process = call_stack.top();
+  // root_process.addOutputStream();
+  do
+    {
+      outfile << "iteration " << idx << " start" << std::endl
+              << "current argv: " << argv[idx] << "  current_process: " << current_process->operatorName << std::endl;
+      if (argv[idx][0] == '-')
+        {
+          outfile << "found new operator: creating process: ";
+          parent_process = current_process;
+          current_process = processCreate(argv[idx]);
+          parent_process->addChild(current_process);
+          current_process->addParent(parent_process);
+          call_stack.push(current_process);
+          outfile << current_process->operatorName << std::endl;
+        }
+      else
+        {
+          outfile << "added file " << argv[idx] << std::endl;
+          pstream_t *new_pstream = create_pstream();
+          // new_pstream->pstreamOpenReadFile(argv[i]);
+          current_process->inputStreams.push_back(new_pstream);
+        }
+      while (current_process->hasAllInputs() && current_process != root_process)
+        {
+          outfile << "process " << current_process->operatorName << "poped" << std::endl;
+          call_stack.pop();
+          current_process = call_stack.top();
+        }
+      outfile << "iteration " << idx << " end"
+              << "current_process: " << current_process->operatorName << std::endl;
+      idx++;
+    }
+  while ((current_process != root_process || !root_process->hasAllInputs()) && idx < argc - 1);
+
+  print_creation_results(outfile);
+  outfile.close();
 }
 
 void
 processDefArgument(void *vargument)
 {
+  /*
+process_t &process = processSelf();
+char *operatorArg;
+char *commapos;
+std::vector< char*> &oargv = process.oargv;
+*/
   process_t &process = processSelf();
-  char *operatorArg;
-  char *commapos;
   std::vector<char*> &oargv = process.oargv;
-  int argc = ((argument_t *) vargument)->argc;
-  std::vector<char *> &argv = ((argument_t *) vargument)->argv;
+  /*
 
-  process.xoperator = argv[0];
-  process.operatorName = getOperatorName(process.xoperator);
-  process.operatorArg = getOperatorArg(process.xoperator);
+  process.m_operatorCommand = argv[0];
+  process.operatorName = getOperatorName(process.m_operatorCommand);
+  process.operatorArg = getOperatorArg(process.m_operatorCommand);
   operatorArg = process.operatorArg;
 
   if (operatorArg)
     {
-      oargv.push_back(operatorArg);
+      orgv.push_back(operatorArg);
       // fprintf(stderr, "processDefArgument: %d %s\n", oargc, operatorArg);
 
-      commapos = operatorArg;
+      char *commapos = operatorArg;
       while ((commapos = strchr(commapos, ',')) != NULL)
         {
           *commapos = '\0';
-          *commapos++;
+          commapos++;
           if (strlen(commapos))
             {
               oargv.push_back(commapos);
@@ -778,9 +912,7 @@ processDefArgument(void *vargument)
 
   processDefPrompt(process.operatorName);
 
-  process.module = getModule(process.operatorName);
-
-  setStreams(argc, argv);
+*/
 }
 
 void
@@ -1013,22 +1145,21 @@ process_t::print_process()
   std::cout << " nOutStream      : " << nOutStream << std::endl;
   for (int i = 0; i < nInStream; i++)
     {
-      std::cout << "    " << inputStreams[i]->self << std::endl;
+      std::cout << "    " << childProcesses[i]->m_ID << std::endl;
     }
   for (int i = 0; i < nOutStream; i++)
     {
-      std::cout << "    " << outputStreams[i]->self << std::endl;
+      std::cout << "    " << parentProcesses[i]->m_ID << std::endl;
     }
-  if (s_utime)
+  if ( s_utime > 0 )
     {
       std::cout << " s_utime         : " << s_utime << std::endl;
     }
   else
     {
-      std::cout << " s_utime         : "
-                << "UNINITALIZED" << std::endl;
+      std::cout << " s_utime         : " << "UNINITALIZED" << std::endl;
     }
-  if (s_stime)
+  if ( s_stime > 0 )
     {
       std::cout << " s_stime         : " << s_stime << std::endl;
     }
@@ -1073,9 +1204,9 @@ process_t::print_process()
                 << "UNINITALIZED" << std::endl;
     }
   std::cout << " ntimesteps      : " << ntimesteps << std::endl;
-  std::cout << " streamCnt       : " << streamCnt << std::endl;
+  std::cout << " streamCnt       : " << m_streamCnt << std::endl;
   // std::cout << " streamNames     : " << streamNames                  <<  std::endl;
-  std::cout << " xoperator       : " << xoperator << std::endl;
+  std::cout << " m_operatorCommand       : " << m_operatorCommand << std::endl;
   std::cout << " operatorName    : " << operatorName << std::endl;
   std::cout << " operatorArg     : " << operatorArg << std::endl;
   std::cout << " oargc           : " << oargc << std::endl;
@@ -1106,10 +1237,13 @@ processClosePipes(void)
         Message("process %d  stream %d  close streamID %d", processSelf().m_ID, sindex, pstreamptr->self);
 
       if (pstreamptr)
-          pstreamptr->close();
+        pstreamptr->close();
     }
 }
 
+extern "C" {
+size_t getPeakRSS( );
+}
 
 void
 cdoFinish(void)
@@ -1138,7 +1272,7 @@ cdoFinish(void)
       reset_text_color(stderr);
       if (nvals > 0)
         {
-          if (sizeof(int64_t) > sizeof(long))
+          if (sizeof(int64_t) > sizeof(size_t))
 #if defined(_WIN32)
             fprintf(stderr,
                     "Processed %I64d value%s from %d variable%s",
@@ -1152,8 +1286,8 @@ cdoFinish(void)
                     ADD_PLURAL(nvars));
           else
             fprintf(stderr,
-                    "Processed %ld value%s from %d variable%s",
-                    (long) nvals,
+                    "Processed %zu value%s from %d variable%s",
+                    (size_t) nvals,
                     ADD_PLURAL(nvals),
                     nvars,
                     ADD_PLURAL(nvars));
@@ -1197,9 +1331,8 @@ cdoFinish(void)
     {
       int mu[] = { 'b', 'k', 'm', 'g', 't' };
       int muindex = 0;
-      long memmax;
-
-      memmax = memTotal();
+      // size_t memmax = memTotal();
+      size_t memmax = getPeakRSS();
       while (memmax > 9999)
         {
           memmax /= 1024;
@@ -1207,7 +1340,7 @@ cdoFinish(void)
         }
 
       if (memmax)
-        snprintf(memstring, sizeof(memstring), " %ld%c ", memmax, mu[muindex]);
+        snprintf(memstring, sizeof(memstring), " %zu%c", memmax, mu[muindex]);
 
       processEndTime(&p_usertime, &p_systime);
       p_cputime = p_usertime + p_systime;
@@ -1222,11 +1355,11 @@ cdoFinish(void)
 
 #if defined(HAVE_SYS_TIMES_H)
   if (cdoBenchmark)
-    fprintf(stderr, " ( %.2fs %.2fs %.2fs %s)\n", c_usertime, c_systime, c_cputime, memstring);
+    fprintf(stderr, " ( %.2fs %.2fs %.2fs%s )\n", c_usertime, c_systime, c_cputime, memstring);
   else
     {
       if (!cdoSilentMode)
-        fprintf(stderr, " ( %.2fs )\n", c_cputime);
+        fprintf(stderr, " ( %.2fs%s )\n", c_cputime, memstring);
     }
   if (cdoBenchmark && processID == 0)
     fprintf(stderr, "total: user %.2fs  sys %.2fs  cpu %.2fs  mem%s\n", p_usertime, p_systime, p_cputime, memstring);
@@ -1238,3 +1371,23 @@ cdoFinish(void)
 
   processDelete();
 }
+
+void
+process_t::addChild(process_t *childProcess)
+{
+  childProcesses.push_back(childProcess);
+  nchild = childProcesses.size();
+}
+
+void
+process_t::addParent(process_t *parentProcess)
+{
+  parentProcesses.push_back(parentProcess);
+}
+void
+clearProcesses()
+{
+  Process.clear();
+  NumProcess = 0;
+  NumProcessActive = 0;
+}
diff --git a/src/process.h b/src/process.h
index 509ae2f..8ac08a1 100644
--- a/src/process.h
+++ b/src/process.h
@@ -18,7 +18,6 @@
 #ifndef _PROCESS_H
 #define _PROCESS_H
 
-#include <sys/types.h> /* off_t */
 #include <vector>
 #include "util.h"
 #include "pstream.h"
@@ -27,73 +26,85 @@
 #include <vector>
 #include <iostream>
 
-constexpr int MAX_PROCESS  =   128;
-constexpr int MAX_STREAM   =    64;
-constexpr int MAX_OPERATOR =   128;
-constexpr int MAX_OARGC    =  4096;
-constexpr int MAX_FILES    = 65536;
+constexpr int MAX_PROCESS = 128;
+constexpr int MAX_STREAM = 64;
+constexpr int MAX_OPERATOR = 128;
+constexpr int MAX_OARGC = 4096;
+constexpr int MAX_FILES = 65536;
 
-
-typedef struct {
-  int         f1;
-  int         f2;
+typedef struct
+{
+  int f1;
+  int f2;
   const char *name;
   const char *enter;
-}
-oper_t;
+} oper_t;
 
-class process_t {
-    public:
-   int m_ID;
+class process_t
+{
+public:
+  int m_ID;
 #if defined(HAVE_LIBPTHREAD)
-  pthread_t   threadID;
-  int         l_threadID;
+  pthread_t threadID;
+  int l_threadID;
 #endif
-  short       nchild;
-  std::vector<pstream_t*>       inputStreams;
-  std::vector<pstream_t*>       outputStreams;
-  double      s_utime;
-  double      s_stime;
-  double      a_utime;
-  double      a_stime;
-  double      cputime;
-
-  off_t       nvals;
-  short       nvars;
-  int         ntimesteps;
-  short       streamCnt;
+  short nchild;
+  std::vector<process_t *> childProcesses;
+  std::vector<process_t *> parentProcesses;
+  std::vector<pstream_t *> inputStreams;
+  std::vector<pstream_t *> outputStreams;
+  double s_utime;
+  double s_stime;
+  double a_utime;
+  double a_stime;
+  double cputime;
+
+  size_t nvals;
+  short nvars;
+  int ntimesteps;
+  short m_streamCnt;
   std::vector<argument_t> streamNames;
-  char       *xoperator;
+  char *m_operatorCommand;
   const char *operatorName;
-  char       *operatorArg;
-  int         oargc;
+  char *operatorArg;
+  int oargc;
   std::vector<char *> oargv;
-  char        prompt[64];
-  short       noper;
-  oper_t      oper[MAX_OPERATOR];
+  char prompt[64];
+  short noper;
+  oper_t oper[MAX_OPERATOR];
 
-  modules_t module;
+  modules_t m_module;
 
   int getInStreamCnt();
   int getOutStreamCnt();
   void initProcess();
   void print_process();
-  process_t(int ID);
- private: 
+  void defArgument();
+  process_t(int p_ID, char *operatorCommand);
+  void setOperatorArgv(char *operatorArguments);
+  void setStreams(int argc, std::vector<char *> &argv);
+  void addChild(process_t *child_process);
+  void addParent(process_t *parent_process);
+  bool hasAllInputs();
+
+private:
+  void defPrompt();
   process_t();
   void OpenRead(int p_input_idx);
   void OpenWrite(int p_input_idx);
   void OpenAppend(int p_input_idx);
+  void setStreamNames(int argc, std::vector<char *> &argv);
 };
 
-  pstream_t*  processInqInputStream(int streamindex);
-  pstream_t*  processInqOutputStream(int streamindex);
-  process_t&  processSelf(void);
-int  processCreate(void);
+pstream_t *processInqInputStream(int streamindex);
+pstream_t *processInqOutputStream(int streamindex);
+process_t &processSelf(void);
+process_t *processCreate(void);
+process_t *processCreate(char *command);
 void processDelete(void);
-int  processInqTimesteps(void);
+int processInqTimesteps(void);
 void processDefTimesteps(int streamID);
-int  processInqVarNum(void);
+int processInqVarNum(void);
 int processInqInputStreamNum(void);
 int processInqOutputStreamNum(void);
 void processAddInputStream(pstream_t *p_pstream_ptr);
@@ -109,11 +120,11 @@ void processAccuTime(double utime, double stime);
 void processDefCputime(int processID, double cputime);
 double processInqCputime(int processID);
 
-void processAddNvals(off_t nvals);
-off_t processInqNvals(int processID);
+void processAddNvals(size_t nvals);
+size_t processInqNvals(int processID);
 int processNums(void);
 
-int  processInqChildNum(void);
+int processInqChildNum(void);
 
 const char *processOperatorArg(void);
 const char *processInqOpername(void);
@@ -121,5 +132,8 @@ const char *processInqOpername2(int processID);
 const char *processInqPrompt(void);
 
 const argument_t *cdoStreamName(int cnt);
+int checkStreamCnt();
+void createProcesses(int argc, char **argv);
+void clearProcesses();
 
-#endif  /* _PROCESS_H */
+#endif /* _PROCESS_H */
diff --git a/src/pstream.cc b/src/pstream.cc
index f297795..db17a6d 100644
--- a/src/pstream.cc
+++ b/src/pstream.cc
@@ -16,12 +16,13 @@
 */
 
 
-#include <thread>
-#if defined(HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#if defined(_OPENMP)
+#include <thread>
+
+#ifdef  _OPENMP
 #include <omp.h>
 #endif
 
@@ -43,8 +44,8 @@ int pclose(FILE *stream);
 #include "util.h"
 #include "pipe.h"
 #include "error.h"
+#include "cdoDebugOutput.h"
 
-static int PSTREAM_Debug = 0;
 
 //#define MAX_PSTREAMS 4096
 
@@ -135,7 +136,7 @@ pstream_init_pointer(void)
 }
 */
 
-static pstream_t *create_pstream()
+ pstream_t *create_pstream()
 {
     PSTREAM_LOCK();
     auto new_entry  = _pstream_map.insert(
@@ -200,7 +201,7 @@ pstream_from_pointer(pstream_t *ptr)
           idx = newptr->idx;
           newptr->ptr = ptr;
 
-          if (PSTREAM_Debug)
+          if (CdoDebug::PSTREAM)
             Message("Pointer %p has idx %d from pstream list", ptr, idx);
         }
       else
@@ -252,8 +253,8 @@ pstream_delete_entry(pstream_t *pstreamptr)
 
   PSTREAM_UNLOCK();
 
-  if (PSTREAM_Debug)
-    Message("Removed idx %d from pstream list", idx);
+  if (CdoDebug::PSTREAM)
+    MESSAGE("Removed idx ", idx," from pstream list");
 }
 /*
 static void
@@ -266,13 +267,13 @@ pstream_initialize(void)
 
   char *env = getenv("PSTREAM_DEBUG");
   if (env)
-    PSTREAM_Debug = atoi(env);
+    CdoDebug::PSTREAM = atoi(env);
 
   env = getenv("PSTREAM_MAX");
   if (env)
     _pstream_max = atoi(env);
 
-  if (PSTREAM_Debug)
+  if (CdoDebug::PSTREAM)
     Message("PSTREAM_MAX = %d", _pstream_max);
 
   pstream_list_new();
@@ -384,8 +385,8 @@ pstream_t::pstreamOpenReadPipe(const char *pipename)
 
     /* Free(operatorName); */
   /*      pipeInqInfo(pstreamID); */
-  if (PSTREAM_Debug)
-    Message("pipe %s", pipename);
+  if (CdoDebug::PSTREAM)
+    MESSAGE("pipe ", pipename, " %s");
 #else
   cdoAbort("Cannot use pipes, pthread support not compiled in!");
 #endif
@@ -533,8 +534,8 @@ pstream_t::pstreamOpenReadFile(const char* p_args)
      filename = std::string(p_args);
     }
 
-  if (PSTREAM_Debug)
-    Message("file %s", filename.c_str());
+  if (CdoDebug::PSTREAM)
+    MESSAGE("file ", filename.c_str());
 
 #if defined(HAVE_LIBPTHREAD)
   if (cdoLockIO)
@@ -577,6 +578,11 @@ void createPipeName(char *pipename, int pnlen)
 int
 pstreamOpenRead(const argument_t *argument)
 {
+  if(CdoDebug::PSTREAM)
+  {
+      MESSAGE("Opening new pstream for reading with argument:");
+      MESSAGE(print_argument((argument_t*)argument));
+  }
 
   pstream_t *pstreamptr = create_pstream();
   if (!pstreamptr)
@@ -680,9 +686,9 @@ pstreamOpenWritePipe(const argument_t *argument, int filetype)
   int pstreamID = -1;
 
 #if defined(HAVE_LIBPTHREAD)
-  if (PSTREAM_Debug)
+  if (CdoDebug::PSTREAM)
     {
-      Message("pipe %s", argument->args);
+      MESSAGE("pipe ", argument->args);
     }
   pstreamID = pstreamFindID(argument->args);
   if (pstreamID == -1)
@@ -746,8 +752,8 @@ pstreamOpenWriteFile(const argument_t *argument, int filetype)
 
   int pstreamID = pstreamptr->self;
 
-  if (PSTREAM_Debug)
-    Message("file %s", argument->args);
+  if (CdoDebug::PSTREAM)
+    MESSAGE("file ", argument->args);
 
   if (filetype == CDI_UNDEFID)
     filetype = CDI_FILETYPE_GRB;
@@ -834,9 +840,9 @@ pstreamOpenAppend(const argument_t *argument)
 
   if (ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("pipe %s", argument->args);
+          MESSAGE("pipe ", argument->args);
         }
       cdoAbort("this operator doesn't work with pipes!");
     }
@@ -844,10 +850,10 @@ pstreamOpenAppend(const argument_t *argument)
   pstream_t *pstreamptr = create_pstream();
 
   if (!pstreamptr)
-    Error("No memory");
+    ERROR("No memory");
 
-  if (PSTREAM_Debug)
-    Message("file %s", argument->args);
+  if (CdoDebug::PSTREAM)
+    MESSAGE("file ", argument->args);
 
   pstreamptr->openAppend(argument->args);
 
@@ -908,8 +914,8 @@ pstreamCloseChildStream(pstream_t *pstreamptr)
   pipe_t *pipe = pstreamptr->pipe;
   pthread_mutex_lock(pipe->m_mutex);
   pipe->EOP = true;
-  if (PSTREAM_Debug)
-    Message("%s read closed", pstreamptr->m_name.c_str());
+  if (CdoDebug::PSTREAM)
+    MESSAGE(pstreamptr->m_name.c_str(), " read closed");
   pthread_mutex_unlock(pipe->m_mutex);
   pthread_cond_signal(pipe->tsDef);
   pthread_cond_signal(pipe->tsInq);
@@ -942,8 +948,8 @@ pstreamCloseParentStream(pstream_t *pstreamptr)
   pipe_t *pipe = pstreamptr->pipe;
   pthread_mutex_lock(pipe->m_mutex);
   pipe->EOP = true;
-  if (PSTREAM_Debug)
-    Message("%s write closed", pstreamptr->m_name.c_str());
+  if (CdoDebug::PSTREAM)
+    MESSAGE(pstreamptr->m_name.c_str(), " write closed");
   pthread_mutex_unlock(pipe->m_mutex);
   pthread_cond_signal(pipe->tsDef);
   pthread_cond_signal(pipe->tsInq);
@@ -951,8 +957,8 @@ pstreamCloseParentStream(pstream_t *pstreamptr)
   std::unique_lock<std::mutex> locked_mutex(pipe->m_mutex);
   while (pstreamptr->isopen)
     {
-      if (PSTREAM_Debug)
-        Message("wait of read close");
+      if (CdoDebug::PSTREAM)
+        MESSAGE("wait of read close");
       pthread_cond_wait(pipe->isclosed, locked_mutex);
     }
   locked_mutex.unlock();
@@ -964,7 +970,7 @@ pstreamClose(int pstreamID)
   pstream_t *pstreamptr = pstream_to_pointer(pstreamID);
 
   if (pstreamptr == NULL)
-    Error("Internal problem, stream %d not open!", pstreamID);
+    ERROR("Internal problem, stream ", pstreamID ," not open!");
 
   pstreamptr->close();
 
@@ -985,7 +991,7 @@ void pstream_t::close(){
       else if (pthread_equal(threadID, wthreadID))
         pstreamCloseParentStream(this);
       else
-        Error("Internal problem! Close pipe %s", m_name.c_str());
+        Error("Internal problem! Close pipe ", m_name.c_str());
 
      // processDelStream(pstreamID);
 #else
@@ -994,8 +1000,8 @@ void pstream_t::close(){
     }
   else
     {
-      if (PSTREAM_Debug)
-        Message("%s fileID %d", m_name.c_str(), m_fileID);
+      if (CdoDebug::PSTREAM)
+        MESSAGE(m_name.c_str(), " fileID ", m_fileID);
 
       if (mode == 'r')
         {
@@ -1170,8 +1176,8 @@ void pstream_t::defVlist(int p_vlistID){
 #if defined(HAVE_LIBPTHREAD)
   if (ispipe)
     {
-      if (PSTREAM_Debug)
-        Message("%s pstreamID %d", m_name.c_str(), self);
+      if (CdoDebug::PSTREAM)
+       MESSAGE(m_name.c_str()," pstreamID ",  self);
       int vlistIDcp = vlistDuplicate(p_vlistID);
       /*    pipeDefVlist(pstreamptr, p_vlistID);*/
       pipe->pipeDefVlist(m_vlistID, vlistIDcp);
@@ -1245,9 +1251,9 @@ pstreamInqRecord(int pstreamID, int *varID, int *levelID)
 #if defined(HAVE_LIBPTHREAD)
   if (pstreamptr->ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pstreamptr->pipe->name.c_str(), pstreamptr->self);
+          MESSAGE( pstreamptr->pipe->name.c_str()," pstreamID ", pstreamptr->self);
         }
       pstreamptr->pipe->pipeInqRecord(varID, levelID);
     }
@@ -1286,9 +1292,9 @@ pstreamDefRecord(int pstreamID, int varID, int levelID)
   if (pstreamptr->ispipe)
     {
 
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamid %d", pstreamptr->m_name.c_str(), pstreamptr->self);
+          MESSAGE( pstreamptr->m_name.c_str()," pstreamid ", pstreamptr->self);
         }
       pstreamptr->pipe->pipeDefRecord(varID, levelID);
     }
@@ -1312,7 +1318,7 @@ pstreamDefRecord(int pstreamID, int varID, int levelID)
 }
 
 void
-pstreamReadRecord(int pstreamID, double *data, int *nmiss)
+pstreamReadRecord(int pstreamID, double *data, size_t *nmiss)
 {
   if (data == NULL)
     cdoAbort("Data pointer not allocated (pstreamReadRecord)!");
@@ -1322,9 +1328,9 @@ pstreamReadRecord(int pstreamID, double *data, int *nmiss)
 #if defined(HAVE_LIBPTHREAD)
   if (pstreamptr->ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pstreamptr->pipe->name.c_str(), pstreamptr->self);
+          MESSAGE( pstreamptr->pipe->name.c_str()," pstreamID ", pstreamptr->self);
         }
       pstreamptr->pipe->pipeReadRecord(pstreamptr->m_vlistID, data, nmiss);
     }
@@ -1348,7 +1354,7 @@ pstreamReadRecord(int pstreamID, double *data, int *nmiss)
 }
 
 void
-pstreamReadRecordF(int pstreamID, float *data, int *nmiss)
+pstreamReadRecordF(int pstreamID, float *data, size_t *nmiss)
 {
   if (data == NULL)
     cdoAbort("Data pointer not allocated (pstreamReadRecord)!");
@@ -1381,7 +1387,7 @@ pstreamReadRecordF(int pstreamID, float *data, int *nmiss)
 }
 
 void
-pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, int nmiss)
+pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, size_t nmiss)
 {
   long i;
   long gridsize = pstreamptr->m_varlist[varID].gridsize;
@@ -1457,7 +1463,7 @@ pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, int nmiss
 }
 
 void
-pstreamWriteRecord(int pstreamID, double *data, int nmiss)
+pstreamWriteRecord(int pstreamID, double *data, size_t nmiss)
 {
   if (data == NULL)
     cdoAbort("Data pointer not allocated (%s)!", __func__);
@@ -1467,9 +1473,9 @@ pstreamWriteRecord(int pstreamID, double *data, int nmiss)
 #if defined(HAVE_LIBPTHREAD)
   if (pstreamptr->ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pstreamptr->pipe->name.c_str(), pstreamptr->self);
+          MESSAGE(pstreamptr->pipe->name.c_str()," pstreamID ", pstreamptr->self);
         }
       pstreamptr->pipe->pipeWriteRecord(data, nmiss);
     }
@@ -1500,7 +1506,7 @@ pstreamWriteRecord(int pstreamID, double *data, int nmiss)
 }
 
 void
-pstreamWriteRecordF(int pstreamID, float *data, int nmiss)
+pstreamWriteRecordF(int pstreamID, float *data, size_t nmiss)
 {
   if (data == NULL)
     cdoAbort("Data pointer not allocated (%s)!", __func__);
@@ -1511,9 +1517,9 @@ pstreamWriteRecordF(int pstreamID, float *data, int nmiss)
   if (pstreamptr->ispipe)
     {
       cdoAbort("pipeWriteRecord not implemented for memtype float!");
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pstreamptr->pipe->name.c_str(), pstreamptr->self);
+          MESSAGE( pstreamptr->pipe->name.c_str()," pstreamID ", pstreamptr->self);
         }
       // pipeWriteRecord(pstreamptr, data, nmiss);
     }
@@ -1552,9 +1558,9 @@ pstreamInqTimestep(int pstreamID, int tsID)
 #if defined(HAVE_LIBPTHREAD)
   if (pstreamptr->ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pstreamptr->pipe->name.c_str(), pstreamptr->self);
+          MESSAGE(pstreamptr->pipe->name.c_str(), " pstreamID ",  pstreamptr->self);
         }
       nrecs = pstreamptr->pipe->pipeInqTimestep(tsID);
     }
@@ -1664,9 +1670,9 @@ pstream_t::defTimestep(int p_tsID)
 #if defined(HAVE_LIBPTHREAD)
   if (ispipe)
     {
-      if (PSTREAM_Debug)
+      if (CdoDebug::PSTREAM)
         {
-          Message("%s pstreamID %d", pipe->name.c_str(), self);
+          MESSAGE(pipe->name.c_str()," pstreamID ", self);
         }
       pipe->pipeDefTimestep(m_vlistID, p_tsID);
     }
@@ -1702,8 +1708,8 @@ pstream_t::defTimestep(int p_tsID)
 void
 pstreamCopyRecord(int pstreamIDdest, int pstreamIDsrc)
 {
-  if (PSTREAM_Debug)
-    Message("pstreamIDdest = %d  pstreamIDsrc = %d", pstreamIDdest, pstreamIDsrc);
+  if (CdoDebug::PSTREAM)
+    MESSAGE("pstreamIDdest = ",pstreamIDdest,"  pstreamIDsrc = ", pstreamIDsrc);
 
   pstream_t *pstreamptr_dest = pstream_to_pointer(pstreamIDdest);
   pstream_t *pstreamptr_src = pstream_to_pointer(pstreamIDsrc);
@@ -1725,24 +1731,26 @@ pstreamCopyRecord(int pstreamIDdest, int pstreamIDsrc)
 void
 pstreamDebug(int debug)
 {
-  PSTREAM_Debug = debug;
+  CdoDebug::PSTREAM = debug;
 }
 
 void
 cdoInitialize(void *argument)
 {
+    argument_t* argu = (argument_t *)argument;
 #if defined(_OPENMP)
   omp_set_num_threads(ompNumThreads); /* Have to be called for every module (pthread)! */
 #endif
 
-  processCreate();
+  process_t* process = processCreate(argu->argv[0]);
+  process->setStreams(argu->argc, argu->argv);
+
 
 #if defined(HAVE_LIBPTHREAD)
-  if (PSTREAM_Debug)
-    Message("process %d  thread %ld", processSelf().m_ID, pthread_self());
+  if (CdoDebug::PSTREAM)
+    MESSAGE("process ", processSelf().m_ID," thread ", pthread_self());
 #endif
 
-  processDefArgument(argument);
 }
 
 void
@@ -1752,8 +1760,8 @@ pstreamCloseAll()
     {
       if ( pstream_iter.second.m_fileID != CDI_UNDEFID )
         {
-          if (PSTREAM_Debug)
-            Message("Close file %s id %d", pstream_iter.second.m_name.c_str(), pstream_iter.second.m_fileID);
+          if (CdoDebug::PSTREAM)
+            MESSAGE("Close file ", pstream_iter.second.m_name," id ", pstream_iter.second.m_fileID);
           streamClose(pstream_iter.second.m_fileID);
         }
     }
@@ -1772,7 +1780,7 @@ pstreamCloseAll(void)
         {
           if (!pstreamptr->ispipe && pstreamptr->m_fileID != CDI_UNDEFID)
             {
-              if (PSTREAM_Debug)
+              if (CdoDebug::PSTREAM)
                 Message("Close file %s id %d", pstreamptr->m_name.c_str(), pstreamptr->m_fileID);
               streamClose(pstreamptr->m_fileID);
             }
diff --git a/src/pstream.h b/src/pstream.h
index ab7bbec..9f727d8 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -18,6 +18,10 @@
 #ifndef PSTREAM_H
 #define PSTREAM_H
 
+#ifdef  HAVE_CONFIG_H
+#include "config.h" /* _FILE_OFFSET_BITS influence off_t */
+#endif
+
 #include "pstream_write.h"
 #include "varlist.h"
 #include "argument.h"
@@ -81,8 +85,8 @@ int pstreamInqTimestep(int pstreamID, int tsID);
 
 int pstreamInqRecord(int pstreamID, int *varID, int *levelID);
 
-void pstreamReadRecord(int pstreamID, double *data, int *nmiss);
-void pstreamReadRecordF(int pstreamID, float *data, int *nmiss);
+void pstreamReadRecord(int pstreamID, double *data, size_t *nmiss);
+void pstreamReadRecordF(int pstreamID, float *data, size_t *nmiss);
 void pstreamCopyRecord(int pstreamIDdest, int pstreamIDsrc);
 
 void pstreamInqGRIBinfo(int pstreamID, int *intnum, float *fltnum, off_t *bignum);
@@ -92,5 +96,6 @@ int pstreamFileID(int pstreamID);
 void cdoVlistCopyFlag(int vlistID2, int vlistID1);
 
 const int &getPthreadScope();
+pstream_t *create_pstream();
 
 #endif /* PSTREAM_H */
diff --git a/src/pstream_write.h b/src/pstream_write.h
index f55a2bc..78c13f9 100644
--- a/src/pstream_write.h
+++ b/src/pstream_write.h
@@ -28,7 +28,7 @@ void    pstreamDefTimestep(int pstreamID, int tsID);
 
 void    pstreamDefRecord(int pstreamID, int  varID, int  levelID);
 
-void    pstreamWriteRecord(int pstreamID, double *data, int nmiss);
-void    pstreamWriteRecordF(int pstreamID, float *data, int nmiss);
+void    pstreamWriteRecord(int pstreamID, double *data, size_t nmiss);
+void    pstreamWriteRecordF(int pstreamID, float *data, size_t nmiss);
 
 #endif  /* PSTREAM_WRITE_H */
diff --git a/src/remap.h b/src/remap.h
index 582217b..cc80312 100644
--- a/src/remap.h
+++ b/src/remap.h
@@ -1,6 +1,7 @@
-#ifndef _REMAP_H
-#define _REMAP_H
+#ifndef  REMAP_H
+#define  REMAP_H
 
+#include <stdint.h>
 #include <math.h>
 
 #ifndef  M_PI
@@ -86,7 +87,7 @@ typedef struct {
   bool     non_global;
   bool     is_cyclic;
 
-  int      dims[2];               /* size of grid dimension */
+  size_t   dims[2];               /* size of grid dimension */
 
   int      nvgp;                  /* size of vgpm           */
   int*     vgpm;                  /* flag which cells are valid   */
@@ -151,7 +152,7 @@ typedef struct {
   int      nused;
   int      gridID;
   size_t   gridsize;
-  int      nmiss;
+  size_t   nmiss;
   remapgrid_t src_grid;
   remapgrid_t tgt_grid;
   remapvars_t vars;
@@ -197,7 +198,7 @@ void remap_distwgt(size_t num_neighbors, remapgrid_t *src_grid, remapgrid_t *tgt
 void remap_conserv(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const double *restrict src_array, double *restrict tgt_array, double missval);
 
 
-void resize_remap_vars(remapvars_t *rv, int increment);
+void resize_remap_vars(remapvars_t *rv, int64_t increment);
 
 void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, remapvars_t rv, const double *restrict array1, 
 		const double *restrict array2, double missval);
@@ -222,11 +223,11 @@ int grid_search_reg2d_nn(size_t nx, size_t ny, size_t *restrict nbr_add, double
                          const double *restrict src_center_lat, const double *restrict src_center_lon);
 
 int grid_search_reg2d(remapgrid_t *src_grid, size_t *restrict src_add, double *restrict src_lats, 
-                      double *restrict src_lons,  double plat, double plon, const int *restrict src_grid_dims,
+                      double *restrict src_lons,  double plat, double plon, const size_t *restrict src_grid_dims,
                       const double *restrict src_center_lat, const double *restrict src_center_lon);
 
 int grid_search(remapgrid_t *src_grid, size_t *restrict src_add, double *restrict src_lats, 
-		double *restrict src_lons,  double plat, double plon, const int *restrict src_grid_dims,
+		double *restrict src_lons,  double plat, double plon, const size_t *restrict src_grid_dims,
 		const double *restrict src_center_lat, const double *restrict src_center_lon,
 		const restr_t *restrict src_grid_bound_box, const size_t *restrict src_bin_add);
 
@@ -238,4 +239,4 @@ void remapgrid_get_lonlat(remapgrid_t *grid, size_t cell_add, double *plon, doub
 void remapCheckArea(size_t grid_size, double *restrict cell_area, const char *name);
 void remapCheckWeights(size_t num_links, size_t num_wts, int norm_opt, size_t *src_cell_add, size_t *tgt_cell_add, double *wts);
 
-#endif  /* _REMAP_H */
+#endif  /* REMAP_H */
diff --git a/src/remap_bicubic_scrip.cc b/src/remap_bicubic_scrip.cc
index b793129..e6c3f11 100644
--- a/src/remap_bicubic_scrip.cc
+++ b/src/remap_bicubic_scrip.cc
@@ -32,12 +32,12 @@ void set_bicubic_weights(double iw, double jw, double wgts[4][4])
   wgts[3][3] =     iw*(iw-1.)*(iw-1.) *     jw*jw*(jw-1.);
 }
 
-int num_src_points(const int* restrict mask, const size_t src_add[4], double src_lats[4]);
+unsigned num_src_points(const int* restrict mask, const size_t src_add[4], double src_lats[4]);
 
 static
 void renormalize_weights(const double src_lats[4], double wgts[4][4])
 {
-  int n;
+  unsigned n;
   double sum_wgts = 0.0; /* sum of weights for normalization */
   /* 2012-05-08 Uwe Schulzweida: using absolute value of src_lats (bug fix) */
   for ( n = 0; n < 4; ++n ) sum_wgts  += fabs(src_lats[n]);
@@ -50,11 +50,11 @@ void renormalize_weights(const double src_lats[4], double wgts[4][4])
 static
 void bicubic_warning(void)
 {
-  static int lwarn = TRUE;
+  static bool lwarn = true;
 
   if ( cdoVerbose || lwarn )
     {
-      lwarn = FALSE;
+      lwarn = false;
       // cdoWarning("Iteration for iw,jw exceed max iteration count of %d!", remap_max_iter);
       cdoWarning("Bicubic interpolation failed for some grid points - used a distance-weighted average instead!");
     }
@@ -65,7 +65,7 @@ void bicubic_remap(double* restrict tgt_point, const double* restrict src_array,
 		   const double* restrict grad1, const double* restrict grad2, const double* restrict grad3)
 {
   *tgt_point = 0.;
-  for ( int n = 0; n < 4; ++n )
+  for ( unsigned n = 0; n < 4; ++n )
     *tgt_point += src_array[src_add[n]]*wgts[n][0] +
                       grad1[src_add[n]]*wgts[n][1] +
                       grad2[src_add[n]]*wgts[n][2] +
@@ -81,13 +81,6 @@ void bicubic_remap(double* restrict tgt_point, const double* restrict src_array,
 */
 void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapvars_t *rv)
 {
-  /*   Local variables */
-  int  search_result;
-  size_t src_add[4];   /*  address for the four source points     */
-  double src_lats[4];  /*  latitudes  of four bilinear corners    */
-  double src_lons[4];  /*  longitudes of four bilinear corners    */
-  double wgts[4][4];   /*  bicubic weights for four corners       */
-  double plat, plon;   /*  lat/lon coords of destination point    */
   extern int timer_remap_bic;
   int remap_grid_type = src_grid->remap_grid_type;
 
@@ -102,7 +95,7 @@ void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
   if ( src_grid->rank != 2 )
     cdoAbort("Can not do bicubic interpolation when source grid rank != 2"); 
 
-  long tgt_grid_size = tgt_grid->size;
+  size_t tgt_grid_size = tgt_grid->size;
 
   weightlinks4_t *weightlinks = (weightlinks4_t *) Malloc(tgt_grid_size*sizeof(weightlinks4_t));
   weightlinks[0].addweights = (addweight4_t *) Malloc(4*tgt_grid_size*sizeof(addweight4_t));
@@ -115,10 +108,9 @@ void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) \
-  shared(weightlinks, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, rv, findex) \
-  private(src_add, src_lats, src_lons, wgts, plat, plon, search_result)
+  shared(weightlinks, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, rv, findex)
 #endif
-  for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
+  for ( size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     {
 #if defined(_OPENMP)
 #include "pragma_omp_atomic_update.h"
@@ -130,10 +122,16 @@ void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 
       if ( ! tgt_grid->mask[tgt_cell_add] ) continue;
 
-      plat = tgt_grid->cell_center_lat[tgt_cell_add];
-      plon = tgt_grid->cell_center_lon[tgt_cell_add];
+      double plat = tgt_grid->cell_center_lat[tgt_cell_add];
+      double plon = tgt_grid->cell_center_lon[tgt_cell_add];
+
+      size_t src_add[4];   //  address for the four source points
+      double src_lats[4];  //  latitudes  of four bilinear corners
+      double src_lons[4];  //  longitudes of four bilinear corners
+      double wgts[4][4];   //  bicubic weights for four corners
 
       /* Find nearest square of grid points on source grid  */
+      int search_result;
       if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
 	search_result = grid_search_reg2d(src_grid, src_add, src_lats, src_lons, 
 					  plat, plon, src_grid->dims,
@@ -147,17 +145,16 @@ void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
       /* Check to see if points are land points */
       if ( search_result > 0 )
 	{
-	  for ( int n = 0; n < 4; ++n )
+	  for ( unsigned n = 0; n < 4; ++n )
 	    if ( ! src_grid->mask[src_add[n]] ) search_result = 0;
 	}
 
       /* If point found, find local iw,jw coordinates for weights  */
       if ( search_result > 0 )
 	{
-	  double iw, jw;  /*  current guess for bilinear coordinate  */
-
           tgt_grid->cell_frac[tgt_cell_add] = 1.;
 
+	  double iw, jw;  /*  current guess for bilinear coordinate  */
           if ( find_ij_weights(plon, plat, src_lats, src_lons, &iw, &jw) )
 	    {
 	      /* Successfully found iw,jw - compute weights */
@@ -207,20 +204,13 @@ void scrip_remap_bicubic_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, r
 */
 void scrip_remap_bicubic(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const double* restrict src_array, double* restrict tgt_array, double missval)
 {
-  /*   Local variables */
-  int  search_result;
-  size_t src_add[4];      /*  address for the four source points   */
-  double src_lats[4];  /*  latitudes  of four bilinear corners  */
-  double src_lons[4];  /*  longitudes of four bilinear corners  */
-  double wgts[4][4];   /*  bicubic weights for four corners     */
-  double plat, plon;   /*  lat/lon coords of destination point  */
   int remap_grid_type = src_grid->remap_grid_type;
 
   if ( cdoVerbose ) cdoPrint("Called %s()", __func__);
 
   progressInit();
 
-  long tgt_grid_size = tgt_grid->size;
+  size_t tgt_grid_size = tgt_grid->size;
 
   /* Compute mappings from source to target grid */
 
@@ -239,10 +229,9 @@ void scrip_remap_bicubic(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const dou
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) \
-  shared(remap_grid_type, tgt_grid_size, src_grid, tgt_grid, src_array, tgt_array, missval, grad1_lat, grad1_lon, grad1_latlon, findex) \
-  private(src_add, src_lats, src_lons, wgts, plat, plon, search_result)
+  shared(remap_grid_type, tgt_grid_size, src_grid, tgt_grid, src_array, tgt_array, missval, grad1_lat, grad1_lon, grad1_latlon, findex)
 #endif
-  for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
+  for ( size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     {
 #if defined(_OPENMP)
 #include "pragma_omp_atomic_update.h"
@@ -254,10 +243,16 @@ void scrip_remap_bicubic(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const dou
 
       if ( ! tgt_grid->mask[tgt_cell_add] ) continue;
 
-      plat = tgt_grid->cell_center_lat[tgt_cell_add];
-      plon = tgt_grid->cell_center_lon[tgt_cell_add];
+      double plat = tgt_grid->cell_center_lat[tgt_cell_add];
+      double plon = tgt_grid->cell_center_lon[tgt_cell_add];
+
+      size_t src_add[4];   //  address for the four source points
+      double src_lats[4];  //  latitudes  of four bilinear corners
+      double src_lons[4];  //  longitudes of four bilinear corners
+      double wgts[4][4];   //  bicubic weights for four corners
 
       /* Find nearest square of grid points on source grid  */
+      int search_result;
       if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
 	search_result = grid_search_reg2d(src_grid, src_add, src_lats, src_lons, 
 					  plat, plon, src_grid->dims,
@@ -271,17 +266,16 @@ void scrip_remap_bicubic(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const dou
       /* Check to see if points are land points */
       if ( search_result > 0 )
 	{
-	  for ( int n = 0; n < 4; ++n )
+	  for ( unsigned n = 0; n < 4; ++n )
 	    if ( ! src_grid->mask[src_add[n]] ) search_result = 0;
 	}
 
       /* If point found, find local iw,jw coordinates for weights  */
       if ( search_result > 0 )
 	{
-	  double iw, jw;  /*  current guess for bilinear coordinate  */
-
           tgt_grid->cell_frac[tgt_cell_add] = 1.;
 
+	  double iw, jw;  /*  current guess for bilinear coordinate  */
           if ( find_ij_weights(plon, plat, src_lats, src_lons, &iw, &jw) )
 	    {
 	      /* Successfully found iw,jw - compute weights */
diff --git a/src/remap_bilinear_scrip.cc b/src/remap_bilinear_scrip.cc
index a87649e..a8cfd9a 100644
--- a/src/remap_bilinear_scrip.cc
+++ b/src/remap_bilinear_scrip.cc
@@ -92,11 +92,11 @@ void set_bilinear_weights(double iw, double jw, double wgts[4])
 }
 
 
-int num_src_points(const int* restrict mask, const size_t src_add[4], double src_lats[4])
+unsigned num_src_points(const int* restrict mask, const size_t src_add[4], double src_lats[4])
 {
-  int icount = 0;
+  unsigned icount = 0;
 
-  for ( int n = 0; n < 4; ++n )
+  for ( unsigned n = 0; n < 4; ++n )
     {
       if ( mask[src_add[n]] )
 	icount++;
@@ -112,8 +112,8 @@ void renormalize_weights(const double src_lats[4], double wgts[4])
 {
   double sum_wgts = 0.0; /* sum of weights for normalization */
   /* 2012-05-08 Uwe Schulzweida: using absolute value of src_lats (bug fix) */
-  for ( int n = 0; n < 4; ++n ) sum_wgts += fabs(src_lats[n]);
-  for ( int n = 0; n < 4; ++n ) wgts[n] = fabs(src_lats[n])/sum_wgts;
+  for ( unsigned n = 0; n < 4; ++n ) sum_wgts += fabs(src_lats[n]);
+  for ( unsigned n = 0; n < 4; ++n ) wgts[n] = fabs(src_lats[n])/sum_wgts;
 }
 
 static
@@ -148,7 +148,7 @@ static
 void bilinear_remap(double* restrict tgt_point, const double *restrict src_array, const double wgts[4], const size_t src_add[4])
 {
   // *tgt_point = 0.;
-  // for ( int n = 0; n < 4; ++n ) *tgt_point += src_array[src_add[n]]*wgts[n];
+  // for ( unsigned n = 0; n < 4; ++n ) *tgt_point += src_array[src_add[n]]*wgts[n];
   *tgt_point = src_array[src_add[0]]*wgts[0] + src_array[src_add[1]]*wgts[1]
              + src_array[src_add[2]]*wgts[2] + src_array[src_add[3]]*wgts[3];
 }
@@ -162,12 +162,6 @@ void bilinear_remap(double* restrict tgt_point, const double *restrict src_array
 */
 void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid, remapvars_t *rv)
 {
-  /*   Local variables */
-  int  search_result;
-  size_t src_add[4];             /*  address for the four source points     */
-  double src_lats[4];            /*  latitudes  of four bilinear corners    */
-  double src_lons[4];            /*  longitudes of four bilinear corners    */
-  double wgts[4];                /*  bilinear weights for four corners      */
   extern int timer_remap_bil;
   int remap_grid_type = src_grid->remap_grid_type;
 
@@ -182,11 +176,11 @@ void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid,
   if ( src_grid->rank != 2 )
     cdoAbort("Can not do bilinear interpolation when source grid rank != 2"); 
 
-  long tgt_grid_size = tgt_grid->size;
+  size_t tgt_grid_size = tgt_grid->size;
 
   weightlinks_t *weightlinks = (weightlinks_t *) Malloc(tgt_grid_size*sizeof(weightlinks_t));
   weightlinks[0].addweights = (addweight_t *) Malloc(4*tgt_grid_size*sizeof(addweight_t));
-  for ( unsigned tgt_cell_add = 1; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
+  for ( size_t tgt_cell_add = 1; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     weightlinks[tgt_cell_add].addweights = weightlinks[0].addweights + 4*tgt_cell_add;
 
   double findex = 0;
@@ -194,12 +188,10 @@ void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid,
   /* Loop over destination grid */
 
 #if defined(_OPENMP)
-#pragma omp parallel for default(none) \
-  shared(weightlinks, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, rv, findex) \
-  private(src_add, src_lats, src_lons, wgts, search_result)    \
-  schedule(static)
+#pragma omp parallel for default(none)  schedule(static)  \
+  shared(weightlinks, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, rv, findex)
 #endif
-  for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
+  for ( size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     {
 #if defined(_OPENMP)
 #include "pragma_omp_atomic_update.h"
@@ -214,7 +206,13 @@ void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid,
       double plon = 0, plat = 0;
       remapgrid_get_lonlat(tgt_grid, tgt_cell_add, &plon, &plat);
 
+      size_t src_add[4];    //  address for the four source points
+      double src_lats[4];   //  latitudes  of four bilinear corners
+      double src_lons[4];   //  longitudes of four bilinear corners
+      double wgts[4];       //  bilinear weights for four corners
+
       // Find nearest square of grid points on source grid
+      int search_result;
       if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
 	search_result = grid_search_reg2d(src_grid, src_add, src_lats, src_lons, 
 					  plat, plon, src_grid->dims,
@@ -228,17 +226,16 @@ void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid,
       // Check to see if points are mask points
       if ( search_result > 0 )
 	{
-	  for ( int n = 0; n < 4; ++n )
+	  for ( unsigned n = 0; n < 4; ++n )
 	    if ( ! src_grid->mask[src_add[n]] ) search_result = 0;
 	}
 
       // If point found, find local iw,jw coordinates for weights
       if ( search_result > 0 )
 	{
-	  double iw, jw;  // current guess for bilinear coordinate 
-
           tgt_grid->cell_frac[tgt_cell_add] = 1.;
 
+	  double iw, jw;  // current guess for bilinear coordinate 
           if ( find_ij_weights(plon, plat, src_lats, src_lons, &iw, &jw) )
 	    {
 	      // Successfully found iw,jw - compute weights
@@ -287,12 +284,6 @@ void scrip_remap_bilinear_weights(remapgrid_t *src_grid, remapgrid_t *tgt_grid,
 */
 void scrip_remap_bilinear(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const double *restrict src_array, double *restrict tgt_array, double missval)
 {
-  /*   Local variables */
-  int  search_result;
-  size_t src_add[4];             /*  address for the four source points     */
-  double src_lats[4];            /*  latitudes  of four bilinear corners    */
-  double src_lons[4];            /*  longitudes of four bilinear corners    */
-  double wgts[4];                /*  bilinear weights for four corners      */
   extern int timer_remap_bil;
   int remap_grid_type = src_grid->remap_grid_type;
 
@@ -302,7 +293,7 @@ void scrip_remap_bilinear(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const do
 
   progressInit();
 
-  long tgt_grid_size = tgt_grid->size;
+  size_t tgt_grid_size = tgt_grid->size;
 
   /* Compute mappings from source to target grid */
 
@@ -314,12 +305,10 @@ void scrip_remap_bilinear(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const do
   /* Loop over destination grid */
 
 #if defined(_OPENMP)
-#pragma omp parallel for default(none) \
-  shared(cdoSilentMode, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, src_array, tgt_array, missval, findex) \
-  private(src_add, src_lats, src_lons, wgts, search_result)    \
-  schedule(static)
+#pragma omp parallel for default(none)  schedule(static)  \
+  shared(cdoSilentMode, remap_grid_type, tgt_grid_size, src_grid, tgt_grid, src_array, tgt_array, missval, findex)  
 #endif
-  for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
+  for ( size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add )
     {
 #if defined(_OPENMP)
 #include "pragma_omp_atomic_update.h"
@@ -334,7 +323,13 @@ void scrip_remap_bilinear(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const do
       double plon = 0, plat = 0;
       remapgrid_get_lonlat(tgt_grid, tgt_cell_add, &plon, &plat);
 
+      size_t src_add[4];    //  address for the four source points
+      double src_lats[4];   //  latitudes  of four bilinear corners
+      double src_lons[4];   //  longitudes of four bilinear corners
+      double wgts[4];       //  bilinear weights for four corners
+
       // Find nearest square of grid points on source grid
+      int search_result;
       if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
 	search_result = grid_search_reg2d(src_grid, src_add, src_lats, src_lons, 
 					  plat, plon, src_grid->dims,
@@ -348,17 +343,16 @@ void scrip_remap_bilinear(remapgrid_t *src_grid, remapgrid_t *tgt_grid, const do
       // Check to see if points are mask points
       if ( search_result > 0 )
 	{
-	  for ( int n = 0; n < 4; ++n )
+	  for ( unsigned n = 0; n < 4; ++n )
 	    if ( ! src_grid->mask[src_add[n]] ) search_result = 0;
 	}
 
       // If point found, find local iw,jw coordinates for weights
       if ( search_result > 0 )
 	{
-	  double iw, jw;  // current guess for bilinear coordinate
-
           tgt_grid->cell_frac[tgt_cell_add] = 1.;
 
+	  double iw, jw;  // current guess for bilinear coordinate
           if ( find_ij_weights(plon, plat, src_lats, src_lons, &iw, &jw) )
 	    {
 	      // Successfully found iw,jw - compute weights
diff --git a/src/remap_conserv.cc b/src/remap_conserv.cc
index d6cd51d..f6822d9 100644
--- a/src/remap_conserv.cc
+++ b/src/remap_conserv.cc
@@ -108,7 +108,7 @@ void search_free(search_t *search)
 int rect_grid_search2(long *imin, long *imax, double xmin, double xmax, long nxm, const double *restrict xm);
 
 static
-size_t get_srch_cells_reg2d(const int *restrict src_grid_dims, 
+size_t get_srch_cells_reg2d(const size_t *restrict src_grid_dims, 
                             const double *restrict src_corner_lat, const double *restrict src_corner_lon,
                             const double *restrict tgt_cell_bound_box, size_t *srch_add)
 {
@@ -219,7 +219,7 @@ void restrict_boundbox(const double *restrict grid_bound_box, double *restrict b
 }
 
 static
-void boundbox_from_corners_reg2d(size_t grid_add, const int *restrict grid_dims, const double *restrict corner_lon,
+void boundbox_from_corners_reg2d(size_t grid_add, const size_t *restrict grid_dims, const double *restrict corner_lon,
 				 const double *restrict corner_lat, double *restrict bound_box)
 {
   size_t nx = grid_dims[0];
diff --git a/src/remap_distwgt.cc b/src/remap_distwgt.cc
index 0a9407a..5d4dcf5 100644
--- a/src/remap_distwgt.cc
+++ b/src/remap_distwgt.cc
@@ -46,7 +46,7 @@ void nbr_check_distance(size_t num_neighbors, const size_t *restrict nbr_add, do
 {
   // If distance is zero, set to small number
   for ( size_t nchk = 0; nchk < num_neighbors; ++nchk )
-    if ( nbr_add[nchk] < ULONG_MAX && nbr_dist[nchk] <= 0. ) nbr_dist[nchk] = TINY;
+    if ( nbr_add[nchk] < SIZE_MAX && nbr_dist[nchk] <= 0. ) nbr_dist[nchk] = TINY;
 }
 
 
@@ -61,7 +61,7 @@ double nbr_compute_weights(size_t num_neighbors, const int *restrict src_grid_ma
       for ( size_t n = 0; n < num_neighbors; ++n )
         {
           nbr_mask[n] = false;
-          if ( nbr_add[n] < ULONG_MAX )
+          if ( nbr_add[n] < SIZE_MAX )
             if ( src_grid_mask[nbr_add[n]] )
               {
                 nbr_dist[n] = 1./nbr_dist[n];
@@ -75,7 +75,7 @@ double nbr_compute_weights(size_t num_neighbors, const int *restrict src_grid_ma
       for ( size_t n = 0; n < num_neighbors; ++n )
         {
           nbr_mask[n] = false;
-          if ( nbr_add[n] < ULONG_MAX )
+          if ( nbr_add[n] < SIZE_MAX )
             {
               nbr_dist[n] = 1./nbr_dist[n];
               dist_tot += nbr_dist[n];
@@ -113,8 +113,8 @@ size_t nbr_normalize_weights(size_t num_neighbors, double dist_tot, const bool *
 
 #define MAX_SEARCH_CELLS 25
 static
-void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgrid_t *src_grid, size_t *restrict nbr_add, double *restrict nbr_dist, 
-			   double plon, double plat, const int *restrict src_grid_dims)
+void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, size_t *restrict nbr_add, double *restrict nbr_dist, 
+			   double plon, double plat)
 {
   /*
     Output variables:
@@ -127,14 +127,13 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
     double plat,         ! latitude  of the search point
     double plon,         ! longitude of the search point
   */
-  size_t n, nadd;
+  size_t n;
   size_t ii, jj;
   long i, j, ix;
   size_t src_add[MAX_SEARCH_CELLS];
   size_t *src_add_tmp = NULL;
   size_t *psrc_add = src_add;
   size_t num_add = 0;
-  double distance;   //  Angular distance
   double cos_search_radius = cos(gs->search_radius);
   double coslat_dst = cos(plat);  // cos(lat)  of the search point
   double coslon_dst = cos(plon);  // cos(lon)  of the search point
@@ -147,11 +146,11 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
   double *restrict src_center_lon = gs->reg2d_center_lon;
   double *restrict src_center_lat = gs->reg2d_center_lat;
 
-  long nx = src_grid_dims[0];
-  long ny = src_grid_dims[1];
+  long nx = gs->dims[0];
+  long ny = gs->dims[1];
 
   size_t nxm = nx;
-  if ( src_grid->is_cyclic ) nxm++;
+  if ( gs->is_cyclic ) nxm++;
 
   if ( plon < src_center_lon[0]     ) plon += PI2;
   if ( plon > src_center_lon[nxm-1] ) plon -= PI2;
@@ -160,7 +159,7 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
 
   if ( lfound )
     {
-      if ( src_grid->is_cyclic && ii == (nxm-1) ) ii = 0;
+      if ( gs->is_cyclic && ii == (nxm-1) ) ii = 0;
 
       long k;
       for ( k = 3; k < 10000; k+=2 )
@@ -183,7 +182,7 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
 	  {
 	    ix = i;
 	    
-	    if ( src_grid->is_cyclic )
+	    if ( gs->is_cyclic )
 	      {
 		if ( ix <   0 ) ix += nx;
 		if ( ix >= nx ) ix -= nx;
@@ -197,18 +196,19 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
   // Initialize distance and address arrays
   for ( n = 0; n < num_neighbors; ++n )
     {
-      nbr_add[n]  = ULONG_MAX;
+      nbr_add[n]  = SIZE_MAX;
       nbr_dist[n] = BIGNUM;
     }
 
   if ( lfound )
     {
       size_t ix, iy;
+      size_t nadd;
+      double distance;   //  Angular distance
 
       for ( size_t na = 0; na < num_add; ++na )
 	{
 	  nadd = psrc_add[na];
-
 	  iy = nadd/nx;
 	  ix = nadd - iy*nx;
 
@@ -232,7 +232,7 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
 
       if ( src_add_tmp ) Free(src_add_tmp);
     }
-  else if ( src_grid->lextrapolate )
+  else if ( gs->extrapolate )
     {
       int search_result;
 
@@ -240,7 +240,7 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
 	{
 	  size_t nbr_add4[4];
 	  double nbr_dist4[4];
-	  for ( n = 0; n < num_neighbors; ++n ) nbr_add4[n] = ULONG_MAX;
+	  for ( n = 0; n < num_neighbors; ++n ) nbr_add4[n] = SIZE_MAX;
 	  search_result = grid_search_reg2d_nn(nx, ny, nbr_add4, nbr_dist4, plat, plon, src_center_lat, src_center_lon);
 	  if ( search_result < 0 )
 	    {
@@ -254,7 +254,7 @@ void grid_search_nbr_reg2d(struct gridsearch *gs, size_t num_neighbors, remapgri
 	}
 
       if ( search_result >= 0 )
-	for ( n = 0; n < num_neighbors; ++n ) nbr_add[n] = ULONG_MAX;
+	for ( n = 0; n < num_neighbors; ++n ) nbr_add[n] = SIZE_MAX;
     }
 } // grid_search_nbr_reg2d
 
@@ -276,7 +276,7 @@ int grid_search_nbr(struct gridsearch *gs, size_t num_neighbors, size_t *restric
   double search_radius = gs->search_radius;
 
   // Initialize distance and address arrays
-  for ( size_t n = 0; n < num_neighbors; ++n ) nbr_add[n]  = ULONG_MAX;
+  for ( size_t n = 0; n < num_neighbors; ++n ) nbr_add[n]  = SIZE_MAX;
   for ( size_t n = 0; n < num_neighbors; ++n ) nbr_dist[n] = BIGNUM;
 
   size_t ndist = num_neighbors;
@@ -371,9 +371,6 @@ void remap_distwgt_weights(size_t num_neighbors, remapgrid_t *src_grid, remapgri
 
   size_t src_grid_size = src_grid->size;
   size_t tgt_grid_size = tgt_grid->size;
-  size_t nx = src_grid->dims[0];
-  size_t ny = src_grid->dims[1];
-  bool lcyclic = src_grid->is_cyclic;
 
   weightlinks_t *weightlinks = (weightlinks_t *) Malloc(tgt_grid_size*sizeof(weightlinks_t));
   weightlinks[0].addweights = (addweight_t *) Malloc(num_neighbors*tgt_grid_size*sizeof(addweight_t));
@@ -391,12 +388,14 @@ void remap_distwgt_weights(size_t num_neighbors, remapgrid_t *src_grid, remapgri
 
   struct gridsearch *gs = NULL;
   if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
-    gs = gridsearch_create_reg2d(lcyclic, nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
+    gs = gridsearch_create_reg2d(src_grid->is_cyclic, src_grid->dims, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
   else if ( num_neighbors == 1 )
     gs = gridsearch_create_nn(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
   else
     gs = gridsearch_create(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
 
+  if ( src_grid->lextrapolate ) gridsearch_extrapolate(gs);
+
 #if defined(_OPENMP)
   if ( cdoVerbose ) printf("gridsearch created: %.2f seconds\n", omp_get_wtime()-start);
   if ( cdoVerbose ) start = omp_get_wtime();
@@ -430,8 +429,7 @@ void remap_distwgt_weights(size_t num_neighbors, remapgrid_t *src_grid, remapgri
 
       // Find nearest grid points on source grid and distances to each point
       if ( remap_grid_type == REMAP_GRID_TYPE_REG2D )
-	grid_search_nbr_reg2d(gs, num_neighbors, src_grid, nbr_add[ompthID], nbr_dist[ompthID], 
-			      plon, plat, src_grid->dims);
+	grid_search_nbr_reg2d(gs, num_neighbors, nbr_add[ompthID], nbr_dist[ompthID], plon, plat);
       else
         grid_search_nbr(gs, num_neighbors, nbr_add[ompthID], nbr_dist[ompthID], plon, plat);
 
@@ -485,9 +483,6 @@ void remap_distwgt(size_t num_neighbors, remapgrid_t *src_grid, remapgrid_t *tgt
 
   size_t src_grid_size = src_grid->size;
   size_t tgt_grid_size = tgt_grid->size;
-  size_t nx = src_grid->dims[0];
-  size_t ny = src_grid->dims[1];
-  bool lcyclic = src_grid->is_cyclic;
 
   NEW_2D(bool, nbr_mask, ompNumThreads, num_neighbors);   // mask at nearest neighbors
   NEW_2D(size_t, nbr_add, ompNumThreads, num_neighbors);  // source address at nearest neighbors
@@ -500,12 +495,14 @@ void remap_distwgt(size_t num_neighbors, remapgrid_t *src_grid, remapgrid_t *tgt
 
   struct gridsearch *gs = NULL;
   if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-    gs = gridsearch_create_reg2d(lcyclic, nx, ny, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
+    gs = gridsearch_create_reg2d(src_grid->is_cyclic, src_grid->dims, src_grid->reg2d_center_lon, src_grid->reg2d_center_lat);
   else if ( num_neighbors == 1 )
     gs = gridsearch_create_nn(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
   else
     gs = gridsearch_create(src_grid_size, src_grid->cell_center_lon, src_grid->cell_center_lat);
 
+  if ( src_grid->lextrapolate ) gridsearch_extrapolate(gs);
+
 #if defined(_OPENMP)
   if ( cdoVerbose ) printf("gridsearch created: %.2f seconds\n", omp_get_wtime()-start);
   if ( cdoVerbose ) start = omp_get_wtime();
@@ -539,8 +536,7 @@ void remap_distwgt(size_t num_neighbors, remapgrid_t *src_grid, remapgrid_t *tgt
 
       // Find nearest grid points on source grid and distances to each point
       if ( src_remap_grid_type == REMAP_GRID_TYPE_REG2D )
-	grid_search_nbr_reg2d(gs, num_neighbors, src_grid, nbr_add[ompthID], nbr_dist[ompthID], 
-			      plon, plat, src_grid->dims);
+	grid_search_nbr_reg2d(gs, num_neighbors, nbr_add[ompthID], nbr_dist[ompthID], plon, plat);
       else
         grid_search_nbr(gs, num_neighbors, nbr_add[ompthID], nbr_dist[ompthID], plon, plat);
       
diff --git a/src/remap_scrip_io.cc b/src/remap_scrip_io.cc
index c38937c..14fd801 100644
--- a/src/remap_scrip_io.cc
+++ b/src/remap_scrip_io.cc
@@ -384,8 +384,11 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
 
   // Write mapping data
 
-  nce(nc_put_var_int(nc_file_id, nc_srcgrddims_id, src_grid.dims));
-  nce(nc_put_var_int(nc_file_id, nc_dstgrddims_id, tgt_grid.dims));
+  int dims[2];
+  dims[0] = (int)src_grid.dims[0]; dims[1] = (int)src_grid.dims[1];
+  nce(nc_put_var_int(nc_file_id, nc_srcgrddims_id, dims));
+  dims[0] = (int)tgt_grid.dims[0]; dims[1] = (int)tgt_grid.dims[1];
+  nce(nc_put_var_int(nc_file_id, nc_dstgrddims_id, dims));
 
   nce(nc_put_var_int(nc_file_id, nc_srcgrdimask_id, src_grid.mask));
   nce(nc_put_var_int(nc_file_id, nc_dstgrdimask_id, tgt_grid.mask));
@@ -694,7 +697,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   rv->max_links = rv->num_links;
 
-  rv->resize_increment = (int) (0.1 * MAX(src_grid->size, tgt_grid->size));
+  rv->resize_increment = (size_t) (0.1 * MAX(src_grid->size, tgt_grid->size));
 
   // Allocate address and weight arrays for mapping 1
 
@@ -747,7 +750,9 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   // Read all variables
 
-  nce(nc_get_var_int(nc_file_id, nc_srcgrddims_id, src_grid->dims));
+  int dims[2];
+  nce(nc_get_var_int(nc_file_id, nc_srcgrddims_id, dims));
+  src_grid->dims[0] = dims[0]; src_grid->dims[1] = dims[1];
 
   nce(nc_get_var_int(nc_file_id, nc_srcgrdimask_id, src_grid->mask));
 
@@ -779,7 +784,8 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   nce(nc_get_var_double(nc_file_id, nc_srcgrdfrac_id, src_grid->cell_frac));
 
-  nce(nc_get_var_int(nc_file_id, nc_dstgrddims_id, tgt_grid->dims));
+  nce(nc_get_var_int(nc_file_id, nc_dstgrddims_id, dims));
+  tgt_grid->dims[0] = dims[0]; tgt_grid->dims[1] = dims[1];
 
   nce(nc_get_var_int(nc_file_id, nc_dstgrdimask_id, tgt_grid->mask));
 
diff --git a/src/remap_search_latbins.cc b/src/remap_search_latbins.cc
index 8d25ab3..345d0de 100644
--- a/src/remap_search_latbins.cc
+++ b/src/remap_search_latbins.cc
@@ -45,22 +45,17 @@ void calc_bin_addr(size_t gridsize, size_t nbins, const restr_t* restrict bin_la
 
 void calc_lat_bins(remapgrid_t* src_grid, remapgrid_t* tgt_grid, int map_type)
 {
-  size_t nbins;
-  size_t n;      /* Loop counter                  */
   size_t n2;
-  double dlat;                /* lat/lon intervals for search bins  */
-  restr_t *bin_lats = NULL;
-
-  nbins = src_grid->num_srch_bins;
-  dlat = PI/nbins;
+  size_t nbins = src_grid->num_srch_bins;
+  double dlat = PI/nbins;  // lat/lon intervals for search bins
 
   if ( cdoVerbose ) cdoPrint("Using %d latitude bins to restrict search.", nbins);
 
   if ( nbins > 0 )
     {
-      bin_lats = src_grid->bin_lats = (restr_t*) Realloc(src_grid->bin_lats, 2*nbins*sizeof(restr_t));
+      restr_t *bin_lats = src_grid->bin_lats = (restr_t*) Realloc(src_grid->bin_lats, 2*nbins*sizeof(restr_t));
 
-      for ( n = 0; n < nbins; ++n )
+      for ( size_t n = 0; n < nbins; ++n )
 	{
 	  n2 = n<<1;
 	  bin_lats[n2  ] = RESTR_SCALE((n  )*dlat - PIH);
@@ -96,20 +91,15 @@ void calc_lat_bins(remapgrid_t* src_grid, remapgrid_t* tgt_grid, int map_type)
 size_t get_srch_cells(size_t tgt_cell_add, size_t nbins, size_t *bin_addr1, size_t *bin_addr2,
                       restr_t *tgt_cell_bound_box, restr_t *src_cell_bound_box, size_t src_grid_size, size_t *srch_add)
 {
-  size_t num_srch_cells;  /* num cells in restricted search arrays   */
-  size_t min_add;         /* addresses for restricting search of     */
-  size_t max_add;         /* destination grid                        */
-  size_t n, n2;           /* generic counters                        */
-  size_t src_cell_add;    /* current linear address for src cell     */
+  size_t n2;
   size_t src_cell_addm4;
-  restr_t bound_box_lat1, bound_box_lat2, bound_box_lon1, bound_box_lon2;
 
   /* Restrict searches first using search bins */
 
-  min_add = src_grid_size - 1;
-  max_add = 0;
+  size_t min_add = src_grid_size - 1;
+  size_t max_add = 0;
 
-  for ( n = 0; n < nbins; ++n )
+  for ( size_t n = 0; n < nbins; ++n )
     {
       n2 = n<<1;
       if ( tgt_cell_add >= bin_addr1[n2] && tgt_cell_add <= bin_addr1[n2+1] )
@@ -121,13 +111,13 @@ size_t get_srch_cells(size_t tgt_cell_add, size_t nbins, size_t *bin_addr1, size
 
   /* Further restrict searches using bounding boxes */
 
-  bound_box_lat1 = tgt_cell_bound_box[0];
-  bound_box_lat2 = tgt_cell_bound_box[1];
-  bound_box_lon1 = tgt_cell_bound_box[2];
-  bound_box_lon2 = tgt_cell_bound_box[3];
+  restr_t bound_box_lat1 = tgt_cell_bound_box[0];
+  restr_t bound_box_lat2 = tgt_cell_bound_box[1];
+  restr_t bound_box_lon1 = tgt_cell_bound_box[2];
+  restr_t bound_box_lon2 = tgt_cell_bound_box[3];
 
-  num_srch_cells = 0;
-  for ( src_cell_add = min_add; src_cell_add <= max_add; ++src_cell_add )
+  size_t num_srch_cells = 0;
+  for ( size_t src_cell_add = min_add; src_cell_add <= max_add; ++src_cell_add )
     {
       src_cell_addm4 = src_cell_add<<2;
       if ( (src_cell_bound_box[src_cell_addm4+2] <= bound_box_lon2)  &&
@@ -155,7 +145,7 @@ size_t get_srch_cells(size_t tgt_cell_add, size_t nbins, size_t *bin_addr1, size
 	  bound_box_lon2 -= RESTR_SCALE(PI2);
 	}
 
-      for ( src_cell_add = min_add; src_cell_add <= max_add; ++src_cell_add )
+      for ( size_t src_cell_add = min_add; src_cell_add <= max_add; ++src_cell_add )
 	{
 	  src_cell_addm4 = src_cell_add<<2;
 	  if ( (src_cell_bound_box[src_cell_addm4+2] <= bound_box_lon2)  &&
@@ -187,17 +177,15 @@ int grid_search_nn(size_t min_add, size_t max_add, size_t *restrict nbr_add, dou
 		   const double *restrict src_center_lat, const double *restrict src_center_lon)
 {
   int search_result = 0;
-  size_t n, srch_add;
-  size_t i;
-  double dist_min, distance; /* For computing dist-weighted avg */
+  double distance; /* For computing dist-weighted avg */
   double coslat_dst = cos(plat);
   double sinlat_dst = sin(plat);
   double coslon_dst = cos(plon);
   double sinlon_dst = sin(plon);
 
-  dist_min = BIGNUM;
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] = BIGNUM;
-  for ( srch_add = min_add; srch_add <= max_add; ++srch_add )
+  double dist_min = BIGNUM;
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] = BIGNUM;
+  for ( size_t srch_add = min_add; srch_add <= max_add; ++srch_add )
     {
       distance = acos(coslat_dst*cos(src_center_lat[srch_add])*
 		     (coslon_dst*cos(src_center_lon[srch_add]) +
@@ -206,11 +194,11 @@ int grid_search_nn(size_t min_add, size_t max_add, size_t *restrict nbr_add, dou
 
       if ( distance < dist_min )
 	{
-          for ( n = 0; n < 4; ++n )
+          for ( unsigned n = 0; n < 4; ++n )
 	    {
 	      if ( distance < nbr_dist[n] )
 		{
-		  for ( i = 3; i > n; --i )
+		  for ( unsigned i = 3; i > n; --i )
 		    {
 		      nbr_add [i] = nbr_add [i-1];
 		      nbr_dist[i] = nbr_dist[i-1];
@@ -225,17 +213,17 @@ int grid_search_nn(size_t min_add, size_t max_add, size_t *restrict nbr_add, dou
         }
     }
 
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] = ONE/(nbr_dist[n] + TINY);
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] = ONE/(nbr_dist[n] + TINY);
   distance = 0.0;
-  for ( n = 0; n < 4; ++n ) distance += nbr_dist[n];
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] /= distance;
+  for ( unsigned n = 0; n < 4; ++n ) distance += nbr_dist[n];
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] /= distance;
 
   return search_result;
 }
 
 
 int grid_search(remapgrid_t *src_grid, size_t *restrict src_add, double *restrict src_lats, 
-		double *restrict src_lons,  double plat, double plon, const int *restrict src_grid_dims,
+		double *restrict src_lons,  double plat, double plon, const size_t *restrict src_grid_dims,
 		const double *restrict src_center_lat, const double *restrict src_center_lon,
 		const restr_t *restrict src_grid_bound_box, const size_t *restrict src_bin_add)
 {
@@ -261,7 +249,7 @@ int grid_search(remapgrid_t *src_grid, size_t *restrict src_add, double *restric
     int src_bin_add[][2]           ! latitude bins for restricting
   */
   /*  Local variables */
-  size_t n, n2, next_n, srch_add, srch_add4;    /* dummy indices                    */
+  size_t n2, next_n, srch_add, srch_add4;    /* dummy indices                    */
   /* Vectors for cross-product check */
   double vec1_lat, vec1_lon;
   double vec2_lat, vec2_lon;
@@ -276,7 +264,7 @@ int grid_search(remapgrid_t *src_grid, size_t *restrict src_add, double *restric
 
   // restrict search first using bins
 
-  for ( n = 0; n < 4; ++n ) src_add[n] = 0;
+  for ( unsigned n = 0; n < 4; ++n ) src_add[n] = 0;
 
   // addresses for restricting search
   size_t min_add = src_grid->size-1;
@@ -307,6 +295,8 @@ int grid_search(remapgrid_t *src_grid, size_t *restrict src_add, double *restric
 	   rlat >= src_grid_bound_box[srch_add4  ] &&
 	   rlat <= src_grid_bound_box[srch_add4+1])
 	{
+          unsigned n;
+
 	  /* We are within bounding box so get really serious */
 
           /* Determine neighbor addresses */
diff --git a/src/remap_search_reg2d.cc b/src/remap_search_reg2d.cc
index 3aaea0e..da34f58 100644
--- a/src/remap_search_reg2d.cc
+++ b/src/remap_search_reg2d.cc
@@ -6,20 +6,13 @@ int grid_search_reg2d_nn(size_t nx, size_t ny, size_t *restrict nbr_add, double
 			 const double *restrict src_center_lat, const double *restrict src_center_lon)
 {
   int search_result = 0;
-  size_t n, srch_add;
-  size_t i;
-  size_t ii, jj;
-  size_t jjskip;
-  double coslat, sinlat;
-  double dist_min, distance; /* For computing dist-weighted avg */
-  double *sincoslon;
   double coslat_dst = cos(plat);
   double sinlat_dst = sin(plat);
   double coslon_dst = cos(plon);
   double sinlon_dst = sin(plon);
 
-  dist_min = BIGNUM;
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] = BIGNUM;  
+  double dist_min = BIGNUM;
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] = BIGNUM;  
 
   size_t jjf = 0, jjl = ny-1;
   if ( plon >= src_center_lon[0] && plon <= src_center_lon[nx-1] )
@@ -40,33 +33,31 @@ int grid_search_reg2d_nn(size_t nx, size_t ny, size_t *restrict nbr_add, double
 	}
     }
 
-  sincoslon = (double*) Malloc(nx*sizeof(double));
+  double *sincoslon = (double*) Malloc(nx*sizeof(double));
 
-  for ( ii = 0; ii < nx; ++ii )
+  for ( size_t ii = 0; ii < nx; ++ii )
     sincoslon[ii] = coslon_dst*cos(src_center_lon[ii]) + sinlon_dst*sin(src_center_lon[ii]);
 
-  for ( jj = jjf; jj <= jjl; ++jj )
+  for ( size_t jj = jjf; jj <= jjl; ++jj )
     {
-      coslat = coslat_dst*cos(src_center_lat[jj]);
-      sinlat = sinlat_dst*sin(src_center_lat[jj]);
+      double coslat = coslat_dst*cos(src_center_lat[jj]);
+      double sinlat = sinlat_dst*sin(src_center_lat[jj]);
 
-      jjskip = jj > 1 && jj < (ny-2);
+      size_t jjskip = jj > 1 && jj < (ny-2);
 
-      for ( ii = 0; ii < nx; ++ii )
+      for ( size_t ii = 0; ii < nx; ++ii )
 	{
 	  if ( jjskip && ii > 1 && ii < (nx-2) ) continue;
 
-	  srch_add = jj*nx + ii;
-
-	  distance = acos(coslat*sincoslon[ii] + sinlat);
-
+	  double distance = acos(coslat*sincoslon[ii] + sinlat);
 	  if ( distance < dist_min )
 	    {
-	      for ( n = 0; n < 4; ++n )
+              size_t srch_add = jj*nx + ii;
+	      for ( unsigned n = 0; n < 4; ++n )
 		{
 		  if ( distance < nbr_dist[n] )
 		    {
-		      for ( i = 3; i > n; --i )
+		      for ( unsigned i = 3; i > n; --i )
 			{
 			  nbr_add [i] = nbr_add [i-1];
 			  nbr_dist[i] = nbr_dist[i-1];
@@ -84,17 +75,17 @@ int grid_search_reg2d_nn(size_t nx, size_t ny, size_t *restrict nbr_add, double
 
   Free(sincoslon);
 
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] = ONE/(nbr_dist[n] + TINY);
-  distance = 0.0;
-  for ( n = 0; n < 4; ++n ) distance += nbr_dist[n];
-  for ( n = 0; n < 4; ++n ) nbr_dist[n] /= distance;
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] = ONE/(nbr_dist[n] + TINY);
+  double distance = 0.0;
+  for ( unsigned n = 0; n < 4; ++n ) distance += nbr_dist[n];
+  for ( unsigned n = 0; n < 4; ++n ) nbr_dist[n] /= distance;
 
-  return (search_result);
+  return search_result;
 }
 
 
 int grid_search_reg2d(remapgrid_t *src_grid, size_t *restrict src_add, double *restrict src_lats, 
-		      double *restrict src_lons,  double plat, double plon, const int *restrict src_grid_dims,
+		      double *restrict src_lons,  double plat, double plon, const size_t *restrict src_grid_dims,
 		      const double *restrict src_center_lat, const double *restrict src_center_lon)
 {
   /*
@@ -114,12 +105,9 @@ int grid_search_reg2d(remapgrid_t *src_grid, size_t *restrict src_add, double *r
     double src_center_lat[]        ! latitude  of each src grid center 
     double src_center_lon[]        ! longitude of each src grid center
   */
-  /*  Local variables */
   int search_result = 0;
-  long n;
-  size_t ii, iix, jj;
 
-  for ( n = 0; n < 4; ++n ) src_add[n] = 0;
+  for ( unsigned n = 0; n < 4; ++n ) src_add[n] = 0;
 
   size_t nx = src_grid_dims[0];
   size_t ny = src_grid_dims[1];
@@ -130,11 +118,12 @@ int grid_search_reg2d(remapgrid_t *src_grid, size_t *restrict src_add, double *r
   if ( /*plon < 0   &&*/ plon < src_center_lon[0]     ) plon += PI2;
   if ( /*plon > PI2 &&*/ plon > src_center_lon[nxm-1] ) plon -= PI2;
 
+  size_t ii, jj;
   int lfound = rect_grid_search(&ii, &jj, plon, plat, nxm, ny, src_center_lon, src_center_lat);
 
   if ( lfound )
     {
-      iix = ii;
+      size_t iix = ii;
       if ( src_grid->is_cyclic && iix == (nxm-1) ) iix = 0;
       src_add[0] = (jj-1)*nx+(ii-1);
       src_add[1] = (jj-1)*nx+(iix);
@@ -175,5 +164,5 @@ int grid_search_reg2d(remapgrid_t *src_grid, size_t *restrict src_add, double *r
   */
   search_result = grid_search_reg2d_nn(nx, ny, src_add, src_lats, plat, plon, src_center_lat, src_center_lon);
 
-  return (search_result);
+  return search_result;
 }  /* grid_search_reg2d */
diff --git a/src/remap_store_link_cnsrv.cc b/src/remap_store_link_cnsrv.cc
index 719425e..ae215d9 100644
--- a/src/remap_store_link_cnsrv.cc
+++ b/src/remap_store_link_cnsrv.cc
@@ -27,7 +27,7 @@ void grid_store_init(grid_store_t* grid_store, long gridsize)
   if ( grid_store->max_size%grid_store->blk_size > 0 ) grid_store->nblocks++;
 
   if ( cdoVerbose )
-    fprintf(stdout, "blksize = %zu  lastblksize = %zu  max_size = %zu  nblocks = %zu\n", 
+    fprintf(stdout, "blksize = %ld  lastblksize = %ld  max_size = %ld  nblocks = %ld\n",
 	    grid_store->blk_size, grid_store->max_size%grid_store->blk_size, 
 	    grid_store->max_size, grid_store->nblocks);
 
diff --git a/src/remaplib.cc b/src/remaplib.cc
index 9410e98..578fd48 100644
--- a/src/remaplib.cc
+++ b/src/remaplib.cc
@@ -413,6 +413,7 @@ void check_lat_boundbox_range(size_t nlats, restr_t *restrict bound_box, double
 static
 int expand_lonlat_grid(int gridID)
 {
+  if ( cdoVerbose ) cdoPrint("expand_lonlat_grid");
   size_t nx = gridInqXsize(gridID);
   size_t ny = gridInqYsize(gridID);
   size_t nxp4 = nx+4;
@@ -459,6 +460,7 @@ int expand_lonlat_grid(int gridID)
 static
 int expand_curvilinear_grid(int gridID)
 {
+  if ( cdoVerbose ) cdoPrint("expand_curvilinear_grid");
   size_t gridsize = gridInqSize(gridID);
   long nx = (long) gridInqXsize(gridID);
   long ny = (long) gridInqYsize(gridID);
@@ -523,7 +525,7 @@ int expand_curvilinear_grid(int gridID)
 /*****************************************************************************/
 
 static
-void grid_check_lat_borders_rad(int n, double *ybounds)
+void grid_check_lat_borders_rad(size_t n, double *ybounds)
 {
 #define  YLIM  (88*DEG2RAD)
   if ( ybounds[0] > ybounds[n-1] )
@@ -726,14 +728,11 @@ void cell_bounding_boxes(remapgrid_t *grid, int remap_grid_basis)
 	}
       else /* full grid search */
 	{
-	  size_t gridsize;
-	  size_t i, i4;
-	  
-	  gridsize = grid->size;
-  
 	  if ( cdoVerbose ) cdoPrint("Grid: bounds missing -> full grid search!");
 
-	  for ( i = 0; i < gridsize; ++i )
+	  size_t gridsize = grid->size;
+	  size_t i4;
+	  for ( size_t i = 0; i < gridsize; ++i )
 	    {
 	      i4 = i<<2;
 	      grid->cell_bound_box[i4  ] = RESTR_SCALE(-PIH);
@@ -794,10 +793,7 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
       if ( map_type == MAP_TYPE_BILINEAR && src_grid->remap_grid_type == REMAP_GRID_TYPE_REG2D ) tgt_grid->remap_grid_type = REMAP_GRID_TYPE_REG2D;
     }
 
-  if ( lextrapolate )
-    src_grid->lextrapolate = true;
-  else
-    src_grid->lextrapolate = false;
+  src_grid->lextrapolate = lextrapolate;
 
   if ( map_type == MAP_TYPE_CONSERV || map_type == MAP_TYPE_CONSERV_YAC )
     {
@@ -869,7 +865,6 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
 
   //if ( src_grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
   remap_define_grid(map_type, gridID1, src_grid, "Source");
-
   remap_define_grid(map_type, gridID2, tgt_grid, "Target");
 
   if ( src_grid->remap_grid_type == REMAP_GRID_TYPE_REG2D && tgt_grid->remap_grid_type == REMAP_GRID_TYPE_REG2D )
@@ -982,7 +977,7 @@ void remap_vars_init(int map_type, size_t src_grid_size, size_t tgt_grid_size, r
 /*
    This routine resizes remapping arrays by increasing(decreasing) the max_links by increment
 */
-void resize_remap_vars(remapvars_t *rv, int increment)
+void resize_remap_vars(remapvars_t *rv, int64_t increment)
 {
   /*
     Input variables:
@@ -1171,7 +1166,7 @@ size_t get_max_add(size_t num_links, size_t size, const size_t *restrict add)
 static 
 size_t binary_search_int(const size_t *array, size_t len, size_t value)
 {       
-  long low = 0, high = len - 1, midpoint = 0;
+  int64_t low = 0, high = len - 1, midpoint = 0;
  
   while ( low <= high )
     {
@@ -1471,7 +1466,7 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
 #endif
   for ( size_t n = 0; n < rv.num_links; ++n ) tgt_count[rv.tgt_cell_add[n]]++;
 
-  size_t imin = ULONG_MAX;
+  size_t imin = SIZE_MAX;
   size_t imax = 0;
   for ( size_t n = 0; n < tgt_grid.size; ++n )
     {
diff --git a/src/sellist.cc b/src/sellist.cc
index aab80ae..944979c 100644
--- a/src/sellist.cc
+++ b/src/sellist.cc
@@ -115,7 +115,7 @@ int sellist_add(sellist_t *sellist, const char *txt, const char *name, int type)
 
                   if ( first == last )
                     {
-                      ((int*)e->cvalues)[j++] = parameter2int(e->values[i]);
+                      ((int*)e->cvalues)[j++] = first;
                     }
                   else
                     {
@@ -126,17 +126,20 @@ int sellist_add(sellist_t *sellist, const char *txt, const char *name, int type)
                         for ( int ival = first; ival >= last; ival += inc ) k++;
 
                       e->nvalues += k-1;
-                      e->cvalues = Realloc(e->cvalues, e->nvalues*sizeof(int));
-
-                      if ( inc >= 0 )
+                      if ( e->nvalues )
                         {
-                          for ( int ival = first; ival <= last; ival += inc )
-                            ((int*)e->cvalues)[j++] = ival;
-                        }
-                      else
-                        {
-                          for ( int ival = first; ival >= last; ival += inc )
-                            ((int*)e->cvalues)[j++] = ival;
+                          e->cvalues = Realloc(e->cvalues, e->nvalues*sizeof(int));
+
+                          if ( inc >= 0 )
+                            {
+                              for ( int ival = first; ival <= last; ival += inc )
+                                ((int*)e->cvalues)[j++] = ival;
+                            }
+                          else
+                            {
+                              for ( int ival = first; ival >= last; ival += inc )
+                                ((int*)e->cvalues)[j++] = ival;
+                            }
                         }
                     }
 
@@ -358,8 +361,11 @@ void sellist_print(sellist_t *sellist)
           int nvalues = e->nvalues;
           if ( nvalues > 12 ) nvalues = 11;
           for ( int i = 0; i < nvalues; ++i ) sellist_print_val(e->type, (cvalues_t *)e->cvalues, i);
-          if ( nvalues < e->nvalues ) printf(" ...");
-          sellist_print_val(e->type, (cvalues_t *)e->cvalues, e->nvalues-1);
+          if ( nvalues < e->nvalues )
+            {
+              printf(" ...");
+              sellist_print_val(e->type, (cvalues_t *)e->cvalues, e->nvalues-1);
+            }
           printf("\n");
         }
     }
diff --git a/src/util.cc b/src/util.cc
index 790bdde..b51d6f2 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -15,22 +15,23 @@
   GNU General Public License for more details.
 */
 
-#if defined(HAVE_CONFIG_H)
+#ifdef  HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#if defined(_OPENMP)
+#ifdef  _OPENMP
 #include <omp.h>
 #endif
 
-#if defined(HAVE_FNMATCH_H)
+#ifdef  HAVE_FNMATCH_H
 #include <fnmatch.h>
 #endif
 
 
 #include <stdio.h>
 #include <string.h>
-#include <ctype.h>   /* tolower */
+#include <ctype.h>    /* tolower  */
+#include <inttypes.h> /* intmax_t */
 
 #include "cdi.h"
 #include "cdo.h"
@@ -39,22 +40,17 @@
 #include "util.h"
 
 
-#if ! defined(VERSION)
+#ifndef  VERSION
 #define  VERSION  "0.0.1"
 #endif
  
 
-/* refactor: moved here from *.c */
-
-int CDO_opterr = 0;      // refactor: moved here from cdo_getopt.cc
-const char *CDO_optarg = NULL; // refactor: moved here from cdo_getopt.cc
-int CDO_optind = 1;      // refactor: moved here from cdo_getopt.cc
-
+int CDO_opterr = 0; 
+const char *CDO_optarg = NULL;
+int CDO_optind = 1;
 
-/* refactor: moved here from cdo.cc */
-
-char *Progname;
-const char *CDO_Version = "Climate Data Operators version " VERSION" (http://mpimet.mpg.de/cdo)";
+const char *CDO_progname = NULL;
+const char *CDO_version = "Climate Data Operators version " VERSION" (http://mpimet.mpg.de/cdo)";
 
 int ompNumThreads = 1;
 
@@ -68,7 +64,7 @@ int cdoDefaultFileType   = CDI_UNDEFID;
 int cdoDefaultDataType   = CDI_UNDEFID;
 int cdoDefaultByteorder  = CDI_UNDEFID;
 int cdoDefaultTableID    = CDI_UNDEFID;
-int cdoDefaultInstID     = CDI_UNDEFID;     // moved here from institution.cc, was UNDEFID
+int cdoDefaultInstID     = CDI_UNDEFID;
 int cdoDefaultTimeType   = CDI_UNDEFID;
 
 int cdoLockIO            = FALSE;
@@ -112,7 +108,7 @@ char **cdoVarnames       = NULL;
 char CDO_File_Suffix[32];
 
 int cdoExpMode           = -1;
-const char *cdoExpName         = NULL;
+const char *cdoExpName   = NULL;
 
 int timer_read, timer_write;
 
@@ -125,8 +121,8 @@ const char *cdoComment(void)
     {
       init = true;
 
-      int size = strlen(CDO_Version);
-      strncat(comment, CDO_Version, size);
+      int size = strlen(CDO_version);
+      strncat(comment, CDO_version, size);
       comment[size] = 0;
     }
 
@@ -184,7 +180,7 @@ void cdo_omp_set_num_threads(int nthreads)
 }
 
 
-char *getProgname(char *string)
+const char *getProgname(char *string)
 {
 #if defined(_WIN32)
   /*  progname = strrchr(string, '\\'); */
@@ -193,8 +189,10 @@ char *getProgname(char *string)
   char *progname = strrchr(string, '/');
 #endif
 
-  if ( progname == NULL ) progname = string;
-  else                    progname++;
+  if ( progname == NULL )
+    progname = string;
+  else
+    progname++;
 
   return progname;
 }
@@ -216,53 +214,50 @@ char *getOperator(const char *argument)
 }
 
 
-const char *getOperatorName(const char *operatorArg)
+const char *getOperatorName(const char *operatorCommand)
 {
   char *operatorName = NULL;
 
-  if ( operatorArg )
+  if ( operatorCommand )
     {
-      if ( operatorArg[0] == '-' )
-      {
-          operatorArg++;
-      }
-      char *commapos = (char *)strchr(operatorArg, ',');
-      size_t len = (commapos != NULL) ? (size_t)(commapos - operatorArg) : strlen(operatorArg);
+      if ( operatorCommand[0] == '-' ) operatorCommand++;
+      char *commapos = (char *)strchr(operatorCommand, ',');
+      size_t len = (commapos != NULL) ? (size_t)(commapos - operatorCommand) : strlen(operatorCommand);
 
       operatorName = (char*) Malloc(len+1);
 
-      memcpy(operatorName, operatorArg, len);
+      memcpy(operatorName, operatorCommand, len);
       operatorName[len] = '\0';
     }
 
   /*  return operatorName; */
   if(is_alias(operatorName))
-  {
-    operatorName = get_original(operatorName);
-  }
-    return operatorName;
+    {
+      operatorName = get_original(operatorName);
+    }
+
+  return operatorName;
 }
 
-char *getOperatorArg(const char *xoperator)
+char *getOperatorArg(const char *p_operatorCommand)
 {
-  char *operatorArg = NULL;
+  char *operatorCommand = NULL;
 
-  if ( xoperator )
+  if ( p_operatorCommand )
     {
-      char *commapos = (char *)strchr(xoperator, ',');
-
+      char *commapos = (char *)strchr(p_operatorCommand, ',');
       if ( commapos )
         {
           size_t len = strlen(commapos+1);
           if ( len )
             {
-              operatorArg = (char*) Malloc(len+1);
-              strcpy(operatorArg, commapos+1);
+              operatorCommand = (char*) Malloc(len+1);
+              strcpy(operatorCommand, commapos+1);
             }
         }
     }
 
-  return operatorArg;
+  return operatorCommand;
 }
 
 char *getFileArg(char *argument)
@@ -272,7 +267,6 @@ char *getFileArg(char *argument)
   if ( argument )
     {
       char *blankpos = strchr(argument, ' ');
-
       if ( blankpos )
         {
           char *parg = blankpos + 1;
@@ -327,13 +321,11 @@ void input_int(char *arg, int intarr[], int maxint, int *nintfound)
 
 std::string string2lower(std::string str)
 {
-    std::string lower_case_string = str;
-    for(char c : str)
-    {
-       c = tolower(c); 
-    }
-    return lower_case_string;
+  std::string lower_case_string = str;
+  for(char c : str) c = tolower(c); 
+  return lower_case_string;
 }
+
 void strtolower(char *str)
 {
   if ( str )
@@ -408,6 +400,18 @@ int parameter2int(const char *string)
 }
 
 
+size_t parameter2sizet(const char *string)
+{
+  char *endptr = NULL;
+  size_t ival = (size_t) strtoimax(string, &endptr, 10);
+  if ( *endptr != 0 )
+    cdoAbort("Integer parameter >%s< contains invalid character at position %d!",
+	     string, (int)(endptr-string+1));
+
+  return ival;
+}
+
+
 int parameter2intlist(const char *string)
 {
   char *endptr = NULL;
@@ -489,9 +493,7 @@ int month_to_season(int month)
   return seas;
 }
 
-//#include <sys/types.h>
 #include <sys/stat.h>
-//#include <unistd.h>
 
 bool fileExists(const char *restrict filename)
 {
diff --git a/src/util.h b/src/util.h
index 702f07c..9c73b0f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -43,8 +43,12 @@
 
 #define  UNCHANGED_RECORD  (processSelf().m_ID == 0 && cdoStreamName(0)->argv[0][0] != '-' && cdoRegulargrid == FALSE && cdoDefaultFileType == -1 && cdoDefaultDataType == -1 && cdoDefaultByteorder == -1 )
 
+#define  ITSME  (strcmp(CDO_username, "\x6d\x32\x31\x34\x30\x30\x33") == 0)
+
 #include <string>
-extern char *Progname;
+extern const char *CDO_progname;
+extern const char *CDO_version;
+extern const char *CDO_username;
 extern char *cdoGridSearchDir;
 extern int CDO_Reduce_Dim;
 extern int CDO_Memtype;
@@ -60,7 +64,7 @@ extern int CDO_opterr;
 extern int CDO_flt_digits;
 extern int CDO_dbl_digits;
 
-extern int remap_genweights;
+extern bool REMAP_genweights;
 
 extern const char *cdoExpName;
 extern int ompNumThreads;
@@ -109,15 +113,12 @@ extern int cdoNumVarnames;
 extern char **cdoVarnames;
 extern char CDO_File_Suffix[32]; // refactor: added keyword extern
 
-extern const char *CDO_Version;
-
-
 
 
-char *getProgname(char *string);
+const char *getProgname(char *string);
 char *GetOperator(const char *argument);
-const char *getOperatorName(const char *xoperator);
-char *getOperatorArg(const char *xoperator);
+const char *getOperatorName(const char *operatorCommand);
+char *getOperatorArg(const char *operatorCommand);
 const char *cdoComment(void);
 
 char *getFileArg(char *argument);
@@ -194,7 +195,7 @@ int     cdoDefineZaxis(const char *zaxisfile);
 
 int     vlistInqNWPV(int vlistID, int varID);
 int     vlistIsSzipped(int vlistID);
-int     vlist_check_gridsize(int vlistID);
+size_t  vlist_check_gridsize(int vlistID);
 int     vlist_get_psvarid(int vlistID, int zaxisID);
 double *vlist_read_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlev, int *rnhlevf, int *rnhlevh);
 void vlist_change_hybrid_zaxis(int vlistID1, int vlistID2, int zaxisID1, int zaxisID2);
diff --git a/test/Arithc.test.in b/test/Arithc.test.in
index f036885..e783aa4 100644
--- a/test/Arithc.test.in
+++ b/test/Arithc.test.in
@@ -15,17 +15,20 @@ NTEST=1
 for STAT in $STATS; do
   RSTAT=0
 
+  rm Arithc_${STAT}.debug
+  DEBUG_OUT="--seperateDebugFromLog Arithc_${STAT}.debug"
+
   OFILE=stat${STAT}_res
 
   for VAR in -777 -1 0 1 777; do
     VAL=1
     CFILE=constval
-    $CDO -f srv -b 64 const,$VAL,$IFILE $CFILE
+    $CDO $DEBUG_OUT -f srv -b 64 const,$VAL,$IFILE $CFILE
 
 # stat var const
 
     CDOTEST="$STAT"
-    CDOCOMMAND="$CDO $FORMAT ${STAT} $IFILE $CFILE $OFILE"
+    CDOCOMMAND="$CDO $DEBUG_OUT $FORMAT ${STAT} $IFILE $CFILE $OFILE"
 
     echo "Running test: $NTEST - $CDOTEST"
     echo "$CDOCOMMAND"
@@ -36,12 +39,12 @@ for STAT in $STATS; do
 # stat,const var
 
     OFILE2=stat${STAT}c_res
-    CDOCOMMAND="$CDO $FORMAT ${STAT}c,$VAL $IFILE $OFILE2"
+    CDOCOMMAND="$CDO $DEBUG_OUT $FORMAT ${STAT}c,$VAL $IFILE $OFILE2"
 
     $CDOCOMMAND
     test $? -eq 0 || let RSTAT+=1
 
-    $CDO diff $OFILE $OFILE2 > $CDOOUT 2> $CDOERR
+    $CDO $DEBUG_OUT diff $OFILE $OFILE2 > $CDOOUT 2> $CDOERR
     test $? -eq 0 || let RSTAT+=1
     test -s $CDOOUT && let RSTAT+=1
     cat $CDOOUT $CDOERR
@@ -56,12 +59,12 @@ for STAT in $STATS; do
     OFILE3=arithc_expr${STAT}_res
     INSTR="var130=var130${OP}${VAL};var152=var152${OP}${VAL};var129=var129${OP}${VAL};"
     echo $INSTR
-    CDOCOMMAND="$CDO $FORMAT expr,$INSTR $IFILE $OFILE3"
+    CDOCOMMAND="$CDO $DEBUG_OUT $FORMAT expr,$INSTR $IFILE $OFILE3"
 
     $CDOCOMMAND
     test $? -eq 0 || let RSTAT+=1
 
-    $CDO diff $OFILE $OFILE3 > $CDOOUT 2> $CDOERR
+    $CDO $DEBUG_OUT diff $OFILE $OFILE3 > $CDOOUT 2> $CDOERR
     test $? -eq 0 || let RSTAT+=1
     test -s $CDOOUT && let RSTAT+=1
     cat $CDOOUT $CDOERR
diff --git a/test/Expr.test.in b/test/Expr.test.in
index d03068a..b02d5d3 100644
--- a/test/Expr.test.in
+++ b/test/Expr.test.in
@@ -7,6 +7,7 @@ test -n "$DATAPATH" || DATAPATH=./data
 CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
+ABSLIMMAX=0.001
 #
 IFILE=$DATAPATH/pl_data
 NTEST=1
@@ -38,7 +39,7 @@ function testfunc()
       $CDOCOMMAND
       test $? -eq 0 || let RSTAT+=1
 
-      $CDO diff $RFILE $OFILE > $CDOOUT 2> $CDOERR
+      $CDO diff,$ABSLIMMAX $RFILE $OFILE > $CDOOUT 2> $CDOERR
       test $? -eq 0 || let RSTAT+=1
       test -s $CDOOUT && let RSTAT+=1
       cat $CDOOUT $CDOERR
diff --git a/test/Makefile.in b/test/Makefile.in
index dcfe021..da19ceb 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -79,31 +89,10 @@ build_triplet = @build@
 host_triplet = @host@
 XFAIL_TESTS =
 subdir = test
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs $(srcdir)/File.test.in \
-	$(srcdir)/Read_grib.test.in $(srcdir)/Read_netcdf.test.in \
-	$(srcdir)/Copy_netcdf.test.in $(srcdir)/Comp.test.in \
-	$(srcdir)/Compc.test.in $(srcdir)/Cat.test.in \
-	$(srcdir)/Gridarea.test.in $(srcdir)/Genweights.test.in \
-	$(srcdir)/Remap.test.in $(srcdir)/Remap2.test.in \
-	$(srcdir)/Remapeta.test.in $(srcdir)/EOF.test.in \
-	$(srcdir)/Select.test.in $(srcdir)/Spectral.test.in \
-	$(srcdir)/Vertint.test.in $(srcdir)/Timstat.test.in \
-	$(srcdir)/Timselstat.test.in $(srcdir)/Seasstat.test.in \
-	$(srcdir)/Runstat.test.in $(srcdir)/Multiyearstat.test.in \
-	$(srcdir)/Ydrunstat.test.in $(srcdir)/Gridboxstat.test.in \
-	$(srcdir)/Vertstat.test.in $(srcdir)/Fldstat.test.in \
-	$(srcdir)/Fldpctl.test.in $(srcdir)/Ensstat.test.in \
-	$(srcdir)/Enspctl.test.in $(srcdir)/Merstat.test.in \
-	$(srcdir)/Zonstat.test.in $(srcdir)/Mergetime.test.in \
-	$(srcdir)/Afterburner.test.in $(srcdir)/Detrend.test.in \
-	$(srcdir)/Arithc.test.in $(srcdir)/Arith.test.in \
-	$(srcdir)/Expr.test.in $(srcdir)/Gradsdes.test.in \
-	$(srcdir)/Collgrid.test.in $(srcdir)/threads.test.in \
-	$(srcdir)/tsformat.test.in $(srcdir)/wildcard.test.in \
-	$(srcdir)/MapReduce.test.in $(srcdir)/Ninfo.test.in README
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -112,6 +101,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = File.test Read_grib.test Read_netcdf.test \
@@ -347,6 +337,30 @@ am__set_b = \
     *) \
       b='$*';; \
   esac
+am__DIST_COMMON = $(srcdir)/Afterburner.test.in \
+	$(srcdir)/Arith.test.in $(srcdir)/Arithc.test.in \
+	$(srcdir)/Cat.test.in $(srcdir)/Collgrid.test.in \
+	$(srcdir)/Comp.test.in $(srcdir)/Compc.test.in \
+	$(srcdir)/Copy_netcdf.test.in $(srcdir)/Detrend.test.in \
+	$(srcdir)/EOF.test.in $(srcdir)/Enspctl.test.in \
+	$(srcdir)/Ensstat.test.in $(srcdir)/Expr.test.in \
+	$(srcdir)/File.test.in $(srcdir)/Fldpctl.test.in \
+	$(srcdir)/Fldstat.test.in $(srcdir)/Genweights.test.in \
+	$(srcdir)/Gradsdes.test.in $(srcdir)/Gridarea.test.in \
+	$(srcdir)/Gridboxstat.test.in $(srcdir)/Makefile.in \
+	$(srcdir)/MapReduce.test.in $(srcdir)/Mergetime.test.in \
+	$(srcdir)/Merstat.test.in $(srcdir)/Multiyearstat.test.in \
+	$(srcdir)/Ninfo.test.in $(srcdir)/Read_grib.test.in \
+	$(srcdir)/Read_netcdf.test.in $(srcdir)/Remap.test.in \
+	$(srcdir)/Remap2.test.in $(srcdir)/Remapeta.test.in \
+	$(srcdir)/Runstat.test.in $(srcdir)/Seasstat.test.in \
+	$(srcdir)/Select.test.in $(srcdir)/Spectral.test.in \
+	$(srcdir)/Timselstat.test.in $(srcdir)/Timstat.test.in \
+	$(srcdir)/Vertint.test.in $(srcdir)/Vertstat.test.in \
+	$(srcdir)/Ydrunstat.test.in $(srcdir)/Zonstat.test.in \
+	$(srcdir)/threads.test.in $(srcdir)/tsformat.test.in \
+	$(srcdir)/wildcard.test.in $(top_srcdir)/config/mkinstalldirs \
+	README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -389,18 +403,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -476,6 +494,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -576,7 +595,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign test/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -723,7 +741,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
 	if test -n "$$am__remaking_logs"; then \
 	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
 	       "recursion detected" >&2; \
-	else \
+	elif test -n "$$redo_logs"; then \
 	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
 	fi; \
 	if $(am__make_dryrun); then :; else \
@@ -999,6 +1017,8 @@ uninstall-am:
 	mostlyclean-libtool pdf pdf-am ps ps-am recheck tags-am \
 	uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 export
 
diff --git a/test/data/Makefile.in b/test/data/Makefile.in
index a08f930..1ff9b69 100644
--- a/test/data/Makefile.in
+++ b/test/data/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -14,7 +14,17 @@
 
 @SET_MAKE@
 VPATH = @srcdir@
-am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
 am__make_running_with_option = \
   case $${target_option-} in \
       ?) ;; \
@@ -78,10 +88,10 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = test/data
-DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
-	$(top_srcdir)/config/mkinstalldirs
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/acx_cfortran_flags.m4 \
+	$(top_srcdir)/m4/acx_check_cfortran.m4 \
+	$(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
 	$(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -90,6 +100,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_options.m4 \
 	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES =
@@ -114,6 +125,8 @@ am__can_run_installinfo = \
     *) (install-info --version) >/dev/null 2>&1;; \
   esac
 am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+	$(top_srcdir)/config/mkinstalldirs
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -156,18 +169,22 @@ ENABLE_CDI_LIB = @ENABLE_CDI_LIB@
 ENABLE_CGRIBEX = @ENABLE_CGRIBEX@
 ENABLE_DATA = @ENABLE_DATA@
 ENABLE_EXTRA = @ENABLE_EXTRA@
+ENABLE_FORTRAN = @ENABLE_FORTRAN@
 ENABLE_GRIB = @ENABLE_GRIB@
 ENABLE_GRIBAPI = @ENABLE_GRIBAPI@
 ENABLE_IEG = @ENABLE_IEG@
 ENABLE_NC2 = @ENABLE_NC2@
 ENABLE_NC4 = @ENABLE_NC4@
 ENABLE_NC4HDF5 = @ENABLE_NC4HDF5@
+ENABLE_NEARPT3 = @ENABLE_NEARPT3@
 ENABLE_NETCDF = @ENABLE_NETCDF@
 ENABLE_SERVICE = @ENABLE_SERVICE@
 ENABLE_THREADS = @ENABLE_THREADS@
 EXEEXT = @EXEEXT@
-FCFLAGS = @FCFLAGS@
+F77 = @F77@
+FFLAGS = @FFLAGS@
 FGREP = @FGREP@
+FORTRAN_WORKS = @FORTRAN_WORKS@
 GREP = @GREP@
 GRIB_API_INCLUDE = @GRIB_API_INCLUDE@
 GRIB_API_LIBS = @GRIB_API_LIBS@
@@ -243,6 +260,7 @@ ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_F77 = @ac_ct_F77@
 am__include = @am__include@
 am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
@@ -354,7 +372,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__confi
 	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/data/Makefile'; \
 	$(am__cd) $(top_srcdir) && \
 	  $(AUTOMAKE) --foreign test/data/Makefile
-.PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
 	@case '$?' in \
 	  *config.status*) \
@@ -529,6 +546,8 @@ uninstall-am:
 	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
 	tags-am uninstall uninstall-am
 
+.PRECIOUS: Makefile
+
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/test/data/expr2_ref b/test/data/expr2_ref
index cf28d14..5fa8ee3 100644
Binary files a/test/data/expr2_ref and b/test/data/expr2_ref differ

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



More information about the debian-science-commits mailing list